blob: 4cb7ad97baa043b7d228385fff09b4e915d3575b [file] [log] [blame]
/*
* 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 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;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.provider.Settings;
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 androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.TimeZone;
@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", true);
}
@Test
public void testSelectPhoenix() throws Exception {
testSelectTimeZone("United States", "Phoenix", "GMT-07:00", "America/Phoenix", false);
}
private void testSelectTimeZone(String region, String timezone, String expectedTimeZoneOffset,
String expectedTimeZoneId, boolean assumeOneTimeZoneInRegion) 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();
wait(By.text("Region")).click();
// Speed-up the test by searching with the first 2 characters of the region name
wait(By.res("android", "search_src_text")).setText(region.substring(0, 2));
// Select region in the list
selectItemInList(new UiSelector().textContains(region))
.click();
// Only select time zone explicitly if there are more than one time zones in a region
if (!assumeOneTimeZoneInRegion) {
wait(By.text("Time zone"));
selectItemInList(new UiSelector().textContains(timezone))
.click();
}
mDevice.pressBack();
// 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());
}
private UiObject selectItemInList(UiSelector childSelector) throws UiObjectNotFoundException {
UiScrollable recyclerView = new UiScrollable(
new UiSelector().resourceId(SETTINGS_PACKAGE + ":id/recycler_view"));
return selectScrollableItem(recyclerView, childSelector);
}
/**
* 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()));
}
}