Merge "Re-add OfflineLocationTimeZoneDelegate.onDestroy"
diff --git a/locationtzprovider/src/main/java/com/android/timezone/location/provider/OfflineLocationTimeZoneProviderService.java b/locationtzprovider/src/main/java/com/android/timezone/location/provider/OfflineLocationTimeZoneProviderService.java
index f8dc49a..c8b7e22 100644
--- a/locationtzprovider/src/main/java/com/android/timezone/location/provider/OfflineLocationTimeZoneProviderService.java
+++ b/locationtzprovider/src/main/java/com/android/timezone/location/provider/OfflineLocationTimeZoneProviderService.java
@@ -59,6 +59,11 @@
}
@Override
+ public void onDestroy() {
+ mDelegate.onDestroy();
+ }
+
+ @Override
public void onStartUpdates(long initializationTimeoutMillis) {
mDelegate.onStartUpdates(Duration.ofMillis(initializationTimeoutMillis));
}
diff --git a/locationtzprovider/src/main/java/com/android/timezone/location/provider/core/OfflineLocationTimeZoneDelegate.java b/locationtzprovider/src/main/java/com/android/timezone/location/provider/core/OfflineLocationTimeZoneDelegate.java
index 33c26f8..c808183 100644
--- a/locationtzprovider/src/main/java/com/android/timezone/location/provider/core/OfflineLocationTimeZoneDelegate.java
+++ b/locationtzprovider/src/main/java/com/android/timezone/location/provider/core/OfflineLocationTimeZoneDelegate.java
@@ -174,6 +174,23 @@
}
}
+ /** Called during {@link android.service.timezone.TimeZoneProviderService#onDestroy}. */
+ public void onDestroy() {
+ PiiLoggable entryCause = PiiLoggables.fromString("onDestroy() called");
+ logDebug(entryCause);
+
+ synchronized (mLock) {
+ cancelTimeoutsAndLocationCallbacks();
+
+ Mode currentMode = mCurrentMode.get();
+ if (currentMode.mModeEnum == MODE_STARTED) {
+ sendTimeZoneUncertainResultIfNeeded();
+ }
+ Mode newMode = new Mode(MODE_DESTROYED, entryCause);
+ mCurrentMode.set(newMode);
+ }
+ }
+
/** Called during {@link android.service.timezone.TimeZoneProviderService#onStartUpdates}. */
public void onStartUpdates(@NonNull Duration initializationTimeout) {
Objects.requireNonNull(initializationTimeout);
diff --git a/locationtzprovider/src/test/java/com/android/timezone/location/provider/core/OfflineLocationTimeZoneDelegateTest.java b/locationtzprovider/src/test/java/com/android/timezone/location/provider/core/OfflineLocationTimeZoneDelegateTest.java
index e17656a..e1947ef 100644
--- a/locationtzprovider/src/test/java/com/android/timezone/location/provider/core/OfflineLocationTimeZoneDelegateTest.java
+++ b/locationtzprovider/src/test/java/com/android/timezone/location/provider/core/OfflineLocationTimeZoneDelegateTest.java
@@ -18,6 +18,7 @@
import static com.android.timezone.location.provider.core.OfflineLocationTimeZoneDelegate.LOCATION_LISTEN_MODE_ACTIVE;
import static com.android.timezone.location.provider.core.OfflineLocationTimeZoneDelegate.LOCATION_LISTEN_MODE_PASSIVE;
import static com.android.timezone.location.provider.core.TimeZoneProviderResult.RESULT_TYPE_SUGGESTION;
+import static com.android.timezone.location.provider.core.TimeZoneProviderResult.RESULT_TYPE_UNCERTAIN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -91,11 +92,13 @@
assertEquals(Mode.MODE_STOPPED, mDelegate.getCurrentModeEnumForTests());
mTestEnvironment.assertIsNotListening();
mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertNoResultReported();
+
+ final Duration initializationTimeout = Duration.ofSeconds(20);
+ mDelegate.onStartUpdates(initializationTimeout);
// The provider should have started an initialization timeout and followed the first
// instruction from the accountant.
- final Duration initializationTimeout = Duration.ofSeconds(20);
- mDelegate.onStartUpdates(initializationTimeout);
FakeEnvironment.TestTimeoutState<?> initializationTimeoutState =
mTestEnvironment.getActiveTimeoutState(0);
initializationTimeoutState.assertDelay(initializationTimeout);
@@ -142,11 +145,13 @@
assertEquals(Mode.MODE_STOPPED, mDelegate.getCurrentModeEnumForTests());
mTestEnvironment.assertIsNotListening();
mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertNoResultReported();
+
+ final Duration initializationTimeout = Duration.ofSeconds(20);
+ mDelegate.onStartUpdates(initializationTimeout);
// The provider should have started an initialization timeout and followed the first
// instruction from the accountant.
- final Duration initializationTimeout = Duration.ofSeconds(20);
- mDelegate.onStartUpdates(initializationTimeout);
FakeEnvironment.TestTimeoutState<?> initializationTimeoutState =
mTestEnvironment.getActiveTimeoutState(0);
initializationTimeoutState.assertDelay(initializationTimeout);
@@ -169,6 +174,102 @@
passiveInstruction.listenMode, passiveInstruction.duration);
}
+ @Test
+ public void onDestroy_neverStarted() throws Exception {
+ assertEquals(Mode.MODE_STOPPED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsNotListening();
+ mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertNoResultReported();
+
+ mDelegate.onDestroy();
+
+ assertEquals(Mode.MODE_DESTROYED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsNotListening();
+ mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertNoResultReported();
+ }
+
+ @Test
+ public void onDestroy_afterStarted() throws Exception {
+ // Prime the accountant with instructions.
+ ListeningInstruction activeInstruction = new ListeningInstruction(
+ LOCATION_LISTEN_MODE_ACTIVE, Duration.ofSeconds(15));
+ ListeningInstruction passiveInstruction = new ListeningInstruction(
+ LOCATION_LISTEN_MODE_PASSIVE, Duration.ofSeconds(25));
+ mTestLocationListeningAccountant.addInstruction(activeInstruction)
+ .addInstruction(passiveInstruction);
+
+ // Start of the test
+
+ assertEquals(Mode.MODE_STOPPED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsNotListening();
+ mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertNoResultReported();
+
+ final Duration initializationTimeout = Duration.ofSeconds(20);
+ mDelegate.onStartUpdates(initializationTimeout);
+
+ // The provider should have started an initialization timeout and followed the first
+ // instruction from the accountant.
+ FakeEnvironment.TestTimeoutState<?> initializationTimeoutState =
+ mTestEnvironment.getActiveTimeoutState(0);
+ initializationTimeoutState.assertDelay(initializationTimeout);
+ assertEquals(Mode.MODE_STARTED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsLocationListening(
+ activeInstruction.listenMode, activeInstruction.duration);
+
+ // Destroyed without first being stopped.
+ mDelegate.onDestroy();
+
+ assertEquals(Mode.MODE_DESTROYED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsNotListening();
+ mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertUncertainResultReported();
+ }
+
+ @Test
+ public void onDestroy_afterStartedAndStopped() throws Exception {
+ // Prime the accountant with instructions.
+ ListeningInstruction activeInstruction = new ListeningInstruction(
+ LOCATION_LISTEN_MODE_ACTIVE, Duration.ofSeconds(15));
+ ListeningInstruction passiveInstruction = new ListeningInstruction(
+ LOCATION_LISTEN_MODE_PASSIVE, Duration.ofSeconds(25));
+ mTestLocationListeningAccountant.addInstruction(activeInstruction)
+ .addInstruction(passiveInstruction);
+
+ // Start of the test
+ assertEquals(Mode.MODE_STOPPED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsNotListening();
+ mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertNoResultReported();
+
+ final Duration initializationTimeout = Duration.ofSeconds(20);
+ mDelegate.onStartUpdates(initializationTimeout);
+
+ // The provider should have started an initialization timeout and followed the first
+ // instruction from the accountant.
+ FakeEnvironment.TestTimeoutState<?> initializationTimeoutState =
+ mTestEnvironment.getActiveTimeoutState(0);
+ initializationTimeoutState.assertDelay(initializationTimeout);
+ assertEquals(Mode.MODE_STARTED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsLocationListening(
+ activeInstruction.listenMode, activeInstruction.duration);
+
+ mDelegate.onStopUpdates();
+ assertEquals(Mode.MODE_STOPPED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsNotListening();
+ mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertNoResultReported();
+
+ // Destroyed without first being stopped.
+ mDelegate.onDestroy();
+
+ assertEquals(Mode.MODE_DESTROYED, mDelegate.getCurrentModeEnumForTests());
+ mTestEnvironment.assertIsNotListening();
+ mTestEnvironment.assertNoActiveTimeouts();
+ mTestEnvironment.assertNoResultReported();
+ }
+
private static class FakeEnvironment implements Environment {
private final FakeGeoTimeZonesFinder mFakeGeoTimeZonesFinder = new FakeGeoTimeZonesFinder();
@@ -321,6 +422,12 @@
return this;
}
+ FakeEnvironment assertUncertainResultReported() {
+ assertNotNull(mLastResultReported);
+ assertEquals(RESULT_TYPE_UNCERTAIN, mLastResultReported.getType());
+ return this;
+ }
+
FakeEnvironment simulateTimePassing(Duration duration) {
mElapsedRealtimeMillis += duration.toMillis();
return this;