diff --git a/tests/uitests/Android.mk b/tests/uitests/Android.mk new file mode 100644 index 00000000000..23357e8c4c6 --- /dev/null +++ b/tests/uitests/Android.mk @@ -0,0 +1,35 @@ +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := SettingsUITests +LOCAL_COMPATIBILITY_SUITE := device-tests +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_MODULE_TAGS := tests +LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base +LOCAL_STATIC_JAVA_LIBRARIES := \ + app-helpers-base \ + launcher-helper-lib \ + settings-helper \ + timeresult-helper-lib \ + ub-uiautomator \ + sysui-helper \ + metrics-helper-lib \ + platform-test-annotations \ + +#LOCAL_SDK_VERSION := current + +include $(BUILD_PACKAGE) diff --git a/tests/uitests/AndroidManifest.xml b/tests/uitests/AndroidManifest.xml new file mode 100644 index 00000000000..06d74c681e7 --- /dev/null +++ b/tests/uitests/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/uitests/AndroidTest.xml b/tests/uitests/AndroidTest.xml new file mode 100644 index 00000000000..fbeea2db60c --- /dev/null +++ b/tests/uitests/AndroidTest.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/tests/uitests/src/com/android/settings/ui/AboutPhoneSettingsTests.java b/tests/uitests/src/com/android/settings/ui/AboutPhoneSettingsTests.java new file mode 100644 index 00000000000..57f9bc2aedd --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/AboutPhoneSettingsTests.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.content.Intent; +import android.os.RemoteException; +import android.provider.Settings; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +/** Verifies basic functionality of the About Phone screen */ +public class AboutPhoneSettingsTests extends InstrumentationTestCase { + private static final boolean LOCAL_LOGV = false; + private static final String TAG = "AboutPhoneSettingsTest"; + private static final int TIMEOUT = 2000; + private static final String SETTINGS_PACKAGE = "com.android.settings"; + + private UiDevice mDevice; + + // TODO: retrieve using name/ids from com.android.settings package + private static final String[] sResourceTexts = { + "Status", + "Legal information", + "Regulatory labels", + "Model", + "Android version", + "Android security patch level", + "Baseband version", + "Kernel version", + "Build number" + }; + + private static final String[] sClickableResourceTexts = { + "Status", "Legal information", "Regulatory labels", + }; + + @Override + public void setUp() throws Exception { + if (LOCAL_LOGV) { + Log.d(TAG, "-------"); + } + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("Failed to freeze device orientaion", e); + } + + // make sure we are in a clean state before starting the test + mDevice.pressHome(); + Thread.sleep(TIMEOUT * 2); + launchAboutPhoneSettings(Settings.ACTION_DEVICE_INFO_SETTINGS); + // TODO: make sure we are always at the top of the app + // currently this will fail if the user has navigated into submenus + UiObject2 view = + mDevice.wait( + Until.findObject(By.res(SETTINGS_PACKAGE + ":id/main_content")), TIMEOUT); + assertNotNull("Could not find main About Phone screen", view); + view.scroll(Direction.UP, 1.0f); + } + + @Override + protected void tearDown() throws Exception { + // Adding an extra pressBack so we exit About Phone Settings + // and finish the test cleanly + mDevice.pressBack(); + mDevice.pressHome(); // finish settings activity + mDevice.waitForIdle(TIMEOUT * 2); // give UI time to finish animating + super.tearDown(); + } + + private void launchAboutPhoneSettings(String aboutSetting) throws Exception { + Intent aboutIntent = new Intent(aboutSetting); + aboutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getInstrumentation().getContext().startActivity(aboutIntent); + } + + /** + * Callable actions that can be taken when a UIObject2 is found + * + * @param device The current UiDevice + * @param item The UiObject2 that was found and can be acted on + * + * @return {@code true} if the call was successful, and {@code false} otherwise + */ + public interface UIObject2Callback { + boolean call(UiDevice device, UiObject2 item) throws Exception; + } + + /** + * Clicks the given item and then presses the Back button + * + *

Used to test whether a given UiObject2 can be successfully clicked. + * Presses Back to restore state to the previous screen. + * + * @param device The device that can be used to press Back + * @param item The item to click + * + * @return {@code true} if clicking the item succeeded, and {@code false} otherwise + */ + public class UiObject2Clicker implements UIObject2Callback { + public boolean call(UiDevice device, UiObject2 item) throws Exception { + item.click(); + Thread.sleep(TIMEOUT * 2); // give UI time to finish animating + boolean pressWorked = device.pressBack(); + Thread.sleep(TIMEOUT * 2); + return pressWorked; + } + } + + /** + * Removes items found in the view and optionally takes some action. + * + * @param device The current UiDevice + * @param itemsLeftToFind The items to search for in the current view + * @param action Action to call on each item that is found; pass {@code null} to take no action + */ + private void removeItemsAndTakeAction( + UiDevice device, ArrayList itemsLeftToFind, UIObject2Callback action) throws Exception { + for (Iterator iterator = itemsLeftToFind.iterator(); iterator.hasNext(); ) { + String itemText = iterator.next(); + UiObject2 item = device.wait(Until.findObject(By.text(itemText)), TIMEOUT); + if (item != null) { + if (LOCAL_LOGV) { + Log.d(TAG, itemText + " is present"); + } + iterator.remove(); + if (action != null) { + boolean success = action.call(device, item); + assertTrue("Calling action after " + itemText + " did not work", success); + } + } else { + if (LOCAL_LOGV) { + Log.d(TAG, "Could not find " + itemText); + } + } + } + } + + /** + * Searches for UI elements in the current view and optionally takes some action. + * + *

Will scroll down the screen until it has found all elements or reached the bottom. + * This allows elements to be found and acted on even if they change order. + * + * @param device The current UiDevice + * @param itemsToFind The items to search for in the current view + * @param action Action to call on each item that is found; pass {@code null} to take no action + */ + public void searchForItemsAndTakeAction(UiDevice device, String[] itemsToFind, UIObject2Callback action) + throws Exception { + + ArrayList itemsLeftToFind = new ArrayList(Arrays.asList(itemsToFind)); + assertFalse( + "There must be at least one item to search for on the screen!", + itemsLeftToFind.isEmpty()); + + if (LOCAL_LOGV) { + Log.d(TAG, "items: " + TextUtils.join(", ", itemsLeftToFind)); + } + boolean canScrollDown = true; + while (canScrollDown && !itemsLeftToFind.isEmpty()) { + removeItemsAndTakeAction(device, itemsLeftToFind, action); + + // when we've finished searching the current view, scroll down + UiObject2 view = + device.wait( + Until.findObject(By.res(SETTINGS_PACKAGE + ":id/main_content")), + TIMEOUT * 2); + if (view != null) { + canScrollDown = view.scroll(Direction.DOWN, 1.0f); + } else { + canScrollDown = false; + } + } + // check the last items once we have reached the bottom of the view + removeItemsAndTakeAction(device, itemsLeftToFind, action); + + assertTrue( + "The following items were not found on the screen: " + + TextUtils.join(", ", itemsLeftToFind), + itemsLeftToFind.isEmpty()); + } + + @MediumTest // UI interaction + public void testAllMenuEntriesExist() throws Exception { + searchForItemsAndTakeAction(mDevice, sResourceTexts, null); + } + + // Suppressing this test as it might be causing other test failures + // Will verify that this test is the cause before proceeding with solution + @Suppress + @MediumTest // UI interaction + public void testClickableEntriesCanBeClicked() throws Exception { + searchForItemsAndTakeAction(mDevice, sClickableResourceTexts, new UiObject2Clicker()); + } +} diff --git a/tests/uitests/src/com/android/settings/ui/AccessibilitySettingsTests.java b/tests/uitests/src/com/android/settings/ui/AccessibilitySettingsTests.java new file mode 100644 index 00000000000..83afa6583f8 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/AccessibilitySettingsTests.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.support.test.metricshelper.MetricsAsserts; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.SettingsHelper; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; + +import android.metrics.MetricsReader; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + +public class AccessibilitySettingsTests extends InstrumentationTestCase { + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + private static final int TIMEOUT = 2000; + private UiDevice mDevice; + private MetricsReader mMetricsReader; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientaion", e); + } + mMetricsReader = new MetricsReader(); + // Clear out old logs + mMetricsReader.checkpoint(); + } + + @Override + protected void tearDown() throws Exception { + // Need to finish settings activity + mDevice.pressBack(); + mDevice.pressHome(); + mDevice.waitForIdle(); + super.tearDown(); + } + + @Presubmit + @MediumTest + public void testHighContrastTextOn() throws Exception { + verifyAccessibilitySettingOnOrOff("High contrast text", + Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0, 1); + } + + @Presubmit + @MediumTest + public void testHighContrastTextOff() throws Exception { + verifyAccessibilitySettingOnOrOff("High contrast text", + Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 1, 0); + } + + @Presubmit + @MediumTest + public void testPowerButtonEndsCallOn() throws Exception { + verifyAccessibilitySettingOnOrOff("Power button ends call", + Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, 1, 2); + } + + @Presubmit + @MediumTest + public void testPowerButtonEndsCallOff() throws Exception { + verifyAccessibilitySettingOnOrOff("Power button ends call", + Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, 2, 1); + } + + /* Suppressing these four tests. The settings don't play + * nice with Settings.System.putInt or Settings.Secure.putInt. + * Need further clarification. Filed bug b/27792029 + */ + @Suppress + @MediumTest + public void testAutoRotateScreenOn() throws Exception { + verifyAccessibilitySettingOnOrOff("Auto-rotate screen", + Settings.System.ACCELEROMETER_ROTATION, 0, 1); + } + + @Suppress + @MediumTest + public void testAutoRotateScreenOff() throws Exception { + verifyAccessibilitySettingOnOrOff("Auto-rotate screen", + Settings.System.ACCELEROMETER_ROTATION, 1, 0); + } + + @Suppress + @MediumTest + public void testMonoAudioOn() throws Exception { + verifyAccessibilitySettingOnOrOff("Mono audio", + Settings.System.MASTER_MONO, 0, 1); + } + + @Suppress + @MediumTest + public void testMonoAudioOff() throws Exception { + verifyAccessibilitySettingOnOrOff("Mono audio", + Settings.System.MASTER_MONO, 1, 0); + } + + @Presubmit + @MediumTest + public void testLargeMousePointerOn() throws Exception { + verifyAccessibilitySettingOnOrOff("Large mouse pointer", + Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 0, 1); + } + + @Presubmit + @MediumTest + public void testLargeMousePointerOff() throws Exception { + verifyAccessibilitySettingOnOrOff("Large mouse pointer", + Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 1, 0); + } + + @Presubmit + @MediumTest + public void testColorCorrection() throws Exception { + verifySettingToggleAfterScreenLoad("Color correction", + Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED); + MetricsAsserts.assertHasVisibilityLog("Missing color correction log", + mMetricsReader, MetricsEvent.ACCESSIBILITY_TOGGLE_DALTONIZER, true); + } + + // Suppressing this test, since UiAutomator + talkback don't play nice + @Suppress + @MediumTest + public void testTalkback() throws Exception { + verifySettingToggleAfterScreenLoad("TalkBack", + Settings.Secure.ACCESSIBILITY_ENABLED); + } + + @Presubmit + @MediumTest + public void testCaptions() throws Exception { + verifySettingToggleAfterScreenLoad("Captions", + Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED); + MetricsAsserts.assertHasVisibilityLog("Missing captions log", + mMetricsReader, MetricsEvent.ACCESSIBILITY_CAPTION_PROPERTIES, true); + } + + @Presubmit + @MediumTest + public void testMagnificationGesture() throws Exception { + verifySettingToggleAfterScreenLoad("Magnification", "Magnify with triple-tap", + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); + MetricsAsserts.assertHasVisibilityLog("Missing magnification log", + mMetricsReader, MetricsEvent.ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION, true); + } + + @MediumTest + public void testClickAfterPointerStopsMoving() throws Exception { + verifySettingToggleAfterScreenLoad("Click after pointer stops moving", + Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED); + } + + @MediumTest + public void testAccessibilitySettingsLoadLog() throws Exception { + launchAccessibilitySettings(); + MetricsAsserts.assertHasVisibilityLog("Missing accessibility settings load log", + mMetricsReader, MetricsEvent.ACCESSIBILITY, true); + } + + public void launchAccessibilitySettings() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_ACCESSIBILITY_SETTINGS); + } + + private void verifyAccessibilitySettingOnOrOff(String settingText, + String settingFlag, int initialFlagValue, int expectedFlagValue) + throws Exception { + Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(), + settingFlag, initialFlagValue); + launchAccessibilitySettings(); + UiObject2 settingsTitle = findItemOnScreen(settingText); + settingsTitle.click(); + Thread.sleep(TIMEOUT); + int settingValue = Settings.Secure + .getInt(getInstrumentation().getContext().getContentResolver(), settingFlag); + assertEquals(settingText + " not correctly set after toggle", + expectedFlagValue, settingValue); + } + + private void verifySettingToggleAfterScreenLoad(String settingText, String settingFlag) + throws Exception { + verifySettingToggleAfterScreenLoad(settingText, null, settingFlag); + } + + private void verifySettingToggleAfterScreenLoad + (String settingText, String subSetting, String settingFlag) throws Exception { + // Load accessibility settings + launchAccessibilitySettings(); + Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(), + settingFlag, 0); + Thread.sleep(TIMEOUT); + // Tap on setting required + UiObject2 settingTitle = findItemOnScreen(settingText); + // Load screen + settingTitle.click(); + Thread.sleep(TIMEOUT); + if (subSetting != null) { + UiObject2 subSettingObject = findItemOnScreen(subSetting); + subSettingObject.click(); + Thread.sleep(TIMEOUT); + } + // Toggle value + UiObject2 settingToggle = mDevice.wait(Until.findObject(By.text("Off")), + TIMEOUT); + settingToggle.click(); + dismissOpenDialog(); + Thread.sleep(TIMEOUT); + // Assert new value + int settingValue = Settings.Secure. + getInt(getInstrumentation().getContext().getContentResolver(), settingFlag); + assertEquals(settingText + " value not set correctly", 1, settingValue); + // Toogle value + settingToggle.click(); + dismissOpenDialog(); + mDevice.pressBack(); + Thread.sleep(TIMEOUT); + // Assert reset to old value + settingValue = Settings.Secure. + getInt(getInstrumentation().getContext().getContentResolver(), settingFlag); + assertEquals(settingText + " value not set correctly", 0, settingValue); + } + + private UiObject2 findItemOnScreen(String item) throws Exception { + int count = 0; + UiObject2 settingsPanel = mDevice.wait(Until.findObject + (By.res(SETTINGS_PACKAGE, "list")), TIMEOUT); + while (settingsPanel.fling(Direction.UP) && count < 3) { + count++; + } + count = 0; + UiObject2 setting = null; + while(count < 3 && setting == null) { + setting = mDevice.wait(Until.findObject(By.text(item)), TIMEOUT); + if (setting == null) { + settingsPanel.scroll(Direction.DOWN, 1.0f); + } + count++; + } + return setting; + } + + private void dismissOpenDialog() throws Exception { + UiObject2 okButton = mDevice.wait(Until.findObject + (By.res("android:id/button1")), TIMEOUT*2); + if (okButton != null) { + okButton.click(); + } + } +} diff --git a/tests/uitests/src/com/android/settings/ui/AppsSettingsTests.java b/tests/uitests/src/com/android/settings/ui/AppsSettingsTests.java new file mode 100644 index 00000000000..6be49d6d1ca --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/AppsSettingsTests.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.content.Intent; +import android.os.RemoteException; +import android.provider.Settings; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.ActivityHelper; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +/** Verifies basic functionality of the About Phone screen */ +public class AppsSettingsTests extends InstrumentationTestCase { + private static final boolean LOCAL_LOGV = false; + private static final String SETTINGS_PACKAGE = "com.android.settings"; + private static final String TAG = "AboutPhoneSettingsTest"; + private static final int TIMEOUT = 2000; + private ActivityHelper mActivityHelper = null; + + private UiDevice mDevice; + + private static final String[] sResourceTexts = { + "Storage", + "Data usage", + "Permissions", + "App notifications", + "Open by default", + "Battery", + "Memory" + }; + + @Override + public void setUp() throws Exception { + if (LOCAL_LOGV) { + Log.d(TAG, "-------"); + } + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + mActivityHelper = ActivityHelper.getInstance(); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("Failed to freeze device orientaion", e); + } + + // make sure we are in a clean state before starting the test + mDevice.pressHome(); + Thread.sleep(TIMEOUT * 2); + launchAppsSettings(); + UiObject2 view = + mDevice.wait( + Until.findObject(By.text("All apps")), TIMEOUT); + assertNotNull("Could not find Settings > Apps screen", view); + } + + @Override + protected void tearDown() throws Exception { + mDevice.pressBack(); + mDevice.pressHome(); // finish settings activity + mDevice.waitForIdle(TIMEOUT * 2); // give UI time to finish animating + super.tearDown(); + } + + @MediumTest + public void testAppSettingsListForCalculator() { + UiObject2 calculator = mDevice.wait( + Until.findObject(By.text("Calculator")), TIMEOUT); + calculator.click(); + for (String setting : sResourceTexts) { + UiObject2 appSetting = + mDevice.wait( + Until.findObject(By.text(setting)), TIMEOUT); + assertNotNull("Missing setting for Calculator: " + setting, appSetting); + appSetting.scroll(Direction.DOWN, 10.0f); + } + } + + @MediumTest + public void testDisablingAndEnablingSystemApp() throws Exception { + launchAppsSettings(); + UiObject2 calculator = mDevice.wait( + Until.findObject(By.text("Calculator")), TIMEOUT); + calculator.click(); + mDevice.waitForIdle(TIMEOUT); + UiObject2 appInfoList = mDevice.wait( + Until.findObject(By.res(SETTINGS_PACKAGE, "list")), TIMEOUT); + appInfoList.scroll(Direction.DOWN, 100.0f); + UiObject2 disableButton = mDevice.wait( + Until.findObject(By.text("DISABLE")), TIMEOUT); + disableButton.click(); + mDevice.waitForIdle(TIMEOUT); + // Click on "Disable App" on dialog. + mDevice.wait( + Until.findObject(By.text("DISABLE APP")), TIMEOUT).click(); + mDevice.waitForIdle(TIMEOUT); + UiObject2 enableButton = mDevice.wait( + Until.findObject(By.text("ENABLE")), TIMEOUT); + assertNotNull("App not disabled successfully", enableButton); + enableButton.click(); + mDevice.waitForIdle(TIMEOUT); + disableButton = mDevice.wait( + Until.findObject(By.text("DISABLE")), TIMEOUT); + assertNotNull("App not enabled successfully", disableButton); + } + + private void launchAppsSettings() throws Exception { + Intent appsSettingsIntent = new + Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS); + mActivityHelper.launchIntent(appsSettingsIntent); + } +} diff --git a/tests/uitests/src/com/android/settings/ui/BluetoothNetworkSettingsTests.java b/tests/uitests/src/com/android/settings/ui/BluetoothNetworkSettingsTests.java new file mode 100644 index 00000000000..d41be9cd352 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/BluetoothNetworkSettingsTests.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.Intent; +import android.metrics.MetricsReader; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.support.test.metricshelper.MetricsAsserts; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.BySelector; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + +public class BluetoothNetworkSettingsTests extends InstrumentationTestCase { + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + private static final int TIMEOUT = 2000; + private static final int LONG_TIMEOUT = 40000; + private UiDevice mDevice; + private MetricsReader mMetricsReader; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientaion", e); + } + mMetricsReader = new MetricsReader(); + // Clear out old logs + mMetricsReader.checkpoint(); + } + + @Override + protected void tearDown() throws Exception { + mDevice.pressBack(); + mDevice.pressHome(); + mDevice.waitForIdle(); + super.tearDown(); + } + + @Presubmit + @MediumTest + public void testBluetoothEnabled() throws Exception { + verifyBluetoothOnOrOff(true); + MetricsAsserts.assertHasActionLog("missing bluetooth toggle log", + mMetricsReader, MetricsEvent.ACTION_BLUETOOTH_TOGGLE); + } + + @Presubmit + @MediumTest + public void testBluetoothDisabled() throws Exception { + verifyBluetoothOnOrOff(false); + MetricsAsserts.assertHasActionLog("missing bluetooth toggle log", + mMetricsReader, MetricsEvent.ACTION_BLUETOOTH_TOGGLE); + } + + @MediumTest + public void testRenameOption() throws Exception { + launchBluetoothSettings(); + verifyUiObjectClicked(By.text("Device name"), "Rename preference"); + verifyUiObjectClicked(By.text("CANCEL"), "CANCEL button"); + + MetricsAsserts.assertHasActionLog("missing bluetooth rename device log", + mMetricsReader, MetricsEvent.ACTION_BLUETOOTH_RENAME); + MetricsAsserts.assertHasVisibilityLog("missing bluetooth rename dialog log", + mMetricsReader, MetricsEvent.DIALOG_BLUETOOTH_RENAME, true); + } + + @MediumTest + public void testReceivedFilesOption() throws Exception { + launchBluetoothSettings(); + verifyUiObjectClicked(By.text("Received files"), "Received files preference"); + + MetricsAsserts.assertHasActionLog("missing bluetooth received files log", + mMetricsReader, MetricsEvent.ACTION_BLUETOOTH_FILES); + } + + @MediumTest + public void testHelpFeedbackOverflowOption() throws Exception { + launchBluetoothSettings(); + + // Verify help & feedback + assertNotNull("Help & feedback item not found under Bluetooth Settings", + mDevice.wait(Until.findObject(By.desc("Help & feedback")), TIMEOUT)); + } + + public void launchBluetoothSettings() throws Exception { + Intent btIntent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS); + btIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getInstrumentation().getContext().startActivity(btIntent); + Thread.sleep(TIMEOUT * 2); + } + + /** + * Find the {@link UiObject2} by {@code itemSelector} and try to click it if possible. + * + * If not find, throw assertion error + * @param itemSelector used to find the {@link UiObject2} + * @param text the description of the {@link UiObject2} + */ + private void verifyUiObjectClicked(BySelector itemSelector, String text) throws Exception { + UiObject2 uiObject2 = mDevice.wait(Until.findObject(itemSelector), TIMEOUT); + assertNotNull(text + "is not present in bluetooth settings page", uiObject2); + uiObject2.click(); + } + + /** + * Toggles the Bluetooth switch and verifies that the change is reflected in Settings + * + * @param verifyOn set to whether you want the setting turned On or Off + */ + private void verifyBluetoothOnOrOff(boolean verifyOn) throws Exception { + String switchText = "ON"; + BluetoothAdapter bluetoothAdapter = ((BluetoothManager) getInstrumentation().getContext() + .getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter(); + if (verifyOn) { + switchText = "OFF"; + bluetoothAdapter.disable(); + } else { + bluetoothAdapter.enable(); + } + launchBluetoothSettings(); + mDevice.wait(Until + .findObject(By.res(SETTINGS_PACKAGE, "switch_widget").text(switchText)), TIMEOUT) + .click(); + Thread.sleep(TIMEOUT); + String bluetoothValue = + Settings.Global.getString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.BLUETOOTH_ON); + if (verifyOn) { + assertEquals("1", bluetoothValue); + } else { + assertEquals("0", bluetoothValue); + } + } +} diff --git a/tests/uitests/src/com/android/settings/ui/ConnectedDeviceTests.java b/tests/uitests/src/com/android/settings/ui/ConnectedDeviceTests.java new file mode 100644 index 00000000000..971d724d040 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/ConnectedDeviceTests.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.content.Context; +import android.content.Intent; +import android.nfc.NfcAdapter; +import android.nfc.NfcManager; +import android.os.RemoteException; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class ConnectedDeviceTests { + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + private static final int TIMEOUT = 2000; + private UiDevice mDevice; + + @Before + public void setUp() throws Exception { + mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientation", e); + } + } + + @After + public void tearDown() throws Exception { + mDevice.pressBack(); + mDevice.pressHome(); + } + + // This NFC toggle test is set up this way since there's no way to set + // the NFC flag to enabled or disabled without touching UI. + // This way, we get coverage for whether or not the toggle button works. + @Test + public void testNFCToggle() throws Exception { + NfcManager manager = (NfcManager) InstrumentationRegistry.getTargetContext() + .getSystemService(Context.NFC_SERVICE); + NfcAdapter nfcAdapter = manager.getDefaultAdapter(); + boolean nfcInitiallyEnabled = nfcAdapter.isEnabled(); + InstrumentationRegistry.getContext().startActivity(new Intent() + .setClassName( + SETTINGS_PACKAGE, + "com.android.settings.Settings$ConnectedDeviceDashboardActivity")); + UiObject2 nfcSetting = mDevice.wait(Until.findObject(By.text("NFC")), TIMEOUT); + nfcSetting.click(); + Thread.sleep(TIMEOUT * 2); + if (nfcInitiallyEnabled) { + assertFalse("NFC wasn't disabled on toggle", nfcAdapter.isEnabled()); + nfcSetting.click(); + Thread.sleep(TIMEOUT * 2); + assertTrue("NFC wasn't enabled on toggle", nfcAdapter.isEnabled()); + } else { + assertTrue("NFC wasn't enabled on toggle", nfcAdapter.isEnabled()); + nfcSetting.click(); + Thread.sleep(TIMEOUT * 2); + assertFalse("NFC wasn't disabled on toggle", nfcAdapter.isEnabled()); + } + } +} diff --git a/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTests.java b/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTests.java new file mode 100644 index 00000000000..725ba5cf635 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/DataUsageSettingsTests.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.os.RemoteException; +import android.provider.Settings; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.Until; +import android.system.helpers.SettingsHelper; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; + +public class DataUsageSettingsTests extends InstrumentationTestCase { + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + private static final int TIMEOUT = 2000; + private UiDevice mDevice; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientaion", e); + } + } + + @Override + protected void tearDown() throws Exception { + // Need to finish settings activity + mDevice.pressBack(); + mDevice.pressHome(); + super.tearDown(); + } + + @MediumTest + public void testElementsOnDataUsageScreen() throws Exception { + launchDataUsageSettings(); + assertNotNull("Data usage element not found", + mDevice.wait(Until.findObject(By.text("Usage")), + TIMEOUT)); + assertNotNull("Data usage bar not found", + mDevice.wait(Until.findObject(By.res(SETTINGS_PACKAGE, + "color_bar")), TIMEOUT)); + assertNotNull("WiFi Data usage element not found", + mDevice.wait(Until.findObject(By.text("Wi-Fi data usage")), + TIMEOUT)); + assertNotNull("Network restrictions element not found", + mDevice.wait(Until.findObject(By.text("Network restrictions")), + TIMEOUT)); + } + + public void launchDataUsageSettings() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_SETTINGS); + mDevice.wait(Until + .findObject(By.text("Network & Internet")), TIMEOUT) + .click(); + Thread.sleep(TIMEOUT * 2); + assertNotNull("Network & internet screen not loaded", mDevice.wait( + Until.findObject(By.text("Data usage")), TIMEOUT)); + mDevice.wait(Until + .findObject(By.text("Data usage")), TIMEOUT) + .click(); + } +} diff --git a/tests/uitests/src/com/android/settings/ui/DisplaySettingsTest.java b/tests/uitests/src/com/android/settings/ui/DisplaySettingsTest.java new file mode 100644 index 00000000000..0b7402d76f2 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/DisplaySettingsTest.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.content.ContentResolver; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.SettingsHelper; +import android.system.helpers.SettingsHelper.SettingsType; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.regex.Pattern; + +public class DisplaySettingsTest extends InstrumentationTestCase { + + private static final String PAGE = Settings.ACTION_DISPLAY_SETTINGS; + private static final int TIMEOUT = 2000; + private static final FontSetting FONT_SMALL = new FontSetting("Small", 0.85f); + private static final FontSetting FONT_NORMAL = new FontSetting("Default", 1.00f); + private static final FontSetting FONT_LARGE = new FontSetting("Large", 1.15f); + private static final FontSetting FONT_HUGE = new FontSetting("Largest", 1.30f); + + private UiDevice mDevice; + private ContentResolver mResolver; + private SettingsHelper mHelper; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + mDevice.setOrientationNatural(); + mResolver = getInstrumentation().getContext().getContentResolver(); + mHelper = new SettingsHelper(); + } + + @Override + public void tearDown() throws Exception { + // reset settings we touched that may impact others + Settings.System.putFloat(mResolver, Settings.System.FONT_SCALE, 1.00f); + mDevice.waitForIdle(); + super.tearDown(); + } + + @Presubmit + @MediumTest + public void testAdaptiveBrightness() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + Thread.sleep(1000); + + assertTrue(mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, "Adaptive brightness", + Settings.System.SCREEN_BRIGHTNESS_MODE)); + assertTrue(mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, "Adaptive brightness", + Settings.System.SCREEN_BRIGHTNESS_MODE)); + } + + + // blocked on b/27487224 + @MediumTest + @Suppress + public void testDaydreamToggle() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + clickMore(); + Pattern p = Pattern.compile("On|Off"); + mHelper.clickSetting("Screen saver"); + Thread.sleep(1000); + try { + assertTrue(mHelper.verifyToggleSetting(SettingsType.SECURE, PAGE, p, + Settings.Secure.SCREENSAVER_ENABLED, false)); + assertTrue(mHelper.verifyToggleSetting(SettingsType.SECURE, PAGE, p, + Settings.Secure.SCREENSAVER_ENABLED, false)); + } finally { + mDevice.pressBack(); + } + } + + @MediumTest + public void testAccelRotation() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + clickMore(); + Thread.sleep(4000); + int currentAccelSetting = Settings.System.getInt( + mResolver, Settings.System.ACCELEROMETER_ROTATION); + mHelper.clickSetting("Auto-rotate screen"); + int newAccelSetting = Settings.System.getInt( + mResolver, Settings.System.ACCELEROMETER_ROTATION); + assertTrue("Accelorometer setting unchanged after toggle", currentAccelSetting != newAccelSetting); + mHelper.clickSetting("Auto-rotate screen"); + int revertedAccelSetting = Settings.System.getInt( + mResolver, Settings.System.ACCELEROMETER_ROTATION); + assertTrue("Accelorometer setting unchanged after toggle", revertedAccelSetting != newAccelSetting); + } + + @MediumTest + public void testDaydream() throws Exception { + Settings.Secure.putInt(mResolver, Settings.Secure.SCREENSAVER_ENABLED, 1); + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + clickMore(); + mHelper.scrollVert(false); + mDevice.wait(Until.findObject(By.text("Screen saver")), TIMEOUT).click(); + try { + assertTrue(mHelper.verifyRadioSetting(SettingsType.SECURE, PAGE, + "Current screen saver", "Clock", Settings.Secure.SCREENSAVER_COMPONENTS, + "com.google.android.deskclock/com.android.deskclock.Screensaver")); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SECURE, PAGE, + "Current screen saver", "Colors", Settings.Secure.SCREENSAVER_COMPONENTS, + "com.android.dreams.basic/com.android.dreams.basic.Colors")); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SECURE, PAGE, + "Current screen saver", "Photos", Settings.Secure.SCREENSAVER_COMPONENTS, + "com.google.android.apps.photos/com.google.android.apps.photos.daydream" + + ".PhotosDreamService")); + } finally { + mDevice.pressBack(); + Thread.sleep(2000); + } + } + + @Presubmit + @MediumTest + public void testSleep15Seconds() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SYSTEM, PAGE, + "Sleep", "15 seconds", Settings.System.SCREEN_OFF_TIMEOUT, "15000")); + } + + @MediumTest + public void testSleep30Seconds() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SYSTEM, PAGE, + "Sleep", "30 seconds", Settings.System.SCREEN_OFF_TIMEOUT, "30000")); + } + + @MediumTest + public void testSleep1Minute() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SYSTEM, PAGE, + "Sleep", "1 minute", Settings.System.SCREEN_OFF_TIMEOUT, "60000")); + } + + @MediumTest + public void testSleep2Minutes() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SYSTEM, PAGE, + "Sleep", "2 minutes", Settings.System.SCREEN_OFF_TIMEOUT, "120000")); + } + + @MediumTest + public void testSleep5Minutes() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SYSTEM, PAGE, + "Sleep", "5 minutes", Settings.System.SCREEN_OFF_TIMEOUT, "300000")); + } + + @MediumTest + public void testSleep10Minutes() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SYSTEM, PAGE, + "Sleep", "10 minutes", Settings.System.SCREEN_OFF_TIMEOUT, "600000")); + } + + @MediumTest + public void testSleep30Minutes() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(true); + assertTrue(mHelper.verifyRadioSetting(SettingsType.SYSTEM, PAGE, + "Sleep", "30 minutes", Settings.System.SCREEN_OFF_TIMEOUT, "1800000")); + } + + @Presubmit + @MediumTest + public void testFontSizeLarge() throws Exception { + verifyFontSizeSetting(1.00f, FONT_LARGE); + // Leaving the font size at large can make later tests fail, so reset it + Settings.System.putFloat(mResolver, Settings.System.FONT_SCALE, 1.00f); + // It takes a second for the new font size to be picked up + Thread.sleep(2000); + } + + @MediumTest + public void testFontSizeDefault() throws Exception { + verifyFontSizeSetting(1.15f, FONT_NORMAL); + } + + @MediumTest + public void testFontSizeLargest() throws Exception { + verifyFontSizeSetting(1.00f, FONT_HUGE); + // Leaving the font size at huge can make later tests fail, so reset it + Settings.System.putFloat(mResolver, Settings.System.FONT_SCALE, 1.00f); + // It takes a second for the new font size to be picked up + Thread.sleep(2000); + } + + @MediumTest + public void testFontSizeSmall() throws Exception { + verifyFontSizeSetting(1.00f, FONT_SMALL); + } + + private void verifyFontSizeSetting(float resetValue, FontSetting setting) + throws Exception { + Settings.System.putFloat(mResolver, Settings.System.FONT_SCALE, resetValue); + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + clickMore(); + mHelper.clickSetting("Font size"); + try { + mDevice.wait(Until.findObject(By.desc(setting.getName())), TIMEOUT).click(); + Thread.sleep(1000); + float changedValue = Settings.System.getFloat( + mResolver, Settings.System.FONT_SCALE); + assertEquals(setting.getSize(), changedValue, 0.0001); + } finally { + // Make sure to back out of the font menu + mDevice.pressBack(); + } + } + + private void clickMore() throws InterruptedException { + UiObject2 more = mDevice.wait(Until.findObject(By.text("Advanced")), TIMEOUT); + if (more != null) { + more.click(); + Thread.sleep(TIMEOUT); + } + } + + private static class FontSetting { + private final String mSizeName; + private final float mSizeVal; + + public FontSetting(String sizeName, float sizeVal) { + mSizeName = sizeName; + mSizeVal = sizeVal; + } + + public String getName() { + return mSizeName; + } + + public float getSize() { + return mSizeVal; + } + } +} diff --git a/tests/uitests/src/com/android/settings/ui/HomepageDisplayTests.java b/tests/uitests/src/com/android/settings/ui/HomepageDisplayTests.java new file mode 100644 index 00000000000..7931d30edd2 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/HomepageDisplayTests.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.SettingsHelper; + +import com.android.settings.ui.testutils.SettingsTestUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.android.settings.ui.testutils.SettingsTestUtils.SETTINGS_PACKAGE; +import static com.android.settings.ui.testutils.SettingsTestUtils.TIMEOUT; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class HomepageDisplayTests { + + private static final String[] HOMEPAGE_ITEMS = { + "Network & internet", + "Connected devices", + "Apps & notifications", + "Battery", + "Display", + "Sound", + "Storage", + "Security & location", + "Users & accounts", + "Accessibility", + "System", + "Support & tips" + }; + + private UiDevice mDevice; + private SettingsHelper mSettingsHelper; + + @Before + public void setUp() throws Exception { + mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + mSettingsHelper = new SettingsHelper(); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientaion", e); + } + } + + @After + public void tearDown() throws Exception { + // Need to finish settings activity + mDevice.pressHome(); + } + + @Presubmit + @Test + public void testHomepageCategory() throws Exception { + // Launch Settings + SettingsHelper.launchSettingsPage( + InstrumentationRegistry.getContext(), Settings.ACTION_SETTINGS); + + // Scroll to top + final UiObject2 view = mDevice.wait( + Until.findObject(By.res(SETTINGS_PACKAGE, "main_content")), + TIMEOUT); + view.scroll(Direction.UP, 100f); + + // Inspect each item + for (String item : HOMEPAGE_ITEMS) { + SettingsTestUtils.assertTitleMatch(mDevice, item); + } + } +} diff --git a/tests/uitests/src/com/android/settings/ui/LocationSettingsTests.java b/tests/uitests/src/com/android/settings/ui/LocationSettingsTests.java new file mode 100644 index 00000000000..b4a1baa8c23 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/LocationSettingsTests.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.SettingsHelper; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; + + +public class LocationSettingsTests extends InstrumentationTestCase { + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + private static final int TIMEOUT = 2000; + private UiDevice mDevice; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientaion", e); + } + } + + @Override + protected void tearDown() throws Exception { + mDevice.pressBack(); + mDevice.pressHome(); + super.tearDown(); + } + + @MediumTest + public void testLoadingLocationSettings () throws Exception { + // Load Security + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_SECURITY_SETTINGS); + + SettingsHelper helper = new SettingsHelper(); + helper.scrollVert(true); + // Tap on location + UiObject2 settingsPanel = mDevice.wait(Until.findObject + (By.res(SETTINGS_PACKAGE, "main_content")), TIMEOUT); + int count = 0; + UiObject2 locationTitle = null; + while(count < 6 && locationTitle == null) { + locationTitle = mDevice.wait(Until.findObject(By.text("Location")), TIMEOUT); + if (locationTitle == null) { + settingsPanel.scroll(Direction.DOWN, 1.0f); + } + count++; + } + // Verify location settings loads. + locationTitle.click(); + Thread.sleep(TIMEOUT); + assertNotNull("Location screen has not loaded correctly", + mDevice.wait(Until.findObject(By.text("Location services")), TIMEOUT)); + } + + @Presubmit + @MediumTest + public void testLocationSettingOn() throws Exception { + verifyLocationSettingsOnOrOff(true); + } + + @MediumTest + public void testLocationSettingOff() throws Exception { + verifyLocationSettingsOnOrOff(false); + } + + @MediumTest + public void testLocationDeviceOnlyMode() throws Exception { + // Changing the value from default before testing the toggle to Device only mode + Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_HIGH_ACCURACY); + dismissAlertDialogs(); + Thread.sleep(TIMEOUT); + verifyLocationSettingsMode(Settings.Secure.LOCATION_MODE_SENSORS_ONLY); + } + + @MediumTest + public void testLocationBatterySavingMode() throws Exception { + Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_SENSORS_ONLY); + Thread.sleep(TIMEOUT); + verifyLocationSettingsMode(Settings.Secure.LOCATION_MODE_BATTERY_SAVING); + } + + @MediumTest + public void testLocationHighAccuracyMode() throws Exception { + Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_SENSORS_ONLY); + Thread.sleep(TIMEOUT); + verifyLocationSettingsMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY); + } + + @MediumTest + public void testLocationSettingsElements() throws Exception { + String[] textElements = {"Location", "Mode", "Recent location requests", + "Location services"}; + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_LOCATION_SOURCE_SETTINGS); + Thread.sleep(TIMEOUT); + for (String element : textElements) { + assertNotNull(element + " item not found under Location Settings", + mDevice.wait(Until.findObject(By.text(element)), TIMEOUT)); + } + } + + @MediumTest + public void testLocationSettingsOverflowMenuElements() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_LOCATION_SOURCE_SETTINGS); + // Verify help & feedback + assertNotNull("Help & feedback item not found under Location Settings", + mDevice.wait(Until.findObject(By.desc("Help & feedback")), TIMEOUT)); + // Verify scanning + assertNotNull("Scanning item not found under Location Settings", + mDevice.wait(Until.findObject(By.text("Scanning")), TIMEOUT)); + } + + private void verifyLocationSettingsMode(int mode) throws Exception { + int modeIntValue = 1; + String textMode = "Device only"; + if (mode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY) { + modeIntValue = 3; + textMode = "High accuracy"; + } + else if (mode == Settings.Secure.LOCATION_MODE_BATTERY_SAVING) { + modeIntValue = 2; + textMode = "Battery saving"; + } + // Load location settings + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_LOCATION_SOURCE_SETTINGS); + // Tap on mode + dismissAlertDialogs(); + // Load location settings + mDevice.wait(Until.findObject(By.text("Mode")), TIMEOUT).click(); + Thread.sleep(TIMEOUT); + assertNotNull("Location mode screen not loaded", mDevice.wait(Until.findObject + (By.text("Location mode")), TIMEOUT)); + // Choose said mode + mDevice.wait(Until.findObject(By.text(textMode)), TIMEOUT).click(); + Thread.sleep(TIMEOUT); + dismissAlertDialogs(); + mDevice.wait(Until.findObject(By.desc("Navigate up")), TIMEOUT).click(); + Thread.sleep(TIMEOUT); + if (mode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY || + mode == Settings.Secure.LOCATION_MODE_BATTERY_SAVING) { + dismissAlertDialogs(); + } + // get setting and verify value + // Verify change of mode + int locationSettingMode = + Settings.Secure.getInt(getInstrumentation().getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE); + assertEquals(mode + " value not set correctly for location.", modeIntValue, + locationSettingMode); + } + + private void verifyLocationSettingsOnOrOff(boolean verifyOn) throws Exception { + // Set location flag + if (verifyOn) { + Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); + } + else { + Settings.Secure.putInt(getInstrumentation().getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_HIGH_ACCURACY); + } + dismissAlertDialogs(); + // Load location settings + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_LOCATION_SOURCE_SETTINGS); + dismissAlertDialogs(); + // Toggle UI + mDevice.wait(Until.findObject(By.res(SETTINGS_PACKAGE, "switch_widget")), TIMEOUT).click(); + dismissAlertDialogs(); + Thread.sleep(TIMEOUT); + // Verify change in setting + int locationEnabled = Settings.Secure.getInt(getInstrumentation() + .getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE); + if (verifyOn) { + assertFalse("Location not enabled correctly", locationEnabled == 0); + } + else { + assertEquals("Location not disabled correctly", 0, locationEnabled); + } + } + + // This method dismisses both alert dialogs that might popup and + // interfere with the test. Since the order in which the dialog + // shows up changes in no specific known way, we're checking for + // both dialogs in any order for a robust test. Bug b/36233151 + // filed against Location team for specifications. This is a + // workaround in the meantime to ensure coverage. + private void dismissAlertDialogs() throws Exception { + for (int count = 0; count < 2; count++) { + UiObject2 agreeDialog = mDevice.wait(Until.findObject + (By.text("Improve location accuracy?")), TIMEOUT); + UiObject2 previousChoiceYesButton = mDevice.wait(Until.findObject + (By.text("YES")), TIMEOUT); + if (agreeDialog != null) { + mDevice.wait(Until.findObject + (By.text("AGREE")), TIMEOUT).click(); + Thread.sleep(TIMEOUT); + assertNull("Improve location dialog not dismissed", + mDevice.wait(Until.findObject + (By.text("Improve location accuracy?")), TIMEOUT)); + } + if (previousChoiceYesButton != null) { + previousChoiceYesButton.click(); + // Short sleep to wait for the new screen + Thread.sleep(TIMEOUT); + } + } + } +} diff --git a/tests/uitests/src/com/android/settings/ui/MoreWirelessSettingsTests.java b/tests/uitests/src/com/android/settings/ui/MoreWirelessSettingsTests.java new file mode 100644 index 00000000000..25236869561 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/MoreWirelessSettingsTests.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.SettingsHelper; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; + + +public class MoreWirelessSettingsTests extends InstrumentationTestCase { + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + private static final int TIMEOUT = 2000; + private UiDevice mDevice; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientaion", e); + } + } + + @Override + protected void tearDown() throws Exception { + mDevice.pressBack(); + mDevice.pressHome(); + super.tearDown(); + } + + @Presubmit + @MediumTest + public void testAirplaneModeEnabled() throws Exception { + verifyAirplaneModeOnOrOff(true); + // Toggling this via the wifi network settings page + // because of bug b/34858716. Once that is fixed, + // we should be able to set this via Settings putString. + toggleAirplaneModeSwitch(); + } + + @Presubmit + @MediumTest + public void testAirplaneModeDisabled() throws Exception { + verifyAirplaneModeOnOrOff(false); + } + + @MediumTest + public void testTetheringMenuLoad() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_WIRELESS_SETTINGS); + mDevice.wait(Until + .findObject(By.text("Hotspot & tethering")), TIMEOUT) + .click(); + Thread.sleep(TIMEOUT); + UiObject2 usbTethering = mDevice.wait(Until + .findObject(By.text("USB tethering")), TIMEOUT); + assertNotNull("Tethering screen did not load correctly", usbTethering); + } + + @MediumTest + public void testVPNMenuLoad() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_WIRELESS_SETTINGS); + mDevice.wait(Until + .findObject(By.text("VPN")), TIMEOUT) + .click(); + Thread.sleep(TIMEOUT); + UiObject2 usbTethering = mDevice.wait(Until + .findObject(By.res(SETTINGS_PACKAGE, "vpn_create")), TIMEOUT); + assertNotNull("VPN screen did not load correctly", usbTethering); + } + + private void verifyAirplaneModeOnOrOff(boolean verifyOn) throws Exception { + if (verifyOn) { + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, "0"); + } + else { + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, "1"); + } + toggleAirplaneModeSwitch(); + String airplaneModeValue = Settings.Global + .getString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON); + if (verifyOn) { + assertEquals("1", airplaneModeValue); + } + else { + assertEquals("0", airplaneModeValue); + } + } + + private void toggleAirplaneModeSwitch() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_WIRELESS_SETTINGS); + mDevice.wait(Until + .findObject(By.text("Airplane mode")), TIMEOUT) + .click(); + Thread.sleep(TIMEOUT); + } +} diff --git a/tests/uitests/src/com/android/settings/ui/NotificationSettingsTests.java b/tests/uitests/src/com/android/settings/ui/NotificationSettingsTests.java new file mode 100644 index 00000000000..133332c2dac --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/NotificationSettingsTests.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.content.Intent; +import android.os.RemoteException; +import android.provider.Settings; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.BySelector; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.ActivityHelper; +import android.system.helpers.SettingsHelper; +import android.widget.ListView; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.util.Log; + +/** Verifies that you can get to the notification app listing page from the apps & notifications + * page */ +public class NotificationSettingsTests extends InstrumentationTestCase { + private static final boolean LOCAL_LOGV = false; + private static final String TAG = "NotifiSettingsTests"; + private static final int TIMEOUT = 2000; + private ActivityHelper mActivityHelper = null; + private SettingsHelper mSettingsHelper = null; + + private UiDevice mDevice; + @Override + public void setUp() throws Exception { + if (LOCAL_LOGV) { + Log.d(TAG, "-------"); + } + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + mActivityHelper = ActivityHelper.getInstance(); + mSettingsHelper = SettingsHelper.getInstance(); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("Failed to freeze device orientaion", e); + } + + // make sure we are in a clean state before starting the test + mDevice.pressHome(); + Thread.sleep(TIMEOUT * 2); + launchAppsSettings(); + } + + @Override + protected void tearDown() throws Exception { + mDevice.pressBack(); + mDevice.pressHome(); // finish settings activity + mDevice.waitForIdle(TIMEOUT * 2); // give UI time to finish animating + super.tearDown(); + } + + @MediumTest + public void testNotificationsSettingsListForCalculator() { + UiObject2 configureNotifications = mDevice.wait( + Until.findObject(By.text("Notifications")), TIMEOUT); + configureNotifications.click(); + mDevice.wait(Until.findObject(By.text("Blink light")), TIMEOUT); + UiObject2 appNotifications = mDevice.wait( + Until.findObject(By.text("On for all apps")), TIMEOUT); + appNotifications.click(); + UiObject2 view = + mDevice.wait( + Until.findObject(By.text("All apps")), TIMEOUT); + assertNotNull("Could not find Settings > Apps screen", view); + UiObject2 app = mDevice.wait(Until.findObject(By.text("Calculator")), TIMEOUT); + assertNotNull("Could not find Calculator notification settings", app); + } + + + @MediumTest + public void testNotificationsSettingsListForPhone() { + UiObject2 configureNotifications = mDevice.wait( + Until.findObject(By.text("Notifications")), TIMEOUT); + configureNotifications.click(); + mDevice.wait(Until.findObject(By.text("Blink light")), TIMEOUT); + UiObject2 appNotifications = mDevice.wait( + Until.findObject(By.text("On for all apps")), TIMEOUT); + appNotifications.click(); + UiObject2 view = + mDevice.wait( + Until.findObject(By.text("All apps")), TIMEOUT); + assertNotNull("Could not find Settings > Apps screen", view); + + final BySelector preferenceListSelector = By.clazz(ListView.class).res("android:id/list"); + UiObject2 apps = mDevice.wait(Until.findObject(preferenceListSelector), TIMEOUT); + + UiObject2 phone = scrollTo(mDevice, apps, By.text("Phone"), Direction.DOWN); + assertNotNull("Could not find Phone notification settings", phone); + phone.click(); + UiObject2 incomingCalls = mDevice.wait(Until.findObject(By.text("Incoming calls")), TIMEOUT); + assertNotNull("Could not find incoming calls channel", incomingCalls); + incomingCalls.click(); + + // here's the meat of this test: make sure that you cannot change + // most settings for this channel + + UiObject2 importance = mDevice.wait(Until.findObject(By.text("Importance")), TIMEOUT); + assertNotNull("Could not find importance toggle", importance); + assertFalse(importance.isEnabled()); + assertFalse(mDevice.wait(Until.findObject(By.text("Sound")), TIMEOUT).isEnabled());; + assertFalse(mDevice.wait(Until.findObject(By.text("Vibrate")), TIMEOUT).isEnabled()); + assertFalse(mDevice.wait(Until.findObject(By.text("Override Do Not Disturb")), TIMEOUT).isEnabled()); + + + + + + + } + + private UiObject2 scrollTo(UiDevice device, UiObject2 scrollable, + BySelector target, Direction direction) { + while (!device.hasObject(target) && scrollable.scroll(direction, 1.0f)) { + // continue + } + if (!device.hasObject(target)) { + // Scroll once more if not found; in some cases UiObject2.scroll can return false when + // the last item is not fully visible yet for list views. + scrollable.scroll(direction, 1.0f); + } + return device.findObject(target); + } + + + private void launchAppsSettings() throws Exception { + Intent appsSettingsIntent = new Intent(Settings.ACTION_SETTINGS); + mActivityHelper.launchIntent(appsSettingsIntent); + mSettingsHelper.flingSettingsToStart(); + UiObject2 view = mDevice.wait( + Until.findObject(By.text("Apps & notifications")), TIMEOUT); + view.click(); + UiObject2 title = mDevice.wait( + Until.findObject(By.text("Apps & notifications")), TIMEOUT); + assertNotNull("Could not find Settings > Apps & notifications screen", title); + } +} diff --git a/tests/uitests/src/com/android/settings/ui/SecuritySettingsLaunchTest.java b/tests/uitests/src/com/android/settings/ui/SecuritySettingsLaunchTest.java new file mode 100644 index 00000000000..b730690d22c --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/SecuritySettingsLaunchTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.os.RemoteException; +import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.UiDevice; +import android.system.helpers.SettingsHelper; + +import com.android.settings.ui.testutils.SettingsTestUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SecuritySettingsLaunchTest { + + // Items we really want to always show + private static final String[] CATEGORIES = new String[]{ + "Security status", + "Device security", + "Privacy", + }; + + private UiDevice mDevice; + private SettingsHelper mHelper; + + @Before + public void setUp() throws Exception { + mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + mHelper = SettingsHelper.getInstance(); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientaion", e); + } + } + + @After + public void tearDown() throws Exception { + // Go back to home for next test. + mDevice.pressHome(); + } + + @Test + public void launchSecuritySettings() throws Exception { + // Launch Settings + SettingsHelper.launchSettingsPage( + InstrumentationRegistry.getContext(), Settings.ACTION_SECURITY_SETTINGS); + mHelper.scrollVert(false); + for (String category : CATEGORIES) { + SettingsTestUtils.assertTitleMatch(mDevice, category); + } + } +} diff --git a/tests/uitests/src/com/android/settings/ui/SoundSettingsTest.java b/tests/uitests/src/com/android/settings/ui/SoundSettingsTest.java new file mode 100644 index 00000000000..0aec505185e --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/SoundSettingsTest.java @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.app.NotificationManager; +import android.content.ContentResolver; +import android.content.Context; +import android.os.Handler; +import android.os.SystemClock; +import android.provider.Settings; +import android.service.notification.ZenModeConfig; +import android.support.test.uiautomator.UiObject2; +import android.system.helpers.SettingsHelper; +import android.system.helpers.SettingsHelper.SettingsType; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.Until; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.HashMap; + +public class SoundSettingsTest extends InstrumentationTestCase { + private static final String PAGE = Settings.ACTION_SOUND_SETTINGS; + private static final int TIMEOUT = 2000; + + private UiDevice mDevice; + private ContentResolver mResolver; + private SettingsHelper mHelper; + + + private HashMap ringtoneSounds = new HashMap() {{ + put("angler","Dione"); + put("bullhead","Dione"); + put("marlin","Spaceship"); + put("sailfish","Spaceship"); + put("walleye","Copycat"); + put("taimen","Copycat"); + }}; + + private HashMap ringtoneCodes = new HashMap() {{ + put("angler","38"); + put("bullhead","38"); + put("marlin","37"); + put("sailfish","37"); + put("walleye","26"); + put("taimen","26"); + }}; + + private HashMap alarmSounds = new HashMap() {{ + put("angler","Awaken"); + put("bullhead","Awaken"); + put("marlin","Bounce"); + put("sailfish","Bounce"); + put("walleye","Cuckoo clock"); + put("taimen","Cuckoo clock"); + }}; + + private HashMap alarmCodes = new HashMap() {{ + put("angler","6"); + put("bullhead","6"); + put("marlin","49"); + put("sailfish","49"); + put("walleye","15"); + put("taimen","15"); + }}; + + private HashMap notificationSounds = new HashMap() {{ + put("angler","Ceres"); + put("bullhead","Ceres"); + put("marlin","Trill"); + put("sailfish","Trill"); + put("walleye","Pipes"); + put("taimen","Pipes"); + }}; + + + private HashMap notificationCodes = new HashMap() {{ + put("angler","26"); + put("bullhead","26"); + put("marlin","57"); + put("sailfish","57"); + put("walleye","69"); + put("taimen","69"); + }}; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + mDevice.setOrientationNatural(); + mResolver = getInstrumentation().getContext().getContentResolver(); + mHelper = new SettingsHelper(); + } + + @Override + public void tearDown() throws Exception { + mDevice.pressBack(); + mDevice.pressHome(); + mDevice.waitForIdle(); + mDevice.unfreezeRotation(); + super.tearDown(); + } + + @MediumTest + public void testCallVibrate() throws Exception { + assertTrue(mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, + "Also vibrate for calls", Settings.System.VIBRATE_WHEN_RINGING)); + assertTrue(mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, + "Also vibrate for calls", Settings.System.VIBRATE_WHEN_RINGING)); + } + + @MediumTest + public void testOtherSoundsDialPadTones() throws Exception { + loadOtherSoundsPage(); + assertTrue("Dial pad tones not toggled", mHelper.verifyToggleSetting( + SettingsType.SYSTEM, PAGE, "Dial pad tones", + Settings.System.DTMF_TONE_WHEN_DIALING)); + } + + @MediumTest + public void testOtherSoundsScreenLocking() throws Exception { + loadOtherSoundsPage(); + assertTrue("Screen locking sounds not toggled", + mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, + "Screen locking sounds", Settings.System.LOCKSCREEN_SOUNDS_ENABLED)); + } + + @MediumTest + public void testOtherSoundsCharging() throws Exception { + loadOtherSoundsPage(); + assertTrue("Charging sounds not toggled", + mHelper.verifyToggleSetting(SettingsType.GLOBAL, PAGE, + "Charging sounds", Settings.Global.CHARGING_SOUNDS_ENABLED)); + } + + @MediumTest + public void testOtherSoundsTouch() throws Exception { + loadOtherSoundsPage(); + assertTrue("Touch sounds not toggled", + mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, + "Touch sounds", Settings.System.SOUND_EFFECTS_ENABLED)); + } + + @MediumTest + public void testOtherSoundsVibrateOnTap() throws Exception { + loadOtherSoundsPage(); + assertTrue("Vibrate on tap not toggled", + mHelper.verifyToggleSetting(SettingsType.SYSTEM, PAGE, + "Vibrate on tap", Settings.System.HAPTIC_FEEDBACK_ENABLED)); + } + + private void loadOtherSoundsPage() throws Exception { + launchSoundSettings(); + mHelper.scrollVert(false); + Thread.sleep(1000); + } + + private void launchSoundSettings() throws Exception { + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), PAGE); + mHelper.scrollVert(false); + clickMore(); + Thread.sleep(1000); + mHelper.scrollVert(true); + Thread.sleep(1000); + } + + /* + * Rather than verifying every ringtone, verify the ones least likely to change + * (None and Hangouts) and an arbitrary one from the ringtone pool. + */ + @MediumTest + public void testPhoneRingtoneNone() throws Exception { + launchSoundSettings(); + mHelper.clickSetting("Phone ringtone"); + verifyRingtone(new RingtoneSetting("None", "null"), + Settings.System.RINGTONE); + } + + @MediumTest + @Suppress + public void testPhoneRingtoneHangouts() throws Exception { + launchSoundSettings(); + mHelper.clickSetting("Phone ringtone"); + verifyRingtone(new RingtoneSetting("Hangouts Call", "31"), Settings.System.RINGTONE); + } + + @MediumTest + public void testPhoneRingtone() throws Exception { + launchSoundSettings(); + mHelper.clickSetting("Phone ringtone"); + String ringtone = ringtoneSounds.get(mDevice.getProductName()).toString(); + String ringtoneSettingValue = ringtoneCodes.get(mDevice.getProductName()).toString(); + verifyRingtone(new RingtoneSetting(ringtone, ringtoneSettingValue), + Settings.System.RINGTONE); + } + + @MediumTest + public void testNotificationRingtoneNone() throws Exception { + launchSoundSettings(); + mHelper.clickSetting("Default notification sound"); + verifyRingtone(new RingtoneSetting("None", "null"), + Settings.System.NOTIFICATION_SOUND); + } + + @MediumTest + @Suppress + public void testNotificationRingtoneHangouts() throws Exception { + launchSoundSettings(); + mHelper.clickSetting("Default notification sound"); + verifyRingtone(new RingtoneSetting("Hangouts Message", "30"), + Settings.System.NOTIFICATION_SOUND); + } + + @MediumTest + public void testNotificationRingtone() throws Exception { + launchSoundSettings(); + mHelper.clickSetting("Default notification sound"); + String notificationRingtone = notificationSounds.get(mDevice.getProductName()).toString(); + String notificationSettingValue = notificationCodes.get(mDevice.getProductName()).toString(); + verifyRingtone(new RingtoneSetting(notificationRingtone, notificationSettingValue), + Settings.System.NOTIFICATION_SOUND); + } + + @MediumTest + public void testAlarmRingtoneNone() throws Exception { + launchSoundSettings(); + mHelper.clickSetting("Default alarm sound"); + verifyRingtone(new RingtoneSetting("None", "null"), + Settings.System.ALARM_ALERT); + } + + @MediumTest + public void testAlarmRingtone() throws Exception { + launchSoundSettings(); + String alarmRingtone = alarmSounds.get(mDevice.getProductName()).toString(); + String alarmSettingValue = alarmCodes.get(mDevice.getProductName()).toString(); + mHelper.clickSetting("Default alarm sound"); + verifyRingtone(new RingtoneSetting(alarmRingtone, alarmSettingValue), + Settings.System.ALARM_ALERT); + } + + /* + * This method verifies that setting a custom ringtone changes the + * ringtone code setting on the system. Each ringtone sound corresponds + * to an arbitrary code. To see which ringtone code this is on your device, run + * adb shell settings get system ringtone + * The number you see at the end of the file path is the one you need. + * To see alarms and notifications ringtone codes, run the following: + * adb shell settings get system alarm_alert + * adb shell settings get system notification_sound + * @param r Ringtone setting - the name of the ringtone as displayed on device + * @param settingName - the code of the ringtone as explained above + * @param dir - the direction in which to scroll + */ + private void verifyRingtone(RingtoneSetting r, String settingName) throws Exception { + findRingtoneInList(r.getName()).click(); + if (mDevice.getProductName().equals("walleye") || mDevice.getProductName().equals("taimen")) { + mDevice.wait(Until.findObject(By.text("SAVE")), TIMEOUT).click(); + } + else { + mDevice.wait(Until.findObject(By.text("OK")), TIMEOUT).click(); + } + SystemClock.sleep(1000); + if (r.getVal().equals("null")) { + assertEquals(null, + Settings.System.getString(mResolver, settingName)); + } else if (r.getName().contains("Hangouts")) { + assertEquals("content://media/external/audio/media/" + r.getVal(), + Settings.System.getString(mResolver, settingName)); + } else { + assertEquals("content://media/internal/audio/media/" + r.getVal(), + Settings.System.getString(mResolver, settingName)); + } + } + + private enum ScrollDir { + UP, + DOWN, + NOSCROLL + } + + class RingtoneSetting { + private final String mName; + private final String mMediaVal; + public RingtoneSetting(String name, String fname) { + mName = name; + mMediaVal = fname; + } + public String getName() { + return mName; + } + public String getVal() { + return mMediaVal; + } + } + + private void clickMore() throws InterruptedException { + UiObject2 more = mDevice.wait(Until.findObject(By.text("Advanced")), TIMEOUT); + if (more != null) { + more.click(); + Thread.sleep(TIMEOUT); + } + } + + private UiObject2 findRingtoneInList(String ringtone) throws Exception { + mHelper.scrollVert(false); + SystemClock.sleep(1000); + UiObject2 ringToneObject = mDevice.wait(Until.findObject(By.text(ringtone)), TIMEOUT); + int count = 0; + while (ringToneObject == null && count < 5) { + mHelper.scrollVert(true); + SystemClock.sleep(1000); + ringToneObject = mDevice.wait(Until.findObject(By.text(ringtone)), TIMEOUT); + count++; + } + return ringToneObject; + } +} diff --git a/tests/uitests/src/com/android/settings/ui/SyncSettingsTest.java b/tests/uitests/src/com/android/settings/ui/SyncSettingsTest.java new file mode 100644 index 00000000000..3dca424b2bd --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/SyncSettingsTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.os.RemoteException; +import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.SettingsHelper; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static junit.framework.Assert.assertTrue; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SyncSettingsTest { + private static final int TIMEOUT = 2000; + + private UiDevice mDevice; + + @Before + public void setUp() throws Exception { + mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientaion", e); + } + } + + @After + public void tearDown() throws Exception { + // Need to finish settings activity + mDevice.pressHome(); + } + + @Test + public void syncPageShouldHaveAddAccountButton() throws Exception { + // Launch Settings + SettingsHelper.launchSettingsPage( + InstrumentationRegistry.getContext(), Settings.ACTION_SYNC_SETTINGS); + UiObject2 addAccount = mDevice.wait( + Until.findObject(By.text("Add account")), TIMEOUT); + assertTrue(addAccount != null); + } +} diff --git a/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsTests.java b/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsTests.java new file mode 100644 index 00000000000..1e3b978c804 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsTests.java @@ -0,0 +1,777 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui; + +import android.content.Context; +import android.content.Intent; +import android.net.wifi.WifiManager; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.system.helpers.CommandsHelper; +import android.system.helpers.SettingsHelper; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.BySelector; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.StaleObjectException; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; +import junit.framework.AssertionFailedError; + +public class WirelessNetworkSettingsTests extends InstrumentationTestCase { + // These back button presses are performed in tearDown() to exit Wifi + // Settings sub-menus that a test might finish in. This number should be + // high enough to account for the deepest sub-menu a test might enter. + private static final int NUM_BACK_BUTTON_PRESSES = 5; + private static final int TIMEOUT = 2000; + private static final int SLEEP_TIME = 500; + private static final String AIRPLANE_MODE_BROADCAST = + "am broadcast -a android.intent.action.AIRPLANE_MODE"; + private static final String TAG="WirelessNetworkSettingsTests"; + + // Note: The values of these variables might affect flakiness in tests that involve + // scrolling. Adjust where necessary. + private static final float SCROLL_UP_PERCENT = 10.0f; + private static final float SCROLL_DOWN_PERCENT = 0.5f; + private static final int MAX_SCROLL_ATTEMPTS = 10; + private static final int MAX_ADD_NETWORK_BUTTON_ATTEMPTS = 3; + private static final int SCROLL_SPEED = 2000; + + private static final String TEST_SSID = "testSsid"; + private static final String TEST_PW_GE_8_CHAR = "testPasswordGreaterThan8Char"; + private static final String TEST_PW_LT_8_CHAR = "lt8Char"; + private static final String TEST_DOMAIN = "testDomain.com"; + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + + private static final String CHECKBOX_CLASS = "android.widget.CheckBox"; + private static final String SPINNER_CLASS = "android.widget.Spinner"; + private static final String EDIT_TEXT_CLASS = "android.widget.EditText"; + private static final String SCROLLVIEW_CLASS = "android.widget.ScrollView"; + private static final String LISTVIEW_CLASS = "android.widget.ListView"; + + private static final String ADD_NETWORK_MENU_CANCEL_BUTTON_TEXT = "CANCEL"; + private static final String ADD_NETWORK_MENU_SAVE_BUTTON_TEXT = "SAVE"; + private static final String ADD_NETWORK_PREFERENCE_TEXT = "Add network"; + private static final String CONFIGURE_WIFI_PREFERENCE_TEXT = "Wi‑Fi preferences"; + private static final String CONFIGURE_WIFI_ADVANCED_PREFERENCE_TEXT = "Advanced"; + private static final String CACERT_MENU_PLEASE_SELECT_TEXT = "Please select"; + private static final String CACERT_MENU_USE_SYSTEM_CERTS_TEXT = "Use system certificates"; + private static final String CACERT_MENU_DO_NOT_VALIDATE_TEXT = "Do not validate"; + private static final String USERCERT_MENU_PLEASE_SELECT_TEXT = "Please select"; + private static final String USERCERT_MENU_DO_NOT_PROVIDE_TEXT = "Do not provide"; + private static final String SECURITY_OPTION_NONE_TEXT = "None"; + private static final String SECURITY_OPTION_WEP_TEXT = "WEP"; + private static final String SECURITY_OPTION_PSK_TEXT = "WPA/WPA2 PSK"; + private static final String SECURITY_OPTION_EAP_TEXT = "802.1x EAP"; + private static final String EAP_METHOD_PEAP_TEXT = "PEAP"; + private static final String EAP_METHOD_TLS_TEXT = "TLS"; + private static final String EAP_METHOD_TTLS_TEXT = "TTLS"; + private static final String EAP_METHOD_PWD_TEXT = "PWD"; + private static final String EAP_METHOD_SIM_TEXT = "SIM"; + private static final String EAP_METHOD_AKA_TEXT = "AKA"; + private static final String EAP_METHOD_AKA_PRIME_TEXT = "AKA'"; + private static final String PHASE2_MENU_NONE_TEXT = "None"; + private static final String PHASE2_MENU_MSCHAPV2_TEXT = "MSCHAPV2"; + private static final String PHASE2_MENU_GTC_TEXT = "GTC"; + + private static final String ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID = "wifi_advanced_togglebox"; + private static final String ADD_NETWORK_MENU_IP_SETTINGS_RES_ID = "ip_settings"; + private static final String ADD_NETWORK_MENU_PROXY_SETTINGS_RES_ID = "proxy_settings"; + private static final String ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID = "security"; + private static final String ADD_NETWORK_MENU_EAP_METHOD_RES_ID = "method"; + private static final String ADD_NETWORK_MENU_SSID_RES_ID = "ssid"; + private static final String ADD_NETWORK_MENU_PHASE2_RES_ID = "phase2"; + private static final String ADD_NETWORK_MENU_CACERT_RES_ID = "ca_cert"; + private static final String ADD_NETWORK_MENU_USERCERT_RES_ID = "user_cert"; + private static final String ADD_NETWORK_MENU_NO_DOMAIN_WARNING_RES_ID = "no_domain_warning"; + private static final String ADD_NETWORK_MENU_NO_CACERT_WARNING_RES_ID = "no_ca_cert_warning"; + private static final String ADD_NETWORK_MENU_DOMAIN_LAYOUT_RES_ID = "l_domain"; + private static final String ADD_NETWORK_MENU_DOMAIN_RES_ID = "domain"; + private static final String ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID = "l_identity"; + private static final String ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID = "l_anonymous"; + private static final String ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID = "password_layout"; + private static final String ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID = + "show_password_layout"; + private static final String ADD_NETWORK_MENU_PASSWORD_RES_ID = "password"; + + private static final BySelector ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR = + By.scrollable(true).clazz(SCROLLVIEW_CLASS); + private static final BySelector SPINNER_OPTIONS_SCROLLABLE_BY_SELECTOR = + By.scrollable(true).clazz(LISTVIEW_CLASS); + + private UiDevice mDevice; + private CommandsHelper mCommandsHelper; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientation", e); + } + // Ensure airplane mode is OFF so that wifi can be enabled using WiFiManager. + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, "0"); + Log.d(TAG, "sending airplane mode broadcast to device"); + mCommandsHelper = CommandsHelper.getInstance(); + mCommandsHelper.executeShellCommand(AIRPLANE_MODE_BROADCAST); + } + + @Override + protected void tearDown() throws Exception { + // Exit all settings sub-menus. + for (int i = 0; i < NUM_BACK_BUTTON_PRESSES; ++i) { + mDevice.pressBack(); + } + mDevice.pressHome(); + super.tearDown(); + } + + @Presubmit + @MediumTest + public void testWiFiEnabled() throws Exception { + verifyWiFiOnOrOff(true); + } + + @Presubmit + @MediumTest + public void testWiFiDisabled() throws Exception { + verifyWiFiOnOrOff(false); + } + + @MediumTest + public void testWifiMenuLoadConfigure() throws Exception { + loadWiFiConfigureMenu(); + Thread.sleep(SLEEP_TIME); + UiObject2 configureWiFiHeading = mDevice.wait(Until.findObject + (By.text(CONFIGURE_WIFI_PREFERENCE_TEXT)), TIMEOUT); + assertNotNull("Configure WiFi menu has not loaded correctly", configureWiFiHeading); + } + + @MediumTest + public void testNetworkNotificationsOn() throws Exception { + verifyNetworkNotificationsOnOrOff(true); + } + + @MediumTest + public void testNetworkNotificationsOff() throws Exception { + verifyNetworkNotificationsOnOrOff(false); + } + + @MediumTest + public void testAddNetworkMenu_Default() throws Exception { + loadAddNetworkMenu(); + + // Submit button should be disabled by default, while cancel button should be enabled. + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_CANCEL_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Check that the SSID field is defaults to the hint. + assertEquals("Enter the SSID", mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SSID_RES_ID) + .clazz(EDIT_TEXT_CLASS)), TIMEOUT*2) + .getText()); + + // Check Security defaults to None. + assertEquals("None", mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID) + .clazz(SPINNER_CLASS)), TIMEOUT) + .getChildren().get(0).getText()); + + // Check advanced options are collapsed by default. + assertFalse(mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) + .clazz(CHECKBOX_CLASS)), TIMEOUT).isChecked()); + + } + + @Suppress + @MediumTest + public void testAddNetworkMenu_Proxy() throws Exception { + loadAddNetworkMenu(); + + // Toggle advanced options. + mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) + .clazz(CHECKBOX_CLASS)), TIMEOUT).click(); + + // Verify Proxy defaults to None. + BySelector proxySettingsBySelector = + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PROXY_SETTINGS_RES_ID) + .clazz(SPINNER_CLASS); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); + assertEquals("None", mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT) + .getChildren().get(0).getText()); + + // Verify that Proxy Manual fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); + mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT).click(); + mDevice.wait(Until.findObject(By.text("Manual")), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "proxy_warning_limited_support")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "proxy_hostname")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "proxy_exclusionlist")); + + // Verify that Proxy Auto-Config options appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); + mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT).click(); + mDevice.wait(Until.findObject(By.text("Proxy Auto-Config")), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "proxy_pac")); + } + + @Suppress + @MediumTest + public void testAddNetworkMenu_IpSettings() throws Exception { + loadAddNetworkMenu(); + + // Toggle advanced options. + mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) + .clazz(CHECKBOX_CLASS)), TIMEOUT).click(); + + // Verify IP settings defaults to DHCP. + BySelector ipSettingsBySelector = + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IP_SETTINGS_RES_ID).clazz(SPINNER_CLASS); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, ipSettingsBySelector); + assertEquals("DHCP", mDevice.wait(Until.findObject(ipSettingsBySelector), TIMEOUT) + .getChildren().get(0).getText()); + + // Verify that Static IP settings options appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, ipSettingsBySelector).click(); + mDevice.wait(Until.findObject(By.text("Static")), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "ipaddress")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "gateway")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "network_prefix_length")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "dns1")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "dns2")); + } + + @Suppress + @MediumTest + public void testPhase2Settings() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + + BySelector phase2SettingsBySelector = + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID).clazz(SPINNER_CLASS); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, phase2SettingsBySelector); + assertEquals(PHASE2_MENU_NONE_TEXT, mDevice.wait(Until + .findObject(phase2SettingsBySelector), TIMEOUT).getChildren().get(0).getText()); + mDevice.wait(Until.findObject(phase2SettingsBySelector), TIMEOUT).click(); + Thread.sleep(SLEEP_TIME); + + // Verify Phase 2 authentication spinner options. + assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_NONE_TEXT)), TIMEOUT)); + assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_MSCHAPV2_TEXT)), TIMEOUT)); + assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_GTC_TEXT)), TIMEOUT)); + } + + @Suppress + @MediumTest + public void testCaCertSettings() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + + BySelector caCertSettingsBySelector = + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID).clazz(SPINNER_CLASS); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, caCertSettingsBySelector); + assertEquals(CACERT_MENU_PLEASE_SELECT_TEXT, mDevice.wait(Until + .findObject(caCertSettingsBySelector), TIMEOUT).getChildren().get(0).getText()); + mDevice.wait(Until.findObject(caCertSettingsBySelector), TIMEOUT).click(); + Thread.sleep(SLEEP_TIME); + + // Verify CA certificate spinner options. + assertNotNull(mDevice.wait(Until.findObject( + By.text(CACERT_MENU_PLEASE_SELECT_TEXT)), TIMEOUT)); + assertNotNull(mDevice.wait(Until.findObject( + By.text(CACERT_MENU_USE_SYSTEM_CERTS_TEXT)), TIMEOUT)); + assertNotNull(mDevice.wait(Until.findObject( + By.text(CACERT_MENU_DO_NOT_VALIDATE_TEXT)), TIMEOUT)); + + // Verify that a domain field and warning appear when the user selects the + // "Use system certificates" option. + mDevice.wait(Until.findObject(By.text(CACERT_MENU_USE_SYSTEM_CERTS_TEXT)), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_DOMAIN_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_NO_DOMAIN_WARNING_RES_ID)); + + // Verify that a warning appears when the user chooses the "Do Not Validate" option. + mDevice.wait(Until.findObject(caCertSettingsBySelector), TIMEOUT).click(); + mDevice.wait(Until.findObject(By.text(CACERT_MENU_DO_NOT_VALIDATE_TEXT)), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_NO_CACERT_WARNING_RES_ID)); + } + + @Suppress + @MediumTest + public void testAddNetwork_NoSecurity() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_NONE_TEXT); + + // Entering an SSID is enough to enable the submit button. // TODO THIS GUY + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until + .findObject(By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_WEP() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_WEP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Verify that WEP fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Submit button is only enabled after a password is entered. + enterPassword(TEST_PW_GE_8_CHAR); + assertTrue(mDevice.wait(Until + .findObject(By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_PSK() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_PSK_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Verify that PSK fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Entering an password that is too short does not enable submit button. + enterPassword(TEST_PW_LT_8_CHAR); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Submit button is only enabled after a password of valid length is entered. + enterPassword(TEST_PW_GE_8_CHAR); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_PEAP() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_PEAP_TEXT); + + // Verify that EAP-PEAP fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + verifyCaCertificateSubmitConditions(); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_TLS() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_TLS_TEXT); + + // Verify that EAP-TLS fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_USERCERT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Selecting the User certificate "Do not provide" option alone does not enable the submit + // button. + selectUserCertificateOption(USERCERT_MENU_DO_NOT_PROVIDE_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + verifyCaCertificateSubmitConditions(); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_TTLS() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_TTLS_TEXT); + + // Verify that EAP-TLS fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + verifyCaCertificateSubmitConditions(); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_PWD() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_PWD_TEXT); + + // Verify that EAP-TLS fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone enables the submit button. + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_SIM() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_SIM_TEXT); + + // Entering an SSID alone enables the submit button. + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_AKA() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_AKA_TEXT); + + // Entering an SSID alone enables the submit button. + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_AKA_PRIME() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_AKA_PRIME_TEXT); + + // Entering an SSID alone enables the submit button. + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + private void verifyKeepWiFiOnDuringSleep(String settingToBeVerified, int settingValue) + throws Exception { + loadWiFiConfigureMenu(); + mDevice.wait(Until.findObject(By.text("Keep Wi‑Fi on during sleep")), TIMEOUT) + .click(); + mDevice.wait(Until.findObject(By.clazz("android.widget.CheckedTextView") + .text(settingToBeVerified)), TIMEOUT).click(); + Thread.sleep(SLEEP_TIME); + int keepWiFiOnSetting = + Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_SLEEP_POLICY); + assertEquals(settingValue, keepWiFiOnSetting); + } + + private void verifyNetworkNotificationsOnOrOff(boolean verifyOn) + throws Exception { + // Enable network recommendations to enable the toggle switch for Network + // notifications + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, "1"); + if (verifyOn) { + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "0"); + } + else { + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "1"); + } + loadWiFiConfigureMenu(); + mDevice.wait(Until.findObject(By.text("Open network notification")), TIMEOUT) + .click(); + Thread.sleep(SLEEP_TIME); + String wifiNotificationValue = + Settings.Global.getString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON); + if (verifyOn) { + assertEquals("1", wifiNotificationValue); + } + else { + assertEquals("0", wifiNotificationValue); + } + } + + private void verifyWiFiOnOrOff(boolean verifyOn) throws Exception { + String switchText = "On"; + if (verifyOn) { + switchText = "Off"; + } + loadWiFiSettingsPage(!verifyOn); + mDevice.wait(Until + .findObject(By.res(SETTINGS_PACKAGE, "switch_bar").text(switchText)), TIMEOUT) + .click(); + Thread.sleep(SLEEP_TIME); + String wifiValue = + Settings.Global.getString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_ON); + if (verifyOn) { + // 1 is Enabled, 2 is Enabled while airplane mode is ON. + assertTrue(wifiValue.equals("1") || wifiValue.equals("2")); + } + else { + assertEquals("0", wifiValue); + } + } + + private void verifyCaCertificateSubmitConditions() throws Exception { + // Selecting the CA certificate "Do not validate" option enables the submit button. + selectCaCertificateOption(CACERT_MENU_DO_NOT_VALIDATE_TEXT); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // However, selecting the CA certificate "Use system certificates option" is not enough to + // enable the submit button. + selectCaCertificateOption(CACERT_MENU_USE_SYSTEM_CERTS_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Submit button is only enabled after a domain is entered as well. + enterDomain(TEST_DOMAIN); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + private void loadWiFiSettingsPage(boolean wifiEnabled) throws Exception { + WifiManager wifiManager = (WifiManager)getInstrumentation().getContext() + .getSystemService(Context.WIFI_SERVICE); + wifiManager.setWifiEnabled(wifiEnabled); + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_WIFI_SETTINGS); + } + + private void loadWiFiConfigureMenu() throws Exception { + loadWiFiSettingsPage(false); + Thread.sleep(TIMEOUT); + mDevice.wait(Until.findObject(By.text(CONFIGURE_WIFI_PREFERENCE_TEXT)), TIMEOUT).click(); + mDevice.wait(Until.findObject( + By.text(CONFIGURE_WIFI_ADVANCED_PREFERENCE_TEXT)), TIMEOUT).click(); + } + + private void loadAddNetworkMenu() throws Exception { + loadWiFiSettingsPage(true); + for (int attempts = 0; attempts < MAX_ADD_NETWORK_BUTTON_ATTEMPTS; ++attempts) { + try { + findOrScrollToObject(By.scrollable(true), By.text(ADD_NETWORK_PREFERENCE_TEXT)) + .click(); + } catch (StaleObjectException e) { + // The network list might have been updated between when the Add network button was + // found, and when it UI automator attempted to click on it. Retry. + continue; + } + // If we get here, we successfully clicked on the Add network button, so we are done. + Thread.sleep(SLEEP_TIME*5); + return; + } + + fail("Failed to load Add Network Menu after " + MAX_ADD_NETWORK_BUTTON_ATTEMPTS + + " retries"); + } + + private void selectSecurityOption(String securityOption) throws Exception { + // We might not need to scroll to the security options if not enough add network menu + // options are visible. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID) + .clazz(SPINNER_CLASS)).click(); + Thread.sleep(SLEEP_TIME); + mDevice.wait(Until.findObject(By.text(securityOption)), TIMEOUT).click(); + } + + private void selectEAPMethod(String eapMethod) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_EAP_METHOD_RES_ID).clazz(SPINNER_CLASS)) + .click(); + Thread.sleep(SLEEP_TIME); + findOrScrollToObject(SPINNER_OPTIONS_SCROLLABLE_BY_SELECTOR, By.text(eapMethod)).click(); + } + + private void selectUserCertificateOption(String userCertificateOption) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_USERCERT_RES_ID).clazz(SPINNER_CLASS)) + .click(); + mDevice.wait(Until.findObject(By.text(userCertificateOption)), TIMEOUT).click(); + } + + private void selectCaCertificateOption(String caCertificateOption) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID).clazz(SPINNER_CLASS)) + .click(); + mDevice.wait(Until.findObject(By.text(caCertificateOption)), TIMEOUT).click(); + } + + private void enterSSID(String ssid) throws Exception { + // We might not need to scroll to the SSID option if not enough add network menu options + // are visible. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SSID_RES_ID).clazz(EDIT_TEXT_CLASS)) + .setText(ssid); + } + + private void enterPassword(String password) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_RES_ID).clazz(EDIT_TEXT_CLASS)) + .setText(password); + } + + private void enterDomain(String domain) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_DOMAIN_RES_ID)).setText(domain); + } + + // Use this if the UI object might or might not need to be scrolled to. + private UiObject2 findOrScrollToObject(BySelector scrollableSelector, BySelector objectSelector) + throws Exception { + UiObject2 object = mDevice.wait(Until.findObject(objectSelector), TIMEOUT); + if (object == null) { + object = scrollToObject(scrollableSelector, objectSelector); + } + return object; + } + + private UiObject2 scrollToObject(BySelector scrollableSelector, BySelector objectSelector) + throws Exception { + UiObject2 scrollable = mDevice.wait(Until.findObject(scrollableSelector), TIMEOUT); + if (scrollable == null) { + fail("Could not find scrollable UI object identified by " + scrollableSelector); + } + UiObject2 found = null; + // Scroll all the way up first, then all the way down. + while (true) { + // Optimization: terminate if we find the object while scrolling up to reset, so + // we save the time spent scrolling down again. + boolean canScrollAgain = scrollable.scroll(Direction.UP, SCROLL_UP_PERCENT, + SCROLL_SPEED); + found = mDevice.findObject(objectSelector); + if (found != null) return found; + if (!canScrollAgain) break; + } + for (int attempts = 0; found == null && attempts < MAX_SCROLL_ATTEMPTS; ++attempts) { + // Return value of UiObject2.scroll() is not reliable, so do not use it in loop + // condition, in case it causes this loop to terminate prematurely. + scrollable.scroll(Direction.DOWN, SCROLL_DOWN_PERCENT, SCROLL_SPEED); + found = mDevice.findObject(objectSelector); + } + if (found == null) { + fail("Could not scroll to UI object identified by " + objectSelector); + } + return found; + } +} diff --git a/tests/uitests/src/com/android/settings/ui/testutils/SettingsTestUtils.java b/tests/uitests/src/com/android/settings/ui/testutils/SettingsTestUtils.java new file mode 100644 index 00000000000..9b1be14bfa5 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/testutils/SettingsTestUtils.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.ui.testutils; + +import static org.junit.Assert.assertNotNull; + +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; + +public class SettingsTestUtils { + + public static final String SETTINGS_PACKAGE = "com.android.settings"; + public static final int TIMEOUT = 2000; + + private void scrollToTop(UiDevice device) throws Exception { + int count = 5; + UiObject2 view = null; + while (count >= 0) { + view = device.wait( + Until.findObject(By.res(SETTINGS_PACKAGE, "main_content")), + TIMEOUT); + view.scroll(Direction.UP, 1.0f); + count--; + } + } + + public static void assertTitleMatch(UiDevice device, String title) { + int maxAttempt = 5; + UiObject2 item = null; + UiObject2 view = null; + while (maxAttempt-- > 0) { + item = device.wait(Until.findObject(By.res("android:id/title").text(title)), TIMEOUT); + if (item == null) { + view = device.wait( + Until.findObject(By.res(SETTINGS_PACKAGE, "main_content")), + TIMEOUT); + view.scroll(Direction.DOWN, 1.0f); + } else { + return; + } + } + assertNotNull(String.format("%s in Setting has not been loaded correctly", title), item); + } +}