Add UI tests for new time zone picker
- Test selecting 2 time zones in picker
- Device.wait could return null object and cause NPE.
Add helper function throw UiObjectNotFoundException with selector info
Bug: 62255208
Test: atest SettingsUITests:ZonePickerSettingsTest
Change-Id: Id0439dde25240cf2d3ee834043d1726a2c738d1a
diff --git a/tests/uitests/src/com/android/settings/ui/ZonePickerSettingsTest.java b/tests/uitests/src/com/android/settings/ui/ZonePickerSettingsTest.java
new file mode 100644
index 0000000..109c3bc
--- /dev/null
+++ b/tests/uitests/src/com/android/settings/ui/ZonePickerSettingsTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.os.SystemProperties;
+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.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+import android.system.helpers.SettingsHelper;
+import android.system.helpers.SettingsHelper.SettingsType;
+import android.widget.ListView;
+import android.widget.Spinner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.TimeZone;
+
+import static com.android.settings.ui.testutils.SettingsTestUtils.SETTINGS_PACKAGE;
+import static com.android.settings.ui.testutils.SettingsTestUtils.TIMEOUT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ZonePickerSettingsTest {
+
+ private static final BySelector SELECTOR_SELECT_TIME_ZONE =
+ By.hasChild(By.text("Select time zone"));
+
+ private UiDevice mDevice;
+ private SettingsHelper mHelper;
+ private String mIsV2EnabledByDefault;
+ private int mIsAutoZoneEnabled;
+
+ @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 orientation", e);
+ }
+ mIsV2EnabledByDefault = mHelper.getStringSetting(SettingsType.GLOBAL,
+ "settings_zone_picker_v2");
+ mHelper.setStringSetting(SettingsType.GLOBAL, "settings_zone_picker_v2", "true");
+ mIsAutoZoneEnabled = mHelper.getIntSetting(SettingsType.GLOBAL,
+ Settings.Global.AUTO_TIME_ZONE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Go back to home for next test.
+ mDevice.pressBack();
+ mDevice.pressBack();
+ mDevice.pressHome();
+ mDevice.waitForIdle(TIMEOUT * 2);
+ mHelper.setStringSetting(SettingsType.GLOBAL, "settings_zone_picker_v2",
+ mIsV2EnabledByDefault);
+ mHelper.setIntSetting(SettingsType.GLOBAL, Settings.Global.AUTO_TIME_ZONE,
+ mIsAutoZoneEnabled);
+ }
+
+ @Test
+ public void zonePickerDisabled() throws Exception {
+ mHelper.setIntSetting(SettingsType.GLOBAL, Settings.Global.AUTO_TIME_ZONE, 1);
+
+ SettingsHelper.launchSettingsPage(
+ InstrumentationRegistry.getContext(), Settings.ACTION_DATE_SETTINGS);
+ UiObject2 selectTimeZone = wait(SELECTOR_SELECT_TIME_ZONE);
+ assertFalse(selectTimeZone.isEnabled());
+ }
+
+ // Test 2 time zones with no DST
+ @Test
+ public void testSelectReykjavik() throws Exception {
+ testSelectTimeZone("Iceland", "Reykjavik", "GMT+00:00", "Atlantic/Reykjavik");
+ }
+
+ @Test
+ public void testSelectPhoenix() throws Exception {
+ testSelectTimeZone("United States", "Phoenix", "GMT-07:00", "America/Phoenix");
+ }
+
+ private void testSelectTimeZone(String region, String timezone, String expectedTimeZoneOffset,
+ String expectedTimeZoneId) throws Exception {
+ mHelper.setIntSetting(SettingsType.GLOBAL, Settings.Global.AUTO_TIME_ZONE, 0);
+
+ SettingsHelper.launchSettingsPage(
+ InstrumentationRegistry.getContext(), Settings.ACTION_DATE_SETTINGS);
+
+ UiObject2 selectTimeZone = wait(SELECTOR_SELECT_TIME_ZONE);
+ assertTrue(selectTimeZone.isEnabled());
+ selectTimeZone.click();
+
+ // Select region in the dropdown list
+ selectScrollableItem(selectDropDownInSpinner(By.clazz(Spinner.class)),
+ new UiSelector().textContains(region))
+ .click();
+
+ // Select time zone
+ selectScrollableItem(selectTimeZoneList(),
+ new UiSelector().textContains(timezone))
+ .click();
+
+ // The select button should include the GMT offset in the summary
+ BySelector summarySelector = By.res("android:id/summary");
+ UiObject2 selectedTimeZone = selectTimeZone.findObject(summarySelector);
+ assertUiObjectFound(selectedTimeZone, summarySelector);
+ assertTrue("Expect " + expectedTimeZoneOffset + " is shown for " + timezone,
+ selectedTimeZone.getText().startsWith(expectedTimeZoneOffset));
+
+ waitAndAssertTimeGetDefault(expectedTimeZoneId);
+ assertEquals("Time zone change in Settings should update persist.sys.timezone",
+ expectedTimeZoneId, SystemProperties.get("persist.sys.timezone"));
+ }
+
+ private static final long CHECK_DEFAULT_TIMEZONE_INTERVAL = 200L;
+ private static final long CHECK_DEFAULT_TIMEZONE_TIMEOUT = 3000L;
+
+ /**
+ * Wait for the broadcast ACTION_TIMEZONE_CHANGED propagated, and update the default TimeZone
+ * by ApplicationThread.
+ */
+ private static void waitAndAssertTimeGetDefault(String expectedTimeZoneId)
+ throws InterruptedException {
+ for (int i = 0; i < CHECK_DEFAULT_TIMEZONE_TIMEOUT / CHECK_DEFAULT_TIMEZONE_INTERVAL; i++) {
+ if (expectedTimeZoneId.equals(TimeZone.getDefault().getID())) {
+ return;
+ }
+ Thread.sleep(CHECK_DEFAULT_TIMEZONE_INTERVAL);
+ }
+
+ assertEquals(expectedTimeZoneId, TimeZone.getDefault().getID());
+ }
+
+ /**
+ * Perform click on {@link Spinner} and return the pop-up dropdown list.
+ * @return UiScrollable representing the pop-up dropdown after clicking on the spinner
+ */
+ private UiScrollable selectDropDownInSpinner(BySelector spinnerSelector)
+ throws UiObjectNotFoundException {
+ UiObject2 spinner = wait(spinnerSelector);
+ spinner.click();
+
+ UiSelector dropDownSelector = new UiSelector().className(ListView.class);
+ return new UiScrollable(dropDownSelector);
+ }
+
+ private UiScrollable selectTimeZoneList() {
+ return new UiScrollable(new UiSelector().resourceId(SETTINGS_PACKAGE + ":id/tz_list"));
+ }
+
+ /**
+ * Select the child object in the UiScrollable
+ * @throws UiObjectNotFoundException if scrollable or child is not found
+ */
+ private UiObject selectScrollableItem(UiScrollable scrollable, UiSelector childSelector)
+ throws UiObjectNotFoundException {
+ if (!scrollable.waitForExists(TIMEOUT)) {
+ throw newUiObjectNotFoundException(scrollable.getSelector());
+ }
+ scrollable.scrollIntoView(childSelector);
+
+ UiObject child = mDevice.findObject(childSelector);
+ assertUiObjectFound(child, childSelector);
+ return child;
+ }
+
+ /**
+ * @throws UiObjectNotFoundException if UiDevice.wait returns null
+ */
+ private UiObject2 wait(BySelector selector) throws UiObjectNotFoundException {
+ UiObject2 item = mDevice.wait(Until.findObject(selector), TIMEOUT);
+ assertUiObjectFound(item, selector);
+ return item;
+ }
+
+ private static void assertUiObjectFound(UiObject2 obj, BySelector selector)
+ throws UiObjectNotFoundException {
+ if (obj == null) {
+ throw newUiObjectNotFoundException(selector);
+ }
+ }
+
+
+ private static void assertUiObjectFound(UiObject obj, UiSelector selector)
+ throws UiObjectNotFoundException {
+ if (obj == null) {
+ throw newUiObjectNotFoundException(selector);
+ }
+ }
+
+ private static UiObjectNotFoundException newUiObjectNotFoundException(Object selector) {
+ return new UiObjectNotFoundException(
+ String.format("UI object not found: %s", selector.toString()));
+ }
+}