1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.settings.ui; 17 18 import android.os.RemoteException; 19 import android.os.SystemProperties; 20 import android.provider.Settings; 21 import android.support.test.InstrumentationRegistry; 22 import android.support.test.filters.MediumTest; 23 import android.support.test.runner.AndroidJUnit4; 24 import android.support.test.uiautomator.By; 25 import android.support.test.uiautomator.BySelector; 26 import android.support.test.uiautomator.UiDevice; 27 import android.support.test.uiautomator.UiObject; 28 import android.support.test.uiautomator.UiObject2; 29 import android.support.test.uiautomator.UiObjectNotFoundException; 30 import android.support.test.uiautomator.UiScrollable; 31 import android.support.test.uiautomator.UiSelector; 32 import android.support.test.uiautomator.Until; 33 import android.system.helpers.SettingsHelper; 34 import android.system.helpers.SettingsHelper.SettingsType; 35 36 import org.junit.After; 37 import org.junit.Before; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 import java.util.TimeZone; 42 43 import static com.android.settings.ui.testutils.SettingsTestUtils.SETTINGS_PACKAGE; 44 import static com.android.settings.ui.testutils.SettingsTestUtils.TIMEOUT; 45 import static org.junit.Assert.assertEquals; 46 import static org.junit.Assert.assertFalse; 47 import static org.junit.Assert.assertTrue; 48 49 @MediumTest 50 @RunWith(AndroidJUnit4.class) 51 public class ZonePickerSettingsTest { 52 53 private static final BySelector SELECTOR_SELECT_TIME_ZONE = 54 By.hasChild(By.text("Select time zone")); 55 56 private UiDevice mDevice; 57 private SettingsHelper mHelper; 58 private String mIsV2EnabledByDefault; 59 private int mIsAutoZoneEnabled; 60 61 @Before setUp()62 public void setUp() throws Exception { 63 mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 64 mHelper = SettingsHelper.getInstance(); 65 try { 66 mDevice.setOrientationNatural(); 67 } catch (RemoteException e) { 68 throw new RuntimeException("failed to freeze device orientation", e); 69 } 70 mIsV2EnabledByDefault = mHelper.getStringSetting(SettingsType.GLOBAL, 71 "settings_zone_picker_v2"); 72 mHelper.setStringSetting(SettingsType.GLOBAL, "settings_zone_picker_v2", "true"); 73 mIsAutoZoneEnabled = mHelper.getIntSetting(SettingsType.GLOBAL, 74 Settings.Global.AUTO_TIME_ZONE); 75 } 76 77 @After tearDown()78 public void tearDown() throws Exception { 79 // Go back to home for next test. 80 mDevice.pressBack(); 81 mDevice.pressBack(); 82 mDevice.pressHome(); 83 mDevice.waitForIdle(TIMEOUT * 2); 84 mHelper.setStringSetting(SettingsType.GLOBAL, "settings_zone_picker_v2", 85 mIsV2EnabledByDefault); 86 mHelper.setIntSetting(SettingsType.GLOBAL, Settings.Global.AUTO_TIME_ZONE, 87 mIsAutoZoneEnabled); 88 } 89 90 @Test zonePickerDisabled()91 public void zonePickerDisabled() throws Exception { 92 mHelper.setIntSetting(SettingsType.GLOBAL, Settings.Global.AUTO_TIME_ZONE, 1); 93 94 SettingsHelper.launchSettingsPage( 95 InstrumentationRegistry.getContext(), Settings.ACTION_DATE_SETTINGS); 96 UiObject2 selectTimeZone = wait(SELECTOR_SELECT_TIME_ZONE); 97 assertFalse(selectTimeZone.isEnabled()); 98 } 99 100 // Test 2 time zones with no DST 101 @Test testSelectReykjavik()102 public void testSelectReykjavik() throws Exception { 103 testSelectTimeZone("Iceland", "Reykjavik", "GMT+00:00", "Atlantic/Reykjavik", true); 104 } 105 106 @Test testSelectPhoenix()107 public void testSelectPhoenix() throws Exception { 108 testSelectTimeZone("United States", "Phoenix", "GMT-07:00", "America/Phoenix", false); 109 } 110 testSelectTimeZone(String region, String timezone, String expectedTimeZoneOffset, String expectedTimeZoneId, boolean assumeOneTimeZoneInRegion)111 private void testSelectTimeZone(String region, String timezone, String expectedTimeZoneOffset, 112 String expectedTimeZoneId, boolean assumeOneTimeZoneInRegion) throws Exception { 113 mHelper.setIntSetting(SettingsType.GLOBAL, Settings.Global.AUTO_TIME_ZONE, 0); 114 115 SettingsHelper.launchSettingsPage( 116 InstrumentationRegistry.getContext(), Settings.ACTION_DATE_SETTINGS); 117 118 UiObject2 selectTimeZone = wait(SELECTOR_SELECT_TIME_ZONE); 119 assertTrue(selectTimeZone.isEnabled()); 120 selectTimeZone.click(); 121 122 wait(By.text("Region")).click(); 123 // Speed-up the test by searching with the first 2 characters of the region name 124 wait(By.res("android", "search_src_text")).setText(region.substring(0, 2)); 125 // Select region in the list 126 selectItemInList(new UiSelector().textContains(region)) 127 .click(); 128 129 // Only select time zone explicitly if there are more than one time zones in a region 130 if (!assumeOneTimeZoneInRegion) { 131 wait(By.text("Time zone")); 132 selectItemInList(new UiSelector().textContains(timezone)) 133 .click(); 134 } 135 136 mDevice.pressBack(); 137 // The select button should include the GMT offset in the summary 138 BySelector summarySelector = By.res("android:id/summary"); 139 UiObject2 selectedTimeZone = selectTimeZone.findObject(summarySelector); 140 assertUiObjectFound(selectedTimeZone, summarySelector); 141 assertTrue("Expect " + expectedTimeZoneOffset + " is shown for " + timezone, 142 selectedTimeZone.getText().startsWith(expectedTimeZoneOffset)); 143 144 waitAndAssertTimeGetDefault(expectedTimeZoneId); 145 assertEquals("Time zone change in Settings should update persist.sys.timezone", 146 expectedTimeZoneId, SystemProperties.get("persist.sys.timezone")); 147 } 148 149 private static final long CHECK_DEFAULT_TIMEZONE_INTERVAL = 200L; 150 private static final long CHECK_DEFAULT_TIMEZONE_TIMEOUT = 3000L; 151 152 /** 153 * Wait for the broadcast ACTION_TIMEZONE_CHANGED propagated, and update the default TimeZone 154 * by ApplicationThread. 155 */ waitAndAssertTimeGetDefault(String expectedTimeZoneId)156 private static void waitAndAssertTimeGetDefault(String expectedTimeZoneId) 157 throws InterruptedException { 158 for (int i = 0; i < CHECK_DEFAULT_TIMEZONE_TIMEOUT / CHECK_DEFAULT_TIMEZONE_INTERVAL; i++) { 159 if (expectedTimeZoneId.equals(TimeZone.getDefault().getID())) { 160 return; 161 } 162 Thread.sleep(CHECK_DEFAULT_TIMEZONE_INTERVAL); 163 } 164 165 assertEquals(expectedTimeZoneId, TimeZone.getDefault().getID()); 166 } 167 selectItemInList(UiSelector childSelector)168 private UiObject selectItemInList(UiSelector childSelector) throws UiObjectNotFoundException { 169 UiScrollable recyclerView = new UiScrollable( 170 new UiSelector().resourceId(SETTINGS_PACKAGE + ":id/recycler_view")); 171 return selectScrollableItem(recyclerView, childSelector); 172 } 173 174 /** 175 * Select the child object in the UiScrollable 176 * @throws UiObjectNotFoundException if scrollable or child is not found 177 */ selectScrollableItem(UiScrollable scrollable, UiSelector childSelector)178 private UiObject selectScrollableItem(UiScrollable scrollable, UiSelector childSelector) 179 throws UiObjectNotFoundException { 180 if (!scrollable.waitForExists(TIMEOUT)) { 181 throw newUiObjectNotFoundException(scrollable.getSelector()); 182 } 183 scrollable.scrollIntoView(childSelector); 184 185 UiObject child = mDevice.findObject(childSelector); 186 assertUiObjectFound(child, childSelector); 187 return child; 188 } 189 190 /** 191 * @throws UiObjectNotFoundException if UiDevice.wait returns null 192 */ wait(BySelector selector)193 private UiObject2 wait(BySelector selector) throws UiObjectNotFoundException { 194 UiObject2 item = mDevice.wait(Until.findObject(selector), TIMEOUT); 195 assertUiObjectFound(item, selector); 196 return item; 197 } 198 assertUiObjectFound(UiObject2 obj, BySelector selector)199 private static void assertUiObjectFound(UiObject2 obj, BySelector selector) 200 throws UiObjectNotFoundException { 201 if (obj == null) { 202 throw newUiObjectNotFoundException(selector); 203 } 204 } 205 206 assertUiObjectFound(UiObject obj, UiSelector selector)207 private static void assertUiObjectFound(UiObject obj, UiSelector selector) 208 throws UiObjectNotFoundException { 209 if (obj == null) { 210 throw newUiObjectNotFoundException(selector); 211 } 212 } 213 newUiObjectNotFoundException(Object selector)214 private static UiObjectNotFoundException newUiObjectNotFoundException(Object selector) { 215 return new UiObjectNotFoundException( 216 String.format("UI object not found: %s", selector.toString())); 217 } 218 } 219