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 00000000000..109c3bc45a2 --- /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())); + } +}