blob: 5871c637c1b3f73fca6ab4b7f7d1caabfa541516 [file] [log] [blame]
/*
* Copyright (C) 2020 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 android.app.time.cts;
import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
import static android.app.time.cts.shell.DeviceConfigKeys.NAMESPACE_SYSTEM_TIME;
import static android.app.time.cts.shell.DeviceConfigShellHelper.SYNC_DISABLED_MODE_UNTIL_REBOOT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
import android.app.time.ExternalTimeSuggestion;
import android.app.time.TimeCapabilities;
import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.time.TimeManager;
import android.app.time.TimeState;
import android.app.time.TimeZoneCapabilities;
import android.app.time.TimeZoneCapabilitiesAndConfig;
import android.app.time.TimeZoneConfiguration;
import android.app.time.TimeZoneState;
import android.app.time.UnixEpochTime;
import android.app.time.cts.shell.DeviceConfigKeys;
import android.app.time.cts.shell.DeviceConfigShellHelper;
import android.app.time.cts.shell.DeviceShellCommandExecutor;
import android.app.time.cts.shell.TimeDetectorShellHelper;
import android.app.time.cts.shell.TimeZoneDetectorShellHelper;
import android.app.time.cts.shell.device.InstrumentationShellCommandExecutor;
import android.content.Context;
import android.location.LocationManager;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/** In-process tests for {@link TimeManager} and associated classes. */
public class TimeManagerTest {
/**
* This rule adopts the Shell process permissions, needed because MANAGE_TIME_AND_ZONE_DETECTION
* and SUGGEST_EXTERNAL_TIME required by {@link TimeManager} are privileged permissions.
*/
@Rule
public final AdoptShellPermissionsRule shellPermRule = new AdoptShellPermissionsRule();
private TimeDetectorShellHelper mTimeDetectorShellHelper;
private TimeZoneDetectorShellHelper mTimeZoneDetectorShellHelper;
private DeviceConfigShellHelper mDeviceConfigShellHelper;
private DeviceConfigShellHelper.PreTestState mDeviceConfigPreTestState;
private Context mContext;
private TimeManager mTimeManager;
@Before
public void before() throws Exception {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
DeviceShellCommandExecutor shellCommandExecutor = new InstrumentationShellCommandExecutor(
instrumentation.getUiAutomation());
mTimeDetectorShellHelper = new TimeDetectorShellHelper(shellCommandExecutor);
mTimeZoneDetectorShellHelper = new TimeZoneDetectorShellHelper(shellCommandExecutor);
mDeviceConfigShellHelper = new DeviceConfigShellHelper(shellCommandExecutor);
// This anticipates a future state where a generally applied target preparer may disable
// device_config sync for all CTS tests: only suspend syncing if it isn't already suspended,
// and only resume it if this test suspended it.
mDeviceConfigPreTestState = mDeviceConfigShellHelper.setSyncModeForTest(
SYNC_DISABLED_MODE_UNTIL_REBOOT, NAMESPACE_SYSTEM_TIME);
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mTimeManager = mContext.getSystemService(TimeManager.class);
assertNotNull(mTimeManager);
// Avoid running tests when device policy doesn't allow user configuration. If this needs to
// pass then tests will become more complicated or separate cases broken out.
int configureAutoDetectionEnabledCapability = mTimeManager.getTimeCapabilitiesAndConfig()
.getCapabilities().getConfigureAutoDetectionEnabledCapability();
boolean userRestricted = configureAutoDetectionEnabledCapability == CAPABILITY_NOT_ALLOWED;
assertFalse(userRestricted);
}
@After
public void after() throws Exception {
mDeviceConfigShellHelper.restoreDeviceConfigStateForTest(mDeviceConfigPreTestState);
}
/**
* Registers a {@link TimeManager.TimeZoneDetectorListener}, makes changes
* to the configuration and checks that the listener is called.
*/
@Test
public void testManageTimeZoneConfiguration() throws Exception {
int expectedListenerTriggerCount = 0;
AtomicInteger listenerTriggerCount = new AtomicInteger(0);
TimeManager.TimeZoneDetectorListener listener = listenerTriggerCount::incrementAndGet;
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
mTimeManager.addTimeZoneDetectorListener(executor, listener);
waitForListenerCallbackCount(expectedListenerTriggerCount, listenerTriggerCount);
TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
mTimeManager.getTimeZoneCapabilitiesAndConfig();
waitForListenerCallbackCount(expectedListenerTriggerCount, listenerTriggerCount);
TimeZoneCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
TimeZoneConfiguration originalConfig = capabilitiesAndConfig.getConfiguration();
// Toggle the auto-detection enabled if capabilities allow or try (but expect to fail)
// if not.
{
boolean newAutoDetectionEnabledValue = !originalConfig.isAutoDetectionEnabled();
TimeZoneConfiguration configUpdate = new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(newAutoDetectionEnabledValue)
.build();
if (capabilities.getConfigureAutoDetectionEnabledCapability()
>= CAPABILITY_NOT_APPLICABLE) {
assertTrue(mTimeManager.updateTimeZoneConfiguration(configUpdate));
expectedListenerTriggerCount++;
waitForListenerCallbackCount(
expectedListenerTriggerCount, listenerTriggerCount);
// Reset the config to what it was when the test started.
TimeZoneConfiguration resetConfigUpdate = new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(!newAutoDetectionEnabledValue)
.build();
assertTrue(mTimeManager.updateTimeZoneConfiguration(resetConfigUpdate));
expectedListenerTriggerCount++;
} else {
assertFalse(mTimeManager.updateTimeZoneConfiguration(configUpdate));
}
}
waitForListenerCallbackCount(expectedListenerTriggerCount, listenerTriggerCount);
// Toggle the geo-detection enabled if capabilities allow or try (but expect to fail)
// if not.
{
boolean newGeoDetectionEnabledValue = !originalConfig.isGeoDetectionEnabled();
TimeZoneConfiguration configUpdate = new TimeZoneConfiguration.Builder()
.setGeoDetectionEnabled(newGeoDetectionEnabledValue)
.build();
if (capabilities.getConfigureGeoDetectionEnabledCapability()
>= CAPABILITY_NOT_APPLICABLE) {
assertTrue(mTimeManager.updateTimeZoneConfiguration(configUpdate));
expectedListenerTriggerCount++;
waitForListenerCallbackCount(
expectedListenerTriggerCount, listenerTriggerCount);
// Reset the config to what it was when the test started.
TimeZoneConfiguration resetConfigUpdate = new TimeZoneConfiguration.Builder()
.setGeoDetectionEnabled(!newGeoDetectionEnabledValue)
.build();
assertTrue(mTimeManager.updateTimeZoneConfiguration(resetConfigUpdate));
expectedListenerTriggerCount++;
} else {
assertFalse(mTimeManager.updateTimeZoneConfiguration(configUpdate));
}
}
waitForListenerCallbackCount(expectedListenerTriggerCount, listenerTriggerCount);
} finally {
// Remove the listener. Required otherwise the fuzzy equality rules of lambdas causes
// problems for later tests.
mTimeManager.removeTimeZoneDetectorListener(listener);
executor.shutdown();
}
}
/**
* Makes changes to the time configuration.
*/
@Test
public void testManageTimeConfiguration() throws Exception {
TimeCapabilitiesAndConfig capabilitiesAndConfig =
mTimeManager.getTimeCapabilitiesAndConfig();
TimeCapabilities capabilities = capabilitiesAndConfig.getCapabilities();
TimeConfiguration originalConfig = capabilitiesAndConfig.getConfiguration();
// Toggle the auto-detection enabled if capabilities allow or try (but expect to fail)
// if not.
{
boolean newAutoDetectionEnabledValue = !originalConfig.isAutoDetectionEnabled();
if (capabilities.getConfigureAutoDetectionEnabledCapability()
>= CAPABILITY_NOT_APPLICABLE) {
assertTrue(setAutoTimeDetectionEnabledAndSleep(
newAutoDetectionEnabledValue));
// Reset the config to what it was when the test started.
assertTrue(setAutoTimeDetectionEnabledAndSleep(
!newAutoDetectionEnabledValue));
} else {
assertFalse(setAutoTimeDetectionEnabledAndSleep(
newAutoDetectionEnabledValue));
}
}
}
@Test
public void testExternalTimeSuggestions() throws Exception {
int setManualTimeCapability = mTimeManager.getTimeCapabilitiesAndConfig()
.getCapabilities().getSetManualTimeCapability();
boolean disableAutoDetectionAfterTest = false;
if (setManualTimeCapability == CAPABILITY_POSSESSED) {
// If the user can set the value manually, this means that auto detection is disabled.
// Turn it on for the duration of this test.
disableAutoDetectionAfterTest = true;
assertTrue(setAutoTimeDetectionEnabledAndSleep(true));
}
try {
long startCurrentTimeMillis = System.currentTimeMillis();
long elapsedRealtimeMillis = SystemClock.elapsedRealtime();
// Set the time detector to only use ORIGIN_NETWORK. The important aspect is that it
// isn't ORIGIN_EXTERNAL, and so suggestions from external should be ignored.
mDeviceConfigShellHelper.put(NAMESPACE_SYSTEM_TIME,
DeviceConfigKeys.TimeDetector.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE,
DeviceConfigKeys.TimeDetector.ORIGIN_NETWORK);
sleepForAsyncOperation();
long suggestion1Millis = Instant.ofEpochMilli(startCurrentTimeMillis)
.plus(1, ChronoUnit.DAYS)
.toEpochMilli();
ExternalTimeSuggestion futureTimeSuggestion1 =
createExternalTimeSuggestion(elapsedRealtimeMillis, suggestion1Millis);
long suggestion2Millis =
Instant.ofEpochMilli(suggestion1Millis).plus(1, ChronoUnit.DAYS).toEpochMilli();
ExternalTimeSuggestion futureTimeSuggestion2 =
createExternalTimeSuggestion(elapsedRealtimeMillis, suggestion2Millis);
// Suggest a change. It shouldn't be used.
mTimeManager.suggestExternalTime(futureTimeSuggestion1);
sleepForAsyncOperation();
// The suggestion should have been ignored so the system clock should not have advanced.
assertTrue(System.currentTimeMillis() < suggestion1Millis);
// Set the time detector to only use ORIGIN_EXTERNAL.
// The suggestion should have been stored and should be acted upon when the origin list
// changes.
mDeviceConfigShellHelper.put(NAMESPACE_SYSTEM_TIME,
DeviceConfigKeys.TimeDetector.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE,
DeviceConfigKeys.TimeDetector.ORIGIN_EXTERNAL);
sleepForAsyncOperation();
assertTrue(System.currentTimeMillis() >= suggestion1Millis);
// Suggest a change. It should be used.
mTimeManager.suggestExternalTime(futureTimeSuggestion2);
sleepForAsyncOperation();
assertTrue(System.currentTimeMillis() >= suggestion2Millis);
// Now do our best to return the device to its original state.
ExternalTimeSuggestion originalTimeSuggestion =
createExternalTimeSuggestion(elapsedRealtimeMillis, startCurrentTimeMillis);
mTimeManager.suggestExternalTime(originalTimeSuggestion);
sleepForAsyncOperation();
} finally {
if (disableAutoDetectionAfterTest) {
assertTrue(setAutoTimeDetectionEnabledAndSleep(false));
}
}
}
/**
* Registers a {@link TimeManager.TimeZoneDetectorListener}, makes changes
* to the "location enabled" setting and checks that the listener is called.
*/
@Test
public void testLocationManagerAffectsTimeZoneCapabilities() throws Exception {
AtomicInteger listenerTriggerCount = new AtomicInteger(0);
TimeManager.TimeZoneDetectorListener listener = listenerTriggerCount::incrementAndGet;
LocationManager locationManager = mContext.getSystemService(LocationManager.class);
assertNotNull(locationManager);
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
mTimeManager.addTimeZoneDetectorListener(executor, listener);
// This test does not use waitForListenerCallbackCount() because changing the location
// enabled setting triggers more than one callback when there's a work profile, so it's
// easier just to sleep and confirm >= 1 callbacks have been received.
sleepForAsyncOperation();
int newCallbackCount = listenerTriggerCount.get();
assertEquals(0, newCallbackCount);
int previousCallbackCount = 0;
UserHandle userHandle = Process.myUserHandle();
boolean locationEnabled = locationManager.isLocationEnabledForUser(userHandle);
locationManager.setLocationEnabledForUser(!locationEnabled, userHandle);
sleepForAsyncOperation();
newCallbackCount = listenerTriggerCount.get();
assertTrue(newCallbackCount > previousCallbackCount);
previousCallbackCount = newCallbackCount;
locationManager.setLocationEnabledForUser(locationEnabled, userHandle);
sleepForAsyncOperation();
newCallbackCount = listenerTriggerCount.get();
assertTrue(newCallbackCount > previousCallbackCount);
} finally {
// Remove the listener. Required otherwise the fuzzy equality rules of lambdas causes
// problems for later tests.
mTimeManager.removeTimeZoneDetectorListener(listener);
executor.shutdown();
}
}
@Test
public void testTimeStateAndConfirmation() throws Exception {
int setManualTimeCapability = mTimeManager.getTimeCapabilitiesAndConfig()
.getCapabilities().getSetManualTimeCapability();
boolean disableAutoDetectionAfterTest = false;
if (setManualTimeCapability != CAPABILITY_POSSESSED) {
// If the user cannot set the value manually, this means that auto detection is enabled.
// Turn it off for the duration of this test.
disableAutoDetectionAfterTest = true;
assertTrue(setAutoTimeDetectionEnabledAndSleep(false));
}
// Capture the initial device state.
TimeState initialTimeState = mTimeManager.getTimeState();
try {
// Set the device to have a new time with low confidence.
UnixEpochTime testTime = new UnixEpochTime(SystemClock.elapsedRealtime(),
Instant.now().plusSeconds(12345L).toEpochMilli());
final boolean userShouldConfirm = true;
setTimeStateViaShell(testTime, userShouldConfirm);
// Confirm getTimeState() works as expected.
TimeState actualTimeState = mTimeManager.getTimeState();
UnixEpochTime actualTimeStateTime = actualTimeState.getUnixEpochTime();
assertAlmostSameTime(testTime, actualTimeStateTime);
assertTrue(actualTimeState.getUserShouldConfirmTime());
// Create a time that differs from the one the device thinks it is and attempt to
// confirm it. This should fail to confirm.
UnixEpochTime nonMatchingTime = new UnixEpochTime(
actualTimeStateTime.getElapsedRealtimeMillis(),
actualTimeStateTime.getUnixEpochTimeMillis() + Duration.ofDays(1).toMillis());
assertFalse(mTimeManager.confirmTime(nonMatchingTime));
// Check nothing has changed about the device's time state.
{
TimeState currentTimeState = mTimeManager.getTimeState();
assertAlmostSameTime(actualTimeState.getUnixEpochTime(),
currentTimeState.getUnixEpochTime());
assertTrue(currentTimeState.getUserShouldConfirmTime());
}
// Now confirm the device's current time.
assertTrue(mTimeManager.confirmTime(actualTimeStateTime));
// Check time is the same, but confidence is higher.
{
TimeState currentTimeState = mTimeManager.getTimeState();
assertAlmostSameTime(actualTimeState.getUnixEpochTime(),
currentTimeState.getUnixEpochTime());
assertFalse(currentTimeState.getUserShouldConfirmTime());
}
} finally {
// Return the device to its original state.
setTimeStateViaShell(initialTimeState.getUnixEpochTime(),
initialTimeState.getUserShouldConfirmTime());
if (disableAutoDetectionAfterTest) {
setAutoTimeDetectionEnabledAndSleep(false);
}
}
}
@Test
public void testTimeZoneStateAndConfirmation() throws Exception {
int setManualTimeZoneCapability = mTimeManager.getTimeZoneCapabilitiesAndConfig()
.getCapabilities().getSetManualTimeZoneCapability();
boolean disableAutoDetectionAfterTest = false;
if (setManualTimeZoneCapability != CAPABILITY_POSSESSED) {
// If the user cannot set the value manually, this means that auto detection is enabled.
// Turn it off for the duration of this test.
disableAutoDetectionAfterTest = true;
assumeTrue(setAutoTimeZoneDetectionEnabledAndSleep(false));
}
// Capture the initial device state.
TimeZoneState initialTimeZoneState = mTimeManager.getTimeZoneState();
try {
// Set the device to have a time zone with low confidence.
final String testZoneId = "Europe/London";
final boolean userShouldConfirm = true;
mTimeZoneDetectorShellHelper.setTimeZoneState(testZoneId, userShouldConfirm);
// Confirm getTimeZoneState() works as expected.
TimeZoneState actualTimeZoneState = mTimeManager.getTimeZoneState();
assertEquals(testZoneId, actualTimeZoneState.getId());
assertTrue(actualTimeZoneState.getUserShouldConfirmId());
// Attempt to confirm a time zone that differs from the one the device thinks it is.
// This should fail to confirm.
final String notTestZoneId = "Europe/Paris";
assertFalse(mTimeManager.confirmTimeZone(notTestZoneId));
// Check nothing has changed about the device's time zone state.
{
TimeZoneState currentTimeZoneState = mTimeManager.getTimeZoneState();
assertEquals(actualTimeZoneState.getId(), currentTimeZoneState.getId());
assertTrue(currentTimeZoneState.getUserShouldConfirmId());
}
// Now confirm the device's current time zone.
assertTrue(mTimeManager.confirmTimeZone(testZoneId));
// Check time zone is the same, but confidence is higher.
{
TimeZoneState currentTimeZoneState = mTimeManager.getTimeZoneState();
assertEquals(actualTimeZoneState.getId(), currentTimeZoneState.getId());
assertFalse(currentTimeZoneState.getUserShouldConfirmId());
}
} finally {
// Return the device to its original state.
mTimeZoneDetectorShellHelper.setTimeZoneState(initialTimeZoneState.getId(),
initialTimeZoneState.getUserShouldConfirmId());
if (disableAutoDetectionAfterTest) {
setAutoTimeZoneDetectionEnabledAndSleep(false);
}
}
}
@Test
public void testSetManualTime() throws Exception {
TimeCapabilitiesAndConfig timeCapabilitiesAndConfig =
mTimeManager.getTimeCapabilitiesAndConfig();
TimeCapabilities capabilities = timeCapabilitiesAndConfig.getCapabilities();
TimeState initialTimeState = mTimeManager.getTimeState();
UnixEpochTime initialDeviceTime = initialTimeState.getUnixEpochTime();
UnixEpochTime testTime1 = new UnixEpochTime(
initialDeviceTime.getElapsedRealtimeMillis(),
initialDeviceTime.getUnixEpochTimeMillis() + Duration.ofDays(1).toMillis());
// Try to get the device into a known state: we want auto detection disabled in order to set
// a manual time.
// Various scenarios to consider:
// a) Auto detection is supported, but it's turned off by the user.
// b) Auto detection is not supported so manual entry is the only option.
// The settings value is ignored by the system for (b) so we don't just look at
// settings values from TimeConfiguration.
boolean initialAutoDetectionEnabled;
if (capabilities.getSetManualTimeCapability() == CAPABILITY_POSSESSED) {
// Good to go - device is already in state (a) or (b).
initialAutoDetectionEnabled = false;
} else if (capabilities.getSetManualTimeCapability() == CAPABILITY_NOT_APPLICABLE) {
// We can infer auto detection is enabled, which will prevent us setting time manually.
// Try to turn auto detection off to begin the test.
boolean success = setAutoTimeDetectionEnabledAndSleep(false);
assertTrue("Test requires being able to turn off auto detection", success);
initialAutoDetectionEnabled = true;
} else {
// CAPABILITY_NOT_ALLOWED, CAPABILITY_NOT_SUPPORTED or unknown.
throw new AssertionError("Unexpected capability state for setting manual value: "
+ capabilities.getSetManualTimeCapability());
}
try {
// The device must be in manual mode at this point and there are no user restrictions,
// so setting it manually should succeed.
assertTrue(mTimeManager.setManualTime(testTime1));
UnixEpochTime expectedDeviceTime = testTime1;
// Confirm the time state has updated.
{
TimeState timeState = mTimeManager.getTimeState();
assertAlmostSameTime(expectedDeviceTime, timeState.getUnixEpochTime());
assertFalse(timeState.getUserShouldConfirmTime());
}
// Now turn on automatic detection.
boolean success = setAutoTimeDetectionEnabledAndSleep(true);
assertTrue("Test requires being able to turn on auto detection", success);
// The device time may change as part of turning auto detection back on.
expectedDeviceTime = mTimeManager.getTimeState().getUnixEpochTime();
// Try to set the time again.
UnixEpochTime testTime2 = new UnixEpochTime(
initialDeviceTime.getElapsedRealtimeMillis(),
initialDeviceTime.getUnixEpochTimeMillis() + Duration.ofDays(2).toMillis());
assertFalse(mTimeManager.setManualTime(testTime2));
// Confirm the call failed completely and time state has stayed the same.
{
TimeState actualTimeState = mTimeManager.getTimeState();
assertAlmostSameTime(expectedDeviceTime, actualTimeState.getUnixEpochTime());
assertFalse(actualTimeState.getUserShouldConfirmTime());
}
} finally {
// Try to return the device to its original time and config state.
setTimeStateViaShell(
initialTimeState.getUnixEpochTime(),
initialTimeState.getUserShouldConfirmTime());
setAutoTimeDetectionEnabledAndSleep(initialAutoDetectionEnabled);
}
}
@Test
public void testSetManualTimeZone() throws Exception {
TimeZoneCapabilitiesAndConfig timeZoneCapabilitiesAndConfig =
mTimeManager.getTimeZoneCapabilitiesAndConfig();
TimeZoneCapabilities capabilities = timeZoneCapabilitiesAndConfig.getCapabilities();
TimeZoneState initialTimeZoneState = mTimeManager.getTimeZoneState();
String testTimeZone1 = "Europe/London";
// Try to get the device into a known state: we want auto detection disabled in order to set
// a manual time zone.
// Various scenarios to consider:
// a) Auto detection is supported, but it's turned off by the user.
// b) Auto detection is not supported so manual entry is the only option.
// The settings value is ignored by the system for (b) so we don't just look at
// settings values from TimeZoneConfiguration.
boolean initialAutoDetectionEnabled;
if (capabilities.getSetManualTimeZoneCapability() == CAPABILITY_POSSESSED) {
// Good to go - device is already in state (a) or (b).
initialAutoDetectionEnabled = false;
} else if (capabilities.getSetManualTimeZoneCapability() == CAPABILITY_NOT_APPLICABLE) {
// We can infer auto detection is enabled, which will prevent us setting time zone
// manually.
// Try to turn auto detection off to begin the test.
boolean success = setAutoTimeZoneDetectionEnabledAndSleep(false);
assertTrue("Test requires being able to turn off auto detection", success);
initialAutoDetectionEnabled = true;
} else {
// CAPABILITY_NOT_ALLOWED, CAPABILITY_NOT_SUPPORTED or unknown.
throw new AssertionError("Unexpected capability state for setting manual value: "
+ capabilities.getSetManualTimeZoneCapability());
}
try {
// The device must be in manual mode at this point and there are no user restrictions,
// so setting it manually should succeed.
assertTrue(mTimeManager.setManualTimeZone(testTimeZone1));
// Confirm the time zone state has updated.
{
TimeZoneState timeZoneState = mTimeManager.getTimeZoneState();
assertEquals(testTimeZone1, timeZoneState.getId());
assertFalse(timeZoneState.getUserShouldConfirmId());
}
// This part of the test is optional: What happens to setManualTimeZone() when automatic
// detection is ON can only be tested if the device supports automatic time zone
// detection.
if (capabilities.getConfigureAutoDetectionEnabledCapability() == CAPABILITY_POSSESSED) {
// Turn on automatic detection.
boolean success = setAutoTimeZoneDetectionEnabledAndSleep(true);
assertTrue("Test requires being able to turn on auto detection", success);
// Try to set the time zone again.
String testTimeZone2 = "Europe/Paris";
assertFalse(mTimeManager.setManualTimeZone(testTimeZone2));
// Confirm the call failed completely and time zone state has stayed the same.
{
TimeZoneState timeZoneState = mTimeManager.getTimeZoneState();
assertEquals(testTimeZone1, timeZoneState.getId());
assertFalse(timeZoneState.getUserShouldConfirmId());
}
}
} finally {
// Try to return the device to its original time and config state.
mTimeZoneDetectorShellHelper.setTimeZoneState(
initialTimeZoneState.getId(),
initialTimeZoneState.getUserShouldConfirmId());
setAutoTimeZoneDetectionEnabledAndSleep(initialAutoDetectionEnabled);
}
}
private boolean setAutoTimeDetectionEnabledAndSleep(boolean enabled) throws Exception {
boolean success = mTimeManager.updateTimeConfiguration(
new TimeConfiguration.Builder().setAutoDetectionEnabled(enabled).build());
// Configuration changes are recorded synchronously, but can be handled asynchronously so
// sleep. Otherwise, the strategy may not yet understand the config has changed.
sleepForAsyncOperation();
return success;
}
private boolean setAutoTimeZoneDetectionEnabledAndSleep(boolean enabled) throws Exception {
boolean success = mTimeManager.updateTimeZoneConfiguration(
new TimeZoneConfiguration.Builder().setAutoDetectionEnabled(enabled).build());
// Configuration changes are recorded synchronously, but can be handled asynchronously so
// sleep. Otherwise, the strategy may not yet understand the config has changed.
sleepForAsyncOperation();
return success;
}
private void setTimeStateViaShell(UnixEpochTime testTime, boolean userShouldConfirm)
throws Exception {
mTimeDetectorShellHelper.setTimeState(
testTime.getElapsedRealtimeMillis(), testTime.getUnixEpochTimeMillis(),
userShouldConfirm);
}
/** Asserts that the two times represent the same time when adjusting for elapsed realtime. */
private static void assertAlmostSameTime(UnixEpochTime one, UnixEpochTime two) {
UnixEpochTime oneAdjusted = one.at(two.getElapsedRealtimeMillis());
long absUnixEpochMillisDifference =
Math.abs(oneAdjusted.getUnixEpochTimeMillis() - two.getUnixEpochTimeMillis());
assertTrue("one=" + one + ", two=" + two
+ ", oneAdjusted=" + oneAdjusted
+ ", absUnixEpochMillisDifference=" + absUnixEpochMillisDifference,
absUnixEpochMillisDifference < 200);
}
private static void waitForListenerCallbackCount(
int expectedValue, AtomicInteger actualValue) throws Exception {
// Busy waits up to 30 seconds for the count to reach the expected value.
final long busyWaitMillis = 30000;
long targetTimeMillis = System.currentTimeMillis() + busyWaitMillis;
while (expectedValue != actualValue.get()
&& System.currentTimeMillis() < targetTimeMillis) {
Thread.sleep(250);
}
assertEquals(expectedValue, actualValue.get());
}
/**
* Sleeps for a length of time sufficient to allow async operations to complete. Many time
* manager APIs are or could be asynchronous and deal with time, so there are no practical
* alternatives.
*/
private static void sleepForAsyncOperation() throws Exception{
Thread.sleep(5_000);
}
private static ExternalTimeSuggestion createExternalTimeSuggestion(
long elapsedRealtimeMillis, long unixEpochTimeMillis) {
ExternalTimeSuggestion externalTimeSuggestion =
new ExternalTimeSuggestion(elapsedRealtimeMillis, unixEpochTimeMillis);
externalTimeSuggestion.addDebugInfo("cts.TimeManagerTest");
return externalTimeSuggestion;
}
}