Add the secondary provider hand-over logic

This commit adds the support for a secondary provider in ControllerImpl
and the logic for enabling / disabling providers as events are received.

This commit modifies / adds unit tests in ControllerImplTest to exercise
the new behavior.

Bug: 152744911
Bug: 149014708
Test: atest services/tests/servicestests/src/com/android/server/location/timezone/
Change-Id: I722baa3b4146a40e7912d73e7d91b5f907677911
This commit is contained in:
Neil Fuller
2020-09-23 14:55:59 +01:00
parent 6ae65b9022
commit 627035a7d0
4 changed files with 579 additions and 64 deletions

View File

@@ -44,16 +44,22 @@ import java.util.List;
import java.util.Objects;
/**
* A real implementation of {@link LocationTimeZoneProviderController} that supports a single
* {@link LocationTimeZoneProvider}.
* A real implementation of {@link LocationTimeZoneProviderController} that supports a primary and a
* secondary {@link LocationTimeZoneProvider}.
*
* TODO(b/152744911): This implementation currently only supports a single ("primary") provider.
* Support for a secondary provider will be added in a later commit.
* <p>The primary is used until it fails or becomes uncertain. The secondary will then be enabled.
* The controller will immediately make suggestions based on "certain" {@link
* LocationTimeZoneEvent}s, i.e. events that demonstrate the provider is certain what the time zone
* is. The controller will not make immediate suggestions based on "uncertain" events, giving
* providers time to change their mind. This also gives the secondary provider time to initialize
* when the primary becomes uncertain.
*/
class ControllerImpl extends LocationTimeZoneProviderController {
@NonNull private final LocationTimeZoneProvider mPrimaryProvider;
@NonNull private final LocationTimeZoneProvider mSecondaryProvider;
@GuardedBy("mSharedLock")
// Non-null after initialize()
private ConfigurationInternal mCurrentUserConfiguration;
@@ -67,7 +73,9 @@ class ControllerImpl extends LocationTimeZoneProviderController {
private Callback mCallback;
/**
* Used for scheduling uncertainty timeouts, i.e after the provider has reported uncertainty.
* Used for scheduling uncertainty timeouts, i.e after a provider has reported uncertainty.
* This timeout is not provider-specific: it is started when the controller becomes uncertain
* due to events it has received from one or other provider.
*/
@NonNull private final SingleRunnableQueue mUncertaintyTimeoutQueue;
@@ -77,10 +85,12 @@ class ControllerImpl extends LocationTimeZoneProviderController {
private GeolocationTimeZoneSuggestion mLastSuggestion;
ControllerImpl(@NonNull ThreadingDomain threadingDomain,
@NonNull LocationTimeZoneProvider primaryProvider) {
@NonNull LocationTimeZoneProvider primaryProvider,
@NonNull LocationTimeZoneProvider secondaryProvider) {
super(threadingDomain);
mUncertaintyTimeoutQueue = threadingDomain.createSingleRunnableQueue();
mPrimaryProvider = Objects.requireNonNull(primaryProvider);
mSecondaryProvider = Objects.requireNonNull(secondaryProvider);
}
@Override
@@ -96,8 +106,9 @@ class ControllerImpl extends LocationTimeZoneProviderController {
LocationTimeZoneProvider.ProviderListener providerListener =
ControllerImpl.this::onProviderStateChange;
mPrimaryProvider.initialize(providerListener);
mSecondaryProvider.initialize(providerListener);
alterProviderEnabledStateIfRequired(
alterProvidersEnabledStateIfRequired(
null /* oldConfiguration */, mCurrentUserConfiguration);
}
}
@@ -115,15 +126,15 @@ class ControllerImpl extends LocationTimeZoneProviderController {
if (!newConfig.equals(oldConfig)) {
if (newConfig.getUserId() != oldConfig.getUserId()) {
// If the user changed, disable the provider if needed. It may be re-enabled for
// the new user below if their settings allow.
// If the user changed, disable the providers if needed. They may be re-enabled
// for the new user immediately afterwards if their settings allow.
debugLog("User changed. old=" + oldConfig.getUserId()
+ ", new=" + newConfig.getUserId() + ": Disabling provider");
disableProvider();
+ ", new=" + newConfig.getUserId() + ": Disabling providers");
disableProviders();
alterProviderEnabledStateIfRequired(null /* oldConfiguration */, newConfig);
alterProvidersEnabledStateIfRequired(null /* oldConfiguration */, newConfig);
} else {
alterProviderEnabledStateIfRequired(oldConfig, newConfig);
alterProvidersEnabledStateIfRequired(oldConfig, newConfig);
}
}
}
@@ -140,10 +151,11 @@ class ControllerImpl extends LocationTimeZoneProviderController {
}
@GuardedBy("mSharedLock")
private void disableProvider() {
private void disableProviders() {
disableProviderIfEnabled(mPrimaryProvider);
disableProviderIfEnabled(mSecondaryProvider);
// By definition, if the provider is disabled, the controller is uncertain.
// By definition, if both providers are disabled, the controller is uncertain.
cancelUncertaintyTimeout();
}
@@ -181,7 +193,7 @@ class ControllerImpl extends LocationTimeZoneProviderController {
}
/**
* Sets the provider into the correct enabled/disabled state for the {@code newConfiguration}
* Sets the providers into the correct enabled/disabled state for the {@code newConfiguration}
* and, if there is a provider state change, makes any suggestions required to inform the
* downstream time zone detection code.
*
@@ -190,7 +202,7 @@ class ControllerImpl extends LocationTimeZoneProviderController {
* or when a new configuration has been received.
*/
@GuardedBy("mSharedLock")
private void alterProviderEnabledStateIfRequired(
private void alterProvidersEnabledStateIfRequired(
@Nullable ConfigurationInternal oldConfiguration,
@NonNull ConfigurationInternal newConfiguration) {
@@ -203,21 +215,40 @@ class ControllerImpl extends LocationTimeZoneProviderController {
return;
}
// The check above ensures that the logic below only executes if providers are going from
// {enabled *} -> {disabled}, or {disabled} -> {enabled initializing}. If this changes in
// future and there could be {enabled *} -> {enabled *} cases, or cases where the provider
// can't be assumed to go straight to the {enabled initializing} state, then the logic below
// would need to cover extra conditions, for example:
// 1) If the primary is in {enabled uncertain}, the secondary should be enabled.
// 2) If (1), and the secondary instantly enters the {perm failed} state, the uncertainty
// timeout started when the primary entered {enabled uncertain} should be cancelled.
if (newGeoDetectionEnabled) {
// Try to enable the primary provider.
tryEnableProvider(mPrimaryProvider, newConfiguration);
// The secondary should only ever be enabled if the primary now isn't enabled (i.e. it
// couldn't become {enabled initializing} because it is {perm failed}).
ProviderState newPrimaryState = mPrimaryProvider.getCurrentState();
if (!newPrimaryState.isEnabled()) {
// If the provider is perm failed then the controller is immediately considered
// uncertain.
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
"Provider is failed:"
+ " primary=" + mPrimaryProvider.getCurrentState());
makeSuggestion(suggestion);
// If the primary provider is {perm failed} then the controller must try to enable
// the secondary.
tryEnableProvider(mSecondaryProvider, newConfiguration);
ProviderState newSecondaryState = mSecondaryProvider.getCurrentState();
if (!newSecondaryState.isEnabled()) {
// If both providers are {perm failed} then the controller immediately
// becomes uncertain.
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
"Providers are failed:"
+ " primary=" + mPrimaryProvider.getCurrentState()
+ " secondary=" + mPrimaryProvider.getCurrentState());
makeSuggestion(suggestion);
}
}
} else {
disableProvider();
disableProviders();
// There can be an uncertainty timeout set if the controller most recently received
// an uncertain event. This is a no-op if there isn't a timeout set.
@@ -300,35 +331,63 @@ class ControllerImpl extends LocationTimeZoneProviderController {
}
private void assertProviderKnown(@NonNull LocationTimeZoneProvider provider) {
if (provider != mPrimaryProvider) {
if (provider != mPrimaryProvider && provider != mSecondaryProvider) {
throw new IllegalArgumentException("Unknown provider: " + provider);
}
}
/**
* Called when the provider has reported that it has failed permanently.
* Called when a provider has reported that it has failed permanently.
*/
@GuardedBy("mSharedLock")
private void handleProviderFailedStateChange(@NonNull ProviderState providerState) {
LocationTimeZoneProvider failedProvider = providerState.provider;
ProviderState primaryCurrentState = mPrimaryProvider.getCurrentState();
ProviderState secondaryCurrentState = mSecondaryProvider.getCurrentState();
// If the provider is newly perm failed then the controller is uncertain by
// definition.
cancelUncertaintyTimeout();
// If a provider has failed, the other may need to be enabled.
if (failedProvider == mPrimaryProvider) {
if (secondaryCurrentState.stateEnum != PROVIDER_STATE_PERM_FAILED) {
// The primary must have failed. Try to enable the secondary. This does nothing if
// the provider is already enabled, and will leave the provider in
// {enabled initializing} if the provider is disabled.
tryEnableProvider(mSecondaryProvider, mCurrentUserConfiguration);
}
} else if (failedProvider == mSecondaryProvider) {
// No-op: The secondary will only be active if the primary is uncertain or is failed.
// So, there the primary should not need to be enabled when the secondary fails.
if (primaryCurrentState.stateEnum != PROVIDER_STATE_ENABLED_UNCERTAIN
&& primaryCurrentState.stateEnum != PROVIDER_STATE_PERM_FAILED) {
warnLog("Secondary provider unexpected reported a failure:"
+ " failed provider=" + failedProvider.getName()
+ ", primary provider=" + mPrimaryProvider
+ ", secondary provider=" + mSecondaryProvider);
}
}
// If the provider is now failed, then we must send a suggestion informing the time
// zone detector that there are no further updates coming in future.
// If both providers are now failed, the controller needs to tell the next component in the
// time zone detection process.
if (primaryCurrentState.stateEnum == PROVIDER_STATE_PERM_FAILED
&& secondaryCurrentState.stateEnum == PROVIDER_STATE_PERM_FAILED) {
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
"The provider is permanently failed:"
+ " provider=" + failedProvider);
makeSuggestion(suggestion);
// If both providers are newly failed then the controller is uncertain by definition
// and it will never recover so it can send a suggestion immediately.
cancelUncertaintyTimeout();
// If both providers are now failed, then a suggestion must be sent informing the time
// zone detector that there are no further updates coming in future.
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
"Both providers are permanently failed:"
+ " primary=" + primaryCurrentState.provider
+ ", secondary=" + secondaryCurrentState.provider);
makeSuggestion(suggestion);
}
}
/**
* Called when a provider has changed state but just moved from one enabled state to another
* enabled state, usually as a result of a new {@link LocationTimeZoneEvent} being received.
* However, there are rare cases where the event can be null.
* However, there are rare cases where the event can also be null.
*/
@GuardedBy("mSharedLock")
private void handleProviderEnabledStateChange(@NonNull ProviderState providerState) {
@@ -395,6 +454,10 @@ class ControllerImpl extends LocationTimeZoneProviderController {
// By definition, the controller is now certain.
cancelUncertaintyTimeout();
if (provider == mPrimaryProvider) {
disableProviderIfEnabled(mSecondaryProvider);
}
GeolocationTimeZoneSuggestion suggestion =
new GeolocationTimeZoneSuggestion(timeZoneIds);
suggestion.addDebugInfo(reason);
@@ -421,6 +484,11 @@ class ControllerImpl extends LocationTimeZoneProviderController {
mPrimaryProvider.dump(ipw, args);
ipw.decreaseIndent(); // level 2
ipw.println("Secondary Provider:");
ipw.increaseIndent(); // level 2
mSecondaryProvider.dump(ipw, args);
ipw.decreaseIndent(); // level 2
ipw.decreaseIndent(); // level 1
}
}
@@ -470,6 +538,14 @@ class ControllerImpl extends LocationTimeZoneProviderController {
mUncertaintyTimeoutQueue.runDelayed(() -> onProviderUncertaintyTimeout(provider),
delay.toMillis());
}
if (provider == mPrimaryProvider) {
// (Try to) enable the secondary. It could already be enabled, or enabling might not
// succeed if the provider has previously reported it is perm failed. The uncertainty
// timeout (set above) is used to ensure that an uncertain suggestion will be made if
// the secondary cannot generate a success event in time.
tryEnableProvider(mSecondaryProvider, mCurrentUserConfiguration);
}
}
private void onProviderUncertaintyTimeout(@NonNull LocationTimeZoneProvider provider) {
@@ -478,7 +554,8 @@ class ControllerImpl extends LocationTimeZoneProviderController {
synchronized (mSharedLock) {
GeolocationTimeZoneSuggestion suggestion = createUncertainSuggestion(
"Uncertainty timeout triggered for " + provider.getName() + ":"
+ " primary=" + mPrimaryProvider);
+ " primary=" + mPrimaryProvider
+ ", secondary=" + mSecondaryProvider);
makeSuggestion(suggestion);
}
}
@@ -498,6 +575,8 @@ class ControllerImpl extends LocationTimeZoneProviderController {
LocationTimeZoneProvider targetProvider;
if (Objects.equals(mPrimaryProvider.getName(), targetProviderName)) {
targetProvider = mPrimaryProvider;
} else if (Objects.equals(mSecondaryProvider.getName(), targetProviderName)) {
targetProvider = mSecondaryProvider;
} else {
warnLog("Unable to process simulated binder provider event,"
+ " unknown providerName in event=" + event);

View File

@@ -44,8 +44,8 @@ import java.util.Objects;
* are made to the {@link TimeZoneDetectorInternal}, and the {@link LocationTimeZoneProvider}s that
* offer {@link android.location.timezone.LocationTimeZoneEvent}s.
*
* TODO(b/152744911): This implementation currently only supports a primary provider. Support for a
* secondary provider must be added in a later commit.
* <p>For details of the time zone suggestion behavior, see {@link
* LocationTimeZoneProviderController}.
*
* <p>Implementation details:
*
@@ -109,6 +109,7 @@ public class LocationTimeZoneManagerService extends Binder {
static final String TAG = "LocationTZDetector";
static final String PRIMARY_PROVIDER_NAME = "primary";
static final String SECONDARY_PROVIDER_NAME = "secondary";
private static final String SIMULATION_MODE_SYSTEM_PROPERTY_PREFIX =
"persist.sys.location_tz_simulation_mode.";
@@ -117,6 +118,8 @@ public class LocationTimeZoneManagerService extends Binder {
private static final String PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
"com.android.location.timezone.service.v1.PrimaryLocationTimeZoneProvider";
private static final String SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION =
"com.android.location.timezone.service.v1.SecondaryLocationTimeZoneProvider";
@NonNull private final Context mContext;
@@ -160,8 +163,9 @@ public class LocationTimeZoneManagerService extends Binder {
// Called on an arbitrary thread during initialization.
synchronized (mSharedLock) {
LocationTimeZoneProvider primary = createPrimaryProvider();
LocationTimeZoneProvider secondary = createSecondaryProvider();
mLocationTimeZoneDetectorController =
new ControllerImpl(mThreadingDomain, primary);
new ControllerImpl(mThreadingDomain, primary, secondary);
ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain);
ControllerEnvironmentImpl environment = new ControllerEnvironmentImpl(
mThreadingDomain, mLocationTimeZoneDetectorController);
@@ -193,6 +197,27 @@ public class LocationTimeZoneManagerService extends Binder {
return createLocationTimeZoneProvider(PRIMARY_PROVIDER_NAME, proxy);
}
private LocationTimeZoneProvider createSecondaryProvider() {
LocationTimeZoneProviderProxy proxy;
if (isInSimulationMode(SECONDARY_PROVIDER_NAME)) {
proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
} else {
// TODO Uncomment this code in a later commit.
throw new UnsupportedOperationException("Not implemented");
/*
proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
mContext,
mThreadingDomain,
SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
com.android.internal.R.bool.config_enableSecondaryLocationTimeZoneOverlay,
com.android.internal.R.string
.config_secondaryLocationTimeZoneProviderPackageName
);
*/
}
return createLocationTimeZoneProvider(SECONDARY_PROVIDER_NAME, proxy);
}
private boolean isInSimulationMode(String providerName) {
return SystemProperties.getBoolean(
SIMULATION_MODE_SYSTEM_PROPERTY_PREFIX + providerName, false);

View File

@@ -21,6 +21,7 @@ import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS
import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
import static com.android.server.location.timezone.LocationTimeZoneManagerService.PRIMARY_PROVIDER_NAME;
import static com.android.server.location.timezone.LocationTimeZoneManagerService.SECONDARY_PROVIDER_NAME;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,7 +43,8 @@ import java.util.Objects;
*/
final class SimulatedBinderProviderEvent {
private static final List<String> VALID_PROVIDER_NAMES = Arrays.asList(PRIMARY_PROVIDER_NAME);
private static final List<String> VALID_PROVIDER_NAMES =
Arrays.asList(PRIMARY_PROVIDER_NAME, SECONDARY_PROVIDER_NAME);
static final int INJECTED_EVENT_TYPE_ON_BIND = 1;
static final int INJECTED_EVENT_TYPE_ON_UNBIND = 2;

View File

@@ -77,6 +77,7 @@ public class ControllerImplTest {
private TestThreadingDomain mTestThreadingDomain;
private TestCallback mTestCallback;
private TestLocationTimeZoneProvider mTestPrimaryLocationTimeZoneProvider;
private TestLocationTimeZoneProvider mTestSecondaryLocationTimeZoneProvider;
@Before
public void setUp() {
@@ -87,26 +88,30 @@ public class ControllerImplTest {
mTestCallback = new TestCallback(mTestThreadingDomain);
mTestPrimaryLocationTimeZoneProvider =
new TestLocationTimeZoneProvider(mTestThreadingDomain, "primary");
mTestSecondaryLocationTimeZoneProvider =
new TestLocationTimeZoneProvider(mTestThreadingDomain, "secondary");
}
@Test
public void initialState_enabled() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
.plus(testEnvironment.getProviderInitializationTimeoutFuzz());
// Initialize. After initialization the provider must be initialized and should be
// Initialize. After initialization the providers must be initialized and one should be
// enabled.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertInitialized();
mTestSecondaryLocationTimeZoneProvider.assertInitialized();
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestPrimaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@@ -114,17 +119,19 @@ public class ControllerImplTest {
@Test
public void initialState_disabled() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
// Initialize. After initialization the provider must be initialized but should not be
// Initialize. After initialization the providers must be initialized but neither should be
// enabled.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertInitialized();
mTestSecondaryLocationTimeZoneProvider.assertInitialized();
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@@ -132,7 +139,7 @@ public class ControllerImplTest {
@Test
public void enabled_uncertaintySuggestionSentIfNoEventReceived() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
@@ -141,6 +148,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -148,9 +156,24 @@ public class ControllerImplTest {
mTestThreadingDomain.executeNext();
// The primary should have reported uncertainty, which should trigger the controller to
// start the uncertainty timeout.
// start the uncertainty timeout and enable the secondary.
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// Simulate time passing with no provider event being received from either the primary or
// secondary.
mTestThreadingDomain.executeNext();
// Now both initialization timeouts should have triggered. The uncertainty timeout should
// still not be triggered.
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
@@ -160,6 +183,8 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertUncertainSuggestionMadeAndCommit();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@@ -167,7 +192,7 @@ public class ControllerImplTest {
@Test
public void enabled_eventReceivedBeforeInitializationTimeout() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
@@ -176,6 +201,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -186,6 +212,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -194,7 +221,7 @@ public class ControllerImplTest {
@Test
public void enabled_eventReceivedFromPrimaryAfterInitializationTimeout() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
@@ -203,6 +230,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -211,16 +239,59 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// Simulate a location event being received from the primary provider. This should cause a
// suggestion to be made.
// suggestion to be made and the secondary to be shut down.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void enabled_eventReceivedFromSecondaryAfterInitializationTimeout() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
// Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate time passing with no provider event being received from the primary.
mTestThreadingDomain.executeNext();
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// Simulate a location event being received from the secondary provider. This should cause a
// suggestion to be made.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -229,7 +300,7 @@ public class ControllerImplTest {
@Test
public void enabled_repeatedPrimaryCertainty() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
@@ -238,6 +309,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -248,6 +320,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -258,6 +331,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -267,15 +341,16 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void enabled_uncertaintyTriggersASuggestionAfterUncertaintyTimeout() {
public void enabled_repeatedSecondaryCertainty() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
@@ -284,6 +359,70 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate time passing with no provider event being received from the primary.
mTestThreadingDomain.executeNext();
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// Simulate a location event being received from the secondary provider. This should cause a
// suggestion to be made.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// A second, identical event should not cause another suggestion.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// And a third, different event should cause another suggestion.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void enabled_uncertaintyTriggersASuggestionAfterUncertaintyTimeout() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
// Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -294,18 +433,48 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate an uncertain event being received from the primary provider. This should not
// cause a suggestion to be made straight away, but the uncertainty timeout should be
// started.
// started and the secondary should be enabled.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// Simulate a location event being received from the secondary provider. This should cause a
// suggestion to be made, cancel the uncertainty timeout and ensure the secondary is
// considered initialized.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate an uncertain event being received from the secondary provider. This should not
// cause a suggestion to be made straight away, but the uncertainty timeout should be
// started. Both providers are now enabled, with no initialization timeout set.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
@@ -315,6 +484,8 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertUncertainSuggestionMadeAndCommit();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@@ -322,7 +493,7 @@ public class ControllerImplTest {
@Test
public void enabled_briefUncertaintyTriggersNoSuggestion() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
@@ -331,6 +502,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -341,27 +513,32 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Uncertainty should not cause a suggestion to be made straight away, but the uncertainty
// timeout should be started.
// timeout should be started and the secondary should be enabled.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// And a success event from the primary provider should cause the controller to make another
// suggestion, the uncertainty timeout should be cancelled.
// suggestion, the uncertainty timeout should be cancelled and the secondary should be
// disabled again.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -370,7 +547,7 @@ public class ControllerImplTest {
@Test
public void configChanges_enableAndDisableWithNoPreviousSuggestion() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
@@ -378,6 +555,7 @@ public class ControllerImplTest {
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -386,6 +564,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -393,6 +572,7 @@ public class ControllerImplTest {
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@@ -400,7 +580,7 @@ public class ControllerImplTest {
@Test
public void configChanges_enableAndDisableWithPreviousSuggestion() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_DISABLED);
@@ -408,6 +588,7 @@ public class ControllerImplTest {
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -416,6 +597,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -425,6 +607,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -436,6 +619,7 @@ public class ControllerImplTest {
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertUncertainSuggestionMadeAndCommit();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@@ -443,7 +627,7 @@ public class ControllerImplTest {
@Test
public void configChanges_userSwitch_enabledToEnabled() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
@@ -452,6 +636,7 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -463,6 +648,7 @@ public class ControllerImplTest {
// and also clear the scheduled uncertainty suggestion.
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -477,13 +663,14 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateChangesAndCommit(expectedStateTransitions);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfig(
PROVIDER_STATE_ENABLED_INITIALIZING, USER2_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void primaryPermFailure_disableAndEnable() {
public void primaryPermFailure_secondaryEventsReceived() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider);
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
@@ -492,22 +679,86 @@ public class ControllerImplTest {
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate a failure location event being received from the primary provider. This should
// cause an uncertain suggestion to be made.
// cause the secondary to be enabled.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertUncertainSuggestionMadeAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate uncertainty from the secondary.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// And a success event from the secondary provider should cause the controller to make
// another suggestion, the uncertainty timeout should be cancelled.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate uncertainty from the secondary.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
}
@Test
public void primaryPermFailure_disableAndEnable() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
// Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate a failure location event being received from the primary provider. This should
// cause the secondary to be enabled.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Now signal a config change so that geo detection is disabled.
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
@@ -515,6 +766,164 @@ public class ControllerImplTest {
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void secondaryPermFailure_primaryEventsReceived() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
// Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate an uncertain event from the primary. This will enable the secondary, which will
// give this test the opportunity to simulate its failure. Then it will be possible to
// demonstrate controller behavior with only the primary working.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// Simulate failure event from the secondary. This should just affect the secondary's state.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// And a success event from the primary provider should cause the controller to make
// a suggestion, the uncertainty timeout should be cancelled.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_CERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertSuggestionMadeAndCommit(
USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2.getTimeZoneIds());
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate uncertainty from the primary. The secondary cannot be enabled.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
}
@Test
public void secondaryPermFailure_disableAndEnable() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
// Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate an uncertain event from the primary. This will enable the secondary, which will
// give this test the opportunity to simulate its failure. Then it will be possible to
// demonstrate controller behavior with only the primary working.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// Simulate failure event from the secondary. This should just affect the secondary's state.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_UNCERTAIN, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertNoSuggestionMade();
assertUncertaintyTimeoutSet(testEnvironment, controllerImpl);
// Now signal a config change so that geo detection is disabled.
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_DISABLED);
mTestPrimaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Now signal a config change so that geo detection is enabled. Only the primary can be
// enabled.
testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void bothPermFailure_disableAndEnable() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
// Initialize and check initial state.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertIsDisabledAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate a failure event from the primary. This will enable the secondary.
mTestPrimaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_ENABLED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
// Simulate failure event from the secondary.
mTestSecondaryLocationTimeZoneProvider.simulateLocationTimeZoneEvent(
USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT);
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertUncertainSuggestionMadeAndCommit();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}