Loading src/java/com/android/internal/telephony/NitzStateMachineImpl.java +32 −3 Original line number Diff line number Diff line Loading @@ -305,8 +305,24 @@ public final class NitzStateMachineImpl implements NitzStateMachine { @Override public void handleAirplaneModeChanged(boolean on) { if (DBG) { Rlog.d(LOG_TAG, "handleAirplaneModeChanged: on=" + on); // TODO } // Treat entry / exit from airplane mode as a strong signal that the user wants to clear // cached state. If the user really is boarding a plane they won't want cached state from // before their flight influencing behavior. // // State is cleared on entry AND exit: on entry because the detection code shouldn't be // opinionated while in airplane mode, and on exit to avoid any unexpected signals received // while in airplane mode from influencing behavior afterwards. // // After clearing detection state, the time zone detection should work out from first // principles what the time / time zone is. This assumes calls like handleNetworkAvailable() // will be made after airplane mode is re-enabled as the device re-establishes network // connectivity. clearTimeDetectionState(); clearTimeZoneDetectionState(); } private void updateTimeFromNitz() { Loading Loading @@ -399,6 +415,11 @@ public final class NitzStateMachineImpl implements NitzStateMachine { } } private void clearTimeDetectionState() { mSavedNitzTime = null; mTimeZoneLog.log("clearTimeZoneDetectionState: All time detection state cleared."); } private void setAndBroadcastNetworkSetTimeZone(String zoneId, String logMessage) { logMessage += " [Setting device time zone to zoneId=" + zoneId + "]"; if (DBG) { Loading Loading @@ -497,6 +518,15 @@ public final class NitzStateMachineImpl implements NitzStateMachine { } } private void clearTimeZoneDetectionState() { mLatestNitzSignal = null; mGotCountryCode = false; mSavedTimeZoneId = null; mNitzTimeZoneDetectionSuccessful = false; mTimeZoneLog.log("clearTimeZoneDetectionState: All time zone detection state cleared."); } // VisibleForTesting public boolean getNitzTimeZoneDetectionSuccessful() { return mNitzTimeZoneDetectionSuccessful; } Loading @@ -510,5 +540,4 @@ public final class NitzStateMachineImpl implements NitzStateMachine { public String getSavedTimeZoneId() { return mSavedTimeZoneId; } } tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineImplTest.java +96 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import org.junit.Before; import org.junit.Test; import java.util.LinkedList; import java.util.concurrent.TimeUnit; public class NitzStateMachineImplTest extends TelephonyTest { Loading Loading @@ -631,6 +632,101 @@ public class NitzStateMachineImplTest extends TelephonyTest { assertEquals(expectedZoneId, mNitzStateMachine.getSavedTimeZoneId()); } @Test public void test_airplaneModeClearsState() throws Exception { Scenario scenario = UNITED_KINGDOM_SCENARIO.mutableCopy(); long timeStepMillis = TimeUnit.HOURS.toMillis(3); Script script = new Script() .setRealtimeClockFromScenario(scenario) .initializeSystemClock(ARBITRARY_SYSTEM_CLOCK_TIME) .initializeTimeZoneDetectionEnabled(true) .initializeTimeZoneSetting(null); // Pre-flight: Simulate a device receiving signals that allow it to detect time and time // zone. TimestampedValue<NitzData> preflightNitzSignal = scenario.createNitzSignal(); script.nitzReceived(preflightNitzSignal) .countryReceived(scenario.getNetworkCountryIsoCode()) .verifyTimeSuggestedAndZoneSetAndReset( scenario.createTimeSignal(), scenario.getTimeZoneId()); // Demonstrate the NitzStateMachineImpl is "opinionated" about time zone: toggling auto-time // zone on should cause it to set the last known time zone again. // Note: Historically Android telephony time detection hasn't retained an opinion about time // so only the time zone is set. Also, NitzStateMachine doesn't pay attention to whether // auto-time is enabled; it is left to the system server service to decide whether to act on // the time suggestion if the settings allow. script.toggleTimeZoneDetectionEnabled(false) .verifyNothingWasSetAndReset() .toggleTimeZoneDetectionEnabled(true) .verifyOnlyTimeZoneWasSetAndReset(scenario.getTimeZoneId()); // Check state that NitzStateMachine must expose. assertEquals(preflightNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData()); assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); // Boarded flight: Airplane mode turned on / time zone detection still enabled. // The NitzStateMachineImpl must lose all state and stop having an opinion about time zone. // Simulate the passage of time and update the device realtime clock. scenario.incrementTime(timeStepMillis); script.setRealtimeClockFromScenario(scenario); script.toggleAirplaneMode(true); // Check state that NitzStateMachine must expose. assertNull(mNitzStateMachine.getCachedNitzData()); assertNull(mNitzStateMachine.getSavedTimeZoneId()); // Verify there's no time zone opinion by toggling auto time zone off and on. script.toggleTimeZoneDetectionEnabled(false) .verifyNothingWasSetAndReset() .toggleTimeZoneDetectionEnabled(true) .verifyNothingWasSetAndReset(); // During flight: Airplane mode turned off / time zone detection still enabled. // The NitzStateMachineImpl still must not have an opinion about time zone / hold any state. // Simulate the passage of time and update the device realtime clock. scenario.incrementTime(timeStepMillis); script.setRealtimeClockFromScenario(scenario); script.toggleAirplaneMode(false); // Verify there's still no opinion by toggling auto time zone off and on. script.toggleTimeZoneDetectionEnabled(false) .verifyNothingWasSetAndReset() .toggleTimeZoneDetectionEnabled(true) .verifyNothingWasSetAndReset(); // Check the state that NitzStateMachine must expose. assertNull(mNitzStateMachine.getCachedNitzData()); assertNull(mNitzStateMachine.getSavedTimeZoneId()); // Post flight: Device has moved and receives new signals. // Simulate the passage of time and update the device realtime clock. scenario.incrementTime(timeStepMillis); script.setRealtimeClockFromScenario(scenario); // Simulate the movement to the destination. scenario.changeCountry(UNIQUE_US_ZONE_SCENARIO.getTimeZoneId(), UNIQUE_US_ZONE_SCENARIO.getNetworkCountryIsoCode()); // Simulate the device receiving NITZ signals again after the flight. Now the // NitzStateMachineImpl is opinionated again. TimestampedValue<NitzData> postFlightNitzSignal = scenario.createNitzSignal(); script.countryReceived(scenario.getNetworkCountryIsoCode()) .nitzReceived(postFlightNitzSignal) .verifyTimeSuggestedAndZoneSetAndReset( scenario.createTimeSignal(), scenario.getTimeZoneId()); // Check state that NitzStateMachine must expose. assertEquals(postFlightNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData()); assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } /** * Asserts a test scenario has the properties we expect for NITZ-only lookup. There are * usually multiple zones that will share the same UTC offset so we get a low quality / low Loading Loading
src/java/com/android/internal/telephony/NitzStateMachineImpl.java +32 −3 Original line number Diff line number Diff line Loading @@ -305,8 +305,24 @@ public final class NitzStateMachineImpl implements NitzStateMachine { @Override public void handleAirplaneModeChanged(boolean on) { if (DBG) { Rlog.d(LOG_TAG, "handleAirplaneModeChanged: on=" + on); // TODO } // Treat entry / exit from airplane mode as a strong signal that the user wants to clear // cached state. If the user really is boarding a plane they won't want cached state from // before their flight influencing behavior. // // State is cleared on entry AND exit: on entry because the detection code shouldn't be // opinionated while in airplane mode, and on exit to avoid any unexpected signals received // while in airplane mode from influencing behavior afterwards. // // After clearing detection state, the time zone detection should work out from first // principles what the time / time zone is. This assumes calls like handleNetworkAvailable() // will be made after airplane mode is re-enabled as the device re-establishes network // connectivity. clearTimeDetectionState(); clearTimeZoneDetectionState(); } private void updateTimeFromNitz() { Loading Loading @@ -399,6 +415,11 @@ public final class NitzStateMachineImpl implements NitzStateMachine { } } private void clearTimeDetectionState() { mSavedNitzTime = null; mTimeZoneLog.log("clearTimeZoneDetectionState: All time detection state cleared."); } private void setAndBroadcastNetworkSetTimeZone(String zoneId, String logMessage) { logMessage += " [Setting device time zone to zoneId=" + zoneId + "]"; if (DBG) { Loading Loading @@ -497,6 +518,15 @@ public final class NitzStateMachineImpl implements NitzStateMachine { } } private void clearTimeZoneDetectionState() { mLatestNitzSignal = null; mGotCountryCode = false; mSavedTimeZoneId = null; mNitzTimeZoneDetectionSuccessful = false; mTimeZoneLog.log("clearTimeZoneDetectionState: All time zone detection state cleared."); } // VisibleForTesting public boolean getNitzTimeZoneDetectionSuccessful() { return mNitzTimeZoneDetectionSuccessful; } Loading @@ -510,5 +540,4 @@ public final class NitzStateMachineImpl implements NitzStateMachine { public String getSavedTimeZoneId() { return mSavedTimeZoneId; } }
tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineImplTest.java +96 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import org.junit.Before; import org.junit.Test; import java.util.LinkedList; import java.util.concurrent.TimeUnit; public class NitzStateMachineImplTest extends TelephonyTest { Loading Loading @@ -631,6 +632,101 @@ public class NitzStateMachineImplTest extends TelephonyTest { assertEquals(expectedZoneId, mNitzStateMachine.getSavedTimeZoneId()); } @Test public void test_airplaneModeClearsState() throws Exception { Scenario scenario = UNITED_KINGDOM_SCENARIO.mutableCopy(); long timeStepMillis = TimeUnit.HOURS.toMillis(3); Script script = new Script() .setRealtimeClockFromScenario(scenario) .initializeSystemClock(ARBITRARY_SYSTEM_CLOCK_TIME) .initializeTimeZoneDetectionEnabled(true) .initializeTimeZoneSetting(null); // Pre-flight: Simulate a device receiving signals that allow it to detect time and time // zone. TimestampedValue<NitzData> preflightNitzSignal = scenario.createNitzSignal(); script.nitzReceived(preflightNitzSignal) .countryReceived(scenario.getNetworkCountryIsoCode()) .verifyTimeSuggestedAndZoneSetAndReset( scenario.createTimeSignal(), scenario.getTimeZoneId()); // Demonstrate the NitzStateMachineImpl is "opinionated" about time zone: toggling auto-time // zone on should cause it to set the last known time zone again. // Note: Historically Android telephony time detection hasn't retained an opinion about time // so only the time zone is set. Also, NitzStateMachine doesn't pay attention to whether // auto-time is enabled; it is left to the system server service to decide whether to act on // the time suggestion if the settings allow. script.toggleTimeZoneDetectionEnabled(false) .verifyNothingWasSetAndReset() .toggleTimeZoneDetectionEnabled(true) .verifyOnlyTimeZoneWasSetAndReset(scenario.getTimeZoneId()); // Check state that NitzStateMachine must expose. assertEquals(preflightNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData()); assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); // Boarded flight: Airplane mode turned on / time zone detection still enabled. // The NitzStateMachineImpl must lose all state and stop having an opinion about time zone. // Simulate the passage of time and update the device realtime clock. scenario.incrementTime(timeStepMillis); script.setRealtimeClockFromScenario(scenario); script.toggleAirplaneMode(true); // Check state that NitzStateMachine must expose. assertNull(mNitzStateMachine.getCachedNitzData()); assertNull(mNitzStateMachine.getSavedTimeZoneId()); // Verify there's no time zone opinion by toggling auto time zone off and on. script.toggleTimeZoneDetectionEnabled(false) .verifyNothingWasSetAndReset() .toggleTimeZoneDetectionEnabled(true) .verifyNothingWasSetAndReset(); // During flight: Airplane mode turned off / time zone detection still enabled. // The NitzStateMachineImpl still must not have an opinion about time zone / hold any state. // Simulate the passage of time and update the device realtime clock. scenario.incrementTime(timeStepMillis); script.setRealtimeClockFromScenario(scenario); script.toggleAirplaneMode(false); // Verify there's still no opinion by toggling auto time zone off and on. script.toggleTimeZoneDetectionEnabled(false) .verifyNothingWasSetAndReset() .toggleTimeZoneDetectionEnabled(true) .verifyNothingWasSetAndReset(); // Check the state that NitzStateMachine must expose. assertNull(mNitzStateMachine.getCachedNitzData()); assertNull(mNitzStateMachine.getSavedTimeZoneId()); // Post flight: Device has moved and receives new signals. // Simulate the passage of time and update the device realtime clock. scenario.incrementTime(timeStepMillis); script.setRealtimeClockFromScenario(scenario); // Simulate the movement to the destination. scenario.changeCountry(UNIQUE_US_ZONE_SCENARIO.getTimeZoneId(), UNIQUE_US_ZONE_SCENARIO.getNetworkCountryIsoCode()); // Simulate the device receiving NITZ signals again after the flight. Now the // NitzStateMachineImpl is opinionated again. TimestampedValue<NitzData> postFlightNitzSignal = scenario.createNitzSignal(); script.countryReceived(scenario.getNetworkCountryIsoCode()) .nitzReceived(postFlightNitzSignal) .verifyTimeSuggestedAndZoneSetAndReset( scenario.createTimeSignal(), scenario.getTimeZoneId()); // Check state that NitzStateMachine must expose. assertEquals(postFlightNitzSignal.getValue(), mNitzStateMachine.getCachedNitzData()); assertEquals(scenario.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } /** * Asserts a test scenario has the properties we expect for NITZ-only lookup. There are * usually multiple zones that will share the same UTC offset so we get a low quality / low Loading