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