Loading services/core/java/com/android/server/timezonedetector/NotifyingTimeZoneChangeListener.java +16 −5 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGI import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_MANUAL; import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_TELEPHONY; import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_UNKNOWN; import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW; import android.annotation.DurationMillisLong; import android.annotation.IntDef; Loading Loading @@ -398,7 +399,10 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener { if (changeEvent.getOrigin() == ORIGIN_MANUAL) { // Just clear any existing notification. clearNotificationForUser(currentUserId); } else { } else if (changeEvent.getOldConfidence() != TIME_ZONE_CONFIDENCE_LOW) { // b/421857844 Only notify if the old confidence is not 0. This // is to prevent notifying users when the time zone is first set // after setup wizard. notifyOfTimeZoneChange(currentUserId, trackedChangeEvent); } } Loading @@ -425,10 +429,17 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener { TimeZoneChangeEvent lastChangeEvent = lastTimeZoneChangeRecord.getEvent(); if (!changeEvent.getOldZoneId().equals(lastChangeEvent.getNewZoneId())) { int changeEventId = mNextChangeEventId.getAndIncrement(); TimeZoneChangeEvent syntheticChangeEvent = new TimeZoneChangeEvent( mEnvironment.elapsedRealtimeMillis(), mEnvironment.currentTimeMillis(), ORIGIN_UNKNOWN, UserHandle.USER_NULL, lastChangeEvent.getNewZoneId(), changeEvent.getOldZoneId(), 0, "Synthetic"); TimeZoneChangeEvent syntheticChangeEvent = new TimeZoneChangeEvent( mEnvironment.elapsedRealtimeMillis(), mEnvironment.currentTimeMillis(), ORIGIN_UNKNOWN, UserHandle.USER_NULL, /* oldZoneId= */ lastChangeEvent.getNewZoneId(), /* newZoneId= */ changeEvent.getOldZoneId(), /* oldConfidence= */ lastChangeEvent.getNewConfidence(), /* newConfidence= */ TIME_ZONE_CONFIDENCE_LOW, "Synthetic"); TimeZoneChangeRecord syntheticTrackedChangeEvent = new TimeZoneChangeRecord(changeEventId, syntheticChangeEvent); syntheticTrackedChangeEvent.setStatus(STATUS_SUPERSEDED, SIGNAL_TYPE_NONE); Loading services/core/java/com/android/server/timezonedetector/TimeZoneChangeListener.java +51 −13 Original line number Diff line number Diff line Loading @@ -43,19 +43,27 @@ public interface TimeZoneChangeListener { private final @UserIdInt int mUserId; private final String mOldZoneId; private final String mNewZoneId; private final @TimeZoneConfidence int mOldConfidence; private final @TimeZoneConfidence int mNewConfidence; private final String mCause; public TimeZoneChangeEvent(@ElapsedRealtimeLong long elapsedRealtimeMillis, public TimeZoneChangeEvent( @ElapsedRealtimeLong long elapsedRealtimeMillis, @CurrentTimeMillisLong long unixEpochTimeMillis, @Origin int origin, @UserIdInt int userId, @NonNull String oldZoneId, @NonNull String newZoneId, int newConfidence, @NonNull String cause) { @Origin int origin, @UserIdInt int userId, @NonNull String oldZoneId, @NonNull String newZoneId, @TimeZoneConfidence int oldConfidence, @TimeZoneConfidence int newConfidence, @NonNull String cause) { mElapsedRealtimeMillis = elapsedRealtimeMillis; mUnixEpochTimeMillis = unixEpochTimeMillis; mOrigin = origin; mUserId = userId; mOldZoneId = Objects.requireNonNull(oldZoneId); mNewZoneId = Objects.requireNonNull(newZoneId); mOldConfidence = oldConfidence; mNewConfidence = newConfidence; mCause = Objects.requireNonNull(cause); } Loading Loading @@ -89,17 +97,38 @@ public interface TimeZoneChangeListener { return mNewZoneId; } public @TimeZoneConfidence int getOldConfidence() { return mOldConfidence; } public @TimeZoneConfidence int getNewConfidence() { return mNewConfidence; } @Override public String toString() { return "TimeZoneChangeEvent{" + "mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + ", mUnixEpochTimeMillis=" + mUnixEpochTimeMillis + ", mOrigin=" + mOrigin + ", mUserId=" + mUserId + ", mOldZoneId='" + mOldZoneId + '\'' + ", mNewZoneId='" + mNewZoneId + '\'' + ", mNewConfidence=" + mNewConfidence + ", mCause='" + mCause + '\'' + "mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + ", mUnixEpochTimeMillis=" + mUnixEpochTimeMillis + ", mOrigin=" + mOrigin + ", mUserId=" + mUserId + ", mOldZoneId='" + mOldZoneId + '\'' + ", mNewZoneId='" + mNewZoneId + '\'' + ", mOldConfidence=" + mOldConfidence + ", mNewConfidence=" + mNewConfidence + ", mCause='" + mCause + '\'' + '}'; } Loading @@ -115,6 +144,7 @@ public interface TimeZoneChangeListener { && mUserId == that.mUserId && Objects.equals(mOldZoneId, that.mOldZoneId) && Objects.equals(mNewZoneId, that.mNewZoneId) && mOldConfidence == that.mOldConfidence && mNewConfidence == that.mNewConfidence && Objects.equals(mCause, that.mCause); } Loading @@ -123,8 +153,16 @@ public interface TimeZoneChangeListener { @Override public int hashCode() { return Objects.hash(mElapsedRealtimeMillis, mUnixEpochTimeMillis, mOrigin, mUserId, mOldZoneId, mNewZoneId, mNewConfidence, mCause); return Objects.hash( mElapsedRealtimeMillis, mUnixEpochTimeMillis, mOrigin, mUserId, mOldZoneId, mNewZoneId, mOldConfidence, mNewConfidence, mCause); } } } services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +8 −2 Original line number Diff line number Diff line Loading @@ -802,9 +802,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat // whether the device / user sticks with it. TimeZoneChangeListener.TimeZoneChangeEvent changeEvent = new TimeZoneChangeListener.TimeZoneChangeEvent( SystemClock.elapsedRealtime(), System.currentTimeMillis(), origin, SystemClock.elapsedRealtime(), System.currentTimeMillis(), origin, userId, currentZoneId, newZoneId, newConfidence, cause); currentZoneId, newZoneId, currentConfidence, newConfidence, cause); mChangeTracker.process(changeEvent); } } Loading services/tests/timetests/src/com/android/server/timezonedetector/NotifyingTimeZoneChangeListenerTest.java +185 −101 Original line number Diff line number Diff line Loading @@ -26,11 +26,15 @@ import static com.android.server.timezonedetector.NotifyingTimeZoneChangeListene import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_LOCATION; import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_MANUAL; import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_TELEPHONY; import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH; import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.spy; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; import android.app.NotificationManager; Loading Loading @@ -152,7 +156,8 @@ public class NotifyingTimeZoneChangeListenerTest { public void process_autoDetectionOff_noManualTracking_shouldTrackWithoutNotifying() { enableTimeZoneNotifications(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -161,7 +166,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE); Loading @@ -179,7 +185,8 @@ public class NotifyingTimeZoneChangeListenerTest { public void process_autoDetectionOff_shouldTrackWithoutNotifying() { enableNotificationsWithManualChangeTracking(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -188,7 +195,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE); Loading Loading @@ -217,7 +225,8 @@ public class NotifyingTimeZoneChangeListenerTest { enableNotificationsWithManualChangeTracking(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -226,7 +235,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading @@ -241,7 +251,8 @@ public class NotifyingTimeZoneChangeListenerTest { assertEquals(1, mNotificationManager.getNotifications().size()); mHandler.assertTotalMessagesEnqueued(1); expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 2, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 1000L, Loading @@ -250,7 +261,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/London", /* newZoneId= */ "Europe/Paris", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading @@ -268,17 +280,20 @@ public class NotifyingTimeZoneChangeListenerTest { // Test manual change within revert threshold { expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 3, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 999L + AUTO_REVERT_THRESHOLD, /* unixEpochTimeMillis= */ 1726597800000L + 999L + AUTO_REVERT_THRESHOLD, /* unixEpochTimeMillis= */ 1726597800000L + 999L + AUTO_REVERT_THRESHOLD, /* origin= */ ORIGIN_MANUAL, /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE); Loading @@ -303,17 +318,20 @@ public class NotifyingTimeZoneChangeListenerTest { disableTimeZoneAutoDetection(); // [END] Reset previous event expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 5, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 1001L + AUTO_REVERT_THRESHOLD, /* unixEpochTimeMillis= */ 1726597800000L + 1001L + AUTO_REVERT_THRESHOLD, /* unixEpochTimeMillis= */ 1726597800000L + 1001L + AUTO_REVERT_THRESHOLD, /* origin= */ ORIGIN_MANUAL, /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE); Loading Loading @@ -344,7 +362,8 @@ public class NotifyingTimeZoneChangeListenerTest { enableNotificationsWithManualChangeTracking(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -353,7 +372,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading @@ -368,7 +388,8 @@ public class NotifyingTimeZoneChangeListenerTest { assertEquals(1, mNotificationManager.getNotifications().size()); mHandler.assertTotalMessagesEnqueued(1); expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 3, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 1000L, Loading @@ -377,7 +398,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Athens", /* newZoneId= */ "Europe/Paris", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading Loading @@ -407,7 +429,8 @@ public class NotifyingTimeZoneChangeListenerTest { enableNotificationsWithManualChangeTracking(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -416,7 +439,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/Rome", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading @@ -433,6 +457,66 @@ public class NotifyingTimeZoneChangeListenerTest { mHandler.assertTotalMessagesEnqueued(1); } @Test @Parameters(method = "getDetectionOrigins") public void process_oldConfidenceIsZero_noNotificationSent( @TimeZoneDetectorStrategy.Origin int origin) { if (origin == ORIGIN_LOCATION) { enableLocationTimeZoneDetection(); } else if (origin == ORIGIN_TELEPHONY) { enableTelephonyTimeZoneDetection(); } else { throw new IllegalStateException( "The given origin has not been implemented for this test: " + origin); } enableNotificationsWithManualChangeTracking(); // Process a first event with zero confidence. // We expect this to be tracked but not to generate a notification. TimeZoneChangeEvent firstEvent = new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, /* unixEpochTimeMillis= */ 1726597800000L, /* origin= */ origin, /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* oldConfidence= */ TIME_ZONE_CONFIDENCE_LOW, /* newConfidence= */ TIME_ZONE_CONFIDENCE_LOW, // Zero confidence /* cause= */ "NO_REASON"); mTimeZoneChangeTracker.process(firstEvent); // Verify the first event was tracked but did not trigger a notification. TimeZoneChangeRecord firstRecord = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord(); assertEquals(firstEvent, firstRecord.getEvent()); assertEquals(0, mNotificationManager.getNotifications().size()); mHandler.assertTotalMessagesEnqueued(1); // Process a second event with non-zero confidence. TimeZoneChangeEvent secondEvent = new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 1000L, /* unixEpochTimeMillis= */ 1726597800000L + 1000L, /* origin= */ origin, /* userId= */ mUid, /* oldZoneId= */ "Europe/London", /* newZoneId= */ "America/New_York", /* oldConfidence= */ TIME_ZONE_CONFIDENCE_LOW, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON"); mTimeZoneChangeTracker.process(secondEvent); // Verify the second event was tracked but did not trigger a notification. TimeZoneChangeRecord secondRecord = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord(); assertEquals(secondEvent, secondRecord.getEvent()); // No notification sent as the previous event had zero confidence. assertEquals(0, mNotificationManager.getNotifications().size()); mHandler.assertTotalMessagesEnqueued(2); } private void enableLocationTimeZoneDetection() { ConfigurationInternal oldConfiguration = mServiceConfigAccessor.getCurrentUserConfigurationInternal(); Loading Loading
services/core/java/com/android/server/timezonedetector/NotifyingTimeZoneChangeListener.java +16 −5 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGI import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_MANUAL; import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_TELEPHONY; import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_UNKNOWN; import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW; import android.annotation.DurationMillisLong; import android.annotation.IntDef; Loading Loading @@ -398,7 +399,10 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener { if (changeEvent.getOrigin() == ORIGIN_MANUAL) { // Just clear any existing notification. clearNotificationForUser(currentUserId); } else { } else if (changeEvent.getOldConfidence() != TIME_ZONE_CONFIDENCE_LOW) { // b/421857844 Only notify if the old confidence is not 0. This // is to prevent notifying users when the time zone is first set // after setup wizard. notifyOfTimeZoneChange(currentUserId, trackedChangeEvent); } } Loading @@ -425,10 +429,17 @@ public class NotifyingTimeZoneChangeListener implements TimeZoneChangeListener { TimeZoneChangeEvent lastChangeEvent = lastTimeZoneChangeRecord.getEvent(); if (!changeEvent.getOldZoneId().equals(lastChangeEvent.getNewZoneId())) { int changeEventId = mNextChangeEventId.getAndIncrement(); TimeZoneChangeEvent syntheticChangeEvent = new TimeZoneChangeEvent( mEnvironment.elapsedRealtimeMillis(), mEnvironment.currentTimeMillis(), ORIGIN_UNKNOWN, UserHandle.USER_NULL, lastChangeEvent.getNewZoneId(), changeEvent.getOldZoneId(), 0, "Synthetic"); TimeZoneChangeEvent syntheticChangeEvent = new TimeZoneChangeEvent( mEnvironment.elapsedRealtimeMillis(), mEnvironment.currentTimeMillis(), ORIGIN_UNKNOWN, UserHandle.USER_NULL, /* oldZoneId= */ lastChangeEvent.getNewZoneId(), /* newZoneId= */ changeEvent.getOldZoneId(), /* oldConfidence= */ lastChangeEvent.getNewConfidence(), /* newConfidence= */ TIME_ZONE_CONFIDENCE_LOW, "Synthetic"); TimeZoneChangeRecord syntheticTrackedChangeEvent = new TimeZoneChangeRecord(changeEventId, syntheticChangeEvent); syntheticTrackedChangeEvent.setStatus(STATUS_SUPERSEDED, SIGNAL_TYPE_NONE); Loading
services/core/java/com/android/server/timezonedetector/TimeZoneChangeListener.java +51 −13 Original line number Diff line number Diff line Loading @@ -43,19 +43,27 @@ public interface TimeZoneChangeListener { private final @UserIdInt int mUserId; private final String mOldZoneId; private final String mNewZoneId; private final @TimeZoneConfidence int mOldConfidence; private final @TimeZoneConfidence int mNewConfidence; private final String mCause; public TimeZoneChangeEvent(@ElapsedRealtimeLong long elapsedRealtimeMillis, public TimeZoneChangeEvent( @ElapsedRealtimeLong long elapsedRealtimeMillis, @CurrentTimeMillisLong long unixEpochTimeMillis, @Origin int origin, @UserIdInt int userId, @NonNull String oldZoneId, @NonNull String newZoneId, int newConfidence, @NonNull String cause) { @Origin int origin, @UserIdInt int userId, @NonNull String oldZoneId, @NonNull String newZoneId, @TimeZoneConfidence int oldConfidence, @TimeZoneConfidence int newConfidence, @NonNull String cause) { mElapsedRealtimeMillis = elapsedRealtimeMillis; mUnixEpochTimeMillis = unixEpochTimeMillis; mOrigin = origin; mUserId = userId; mOldZoneId = Objects.requireNonNull(oldZoneId); mNewZoneId = Objects.requireNonNull(newZoneId); mOldConfidence = oldConfidence; mNewConfidence = newConfidence; mCause = Objects.requireNonNull(cause); } Loading Loading @@ -89,17 +97,38 @@ public interface TimeZoneChangeListener { return mNewZoneId; } public @TimeZoneConfidence int getOldConfidence() { return mOldConfidence; } public @TimeZoneConfidence int getNewConfidence() { return mNewConfidence; } @Override public String toString() { return "TimeZoneChangeEvent{" + "mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + ", mUnixEpochTimeMillis=" + mUnixEpochTimeMillis + ", mOrigin=" + mOrigin + ", mUserId=" + mUserId + ", mOldZoneId='" + mOldZoneId + '\'' + ", mNewZoneId='" + mNewZoneId + '\'' + ", mNewConfidence=" + mNewConfidence + ", mCause='" + mCause + '\'' + "mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + ", mUnixEpochTimeMillis=" + mUnixEpochTimeMillis + ", mOrigin=" + mOrigin + ", mUserId=" + mUserId + ", mOldZoneId='" + mOldZoneId + '\'' + ", mNewZoneId='" + mNewZoneId + '\'' + ", mOldConfidence=" + mOldConfidence + ", mNewConfidence=" + mNewConfidence + ", mCause='" + mCause + '\'' + '}'; } Loading @@ -115,6 +144,7 @@ public interface TimeZoneChangeListener { && mUserId == that.mUserId && Objects.equals(mOldZoneId, that.mOldZoneId) && Objects.equals(mNewZoneId, that.mNewZoneId) && mOldConfidence == that.mOldConfidence && mNewConfidence == that.mNewConfidence && Objects.equals(mCause, that.mCause); } Loading @@ -123,8 +153,16 @@ public interface TimeZoneChangeListener { @Override public int hashCode() { return Objects.hash(mElapsedRealtimeMillis, mUnixEpochTimeMillis, mOrigin, mUserId, mOldZoneId, mNewZoneId, mNewConfidence, mCause); return Objects.hash( mElapsedRealtimeMillis, mUnixEpochTimeMillis, mOrigin, mUserId, mOldZoneId, mNewZoneId, mOldConfidence, mNewConfidence, mCause); } } }
services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +8 −2 Original line number Diff line number Diff line Loading @@ -802,9 +802,15 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat // whether the device / user sticks with it. TimeZoneChangeListener.TimeZoneChangeEvent changeEvent = new TimeZoneChangeListener.TimeZoneChangeEvent( SystemClock.elapsedRealtime(), System.currentTimeMillis(), origin, SystemClock.elapsedRealtime(), System.currentTimeMillis(), origin, userId, currentZoneId, newZoneId, newConfidence, cause); currentZoneId, newZoneId, currentConfidence, newConfidence, cause); mChangeTracker.process(changeEvent); } } Loading
services/tests/timetests/src/com/android/server/timezonedetector/NotifyingTimeZoneChangeListenerTest.java +185 −101 Original line number Diff line number Diff line Loading @@ -26,11 +26,15 @@ import static com.android.server.timezonedetector.NotifyingTimeZoneChangeListene import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_LOCATION; import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_MANUAL; import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.ORIGIN_TELEPHONY; import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH; import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.spy; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; import android.app.NotificationManager; Loading Loading @@ -152,7 +156,8 @@ public class NotifyingTimeZoneChangeListenerTest { public void process_autoDetectionOff_noManualTracking_shouldTrackWithoutNotifying() { enableTimeZoneNotifications(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -161,7 +166,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE); Loading @@ -179,7 +185,8 @@ public class NotifyingTimeZoneChangeListenerTest { public void process_autoDetectionOff_shouldTrackWithoutNotifying() { enableNotificationsWithManualChangeTracking(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -188,7 +195,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE); Loading Loading @@ -217,7 +225,8 @@ public class NotifyingTimeZoneChangeListenerTest { enableNotificationsWithManualChangeTracking(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -226,7 +235,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading @@ -241,7 +251,8 @@ public class NotifyingTimeZoneChangeListenerTest { assertEquals(1, mNotificationManager.getNotifications().size()); mHandler.assertTotalMessagesEnqueued(1); expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 2, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 1000L, Loading @@ -250,7 +261,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/London", /* newZoneId= */ "Europe/Paris", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading @@ -268,17 +280,20 @@ public class NotifyingTimeZoneChangeListenerTest { // Test manual change within revert threshold { expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 3, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 999L + AUTO_REVERT_THRESHOLD, /* unixEpochTimeMillis= */ 1726597800000L + 999L + AUTO_REVERT_THRESHOLD, /* unixEpochTimeMillis= */ 1726597800000L + 999L + AUTO_REVERT_THRESHOLD, /* origin= */ ORIGIN_MANUAL, /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE); Loading @@ -303,17 +318,20 @@ public class NotifyingTimeZoneChangeListenerTest { disableTimeZoneAutoDetection(); // [END] Reset previous event expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 5, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 1001L + AUTO_REVERT_THRESHOLD, /* unixEpochTimeMillis= */ 1726597800000L + 1001L + AUTO_REVERT_THRESHOLD, /* unixEpochTimeMillis= */ 1726597800000L + 1001L + AUTO_REVERT_THRESHOLD, /* origin= */ ORIGIN_MANUAL, /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNTRACKED, SIGNAL_TYPE_NONE); Loading Loading @@ -344,7 +362,8 @@ public class NotifyingTimeZoneChangeListenerTest { enableNotificationsWithManualChangeTracking(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -353,7 +372,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading @@ -368,7 +388,8 @@ public class NotifyingTimeZoneChangeListenerTest { assertEquals(1, mNotificationManager.getNotifications().size()); mHandler.assertTotalMessagesEnqueued(1); expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 3, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 1000L, Loading @@ -377,7 +398,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Athens", /* newZoneId= */ "Europe/Paris", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading Loading @@ -407,7 +429,8 @@ public class NotifyingTimeZoneChangeListenerTest { enableNotificationsWithManualChangeTracking(); TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( TimeZoneChangeRecord expectedTimeZoneChangeRecord = new TimeZoneChangeRecord( /* id= */ 1, new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, Loading @@ -416,7 +439,8 @@ public class NotifyingTimeZoneChangeListenerTest { /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/Rome", /* newConfidence= */ 1, /* oldConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON")); expectedTimeZoneChangeRecord.setStatus(STATUS_UNKNOWN, SIGNAL_TYPE_UNKNOWN); Loading @@ -433,6 +457,66 @@ public class NotifyingTimeZoneChangeListenerTest { mHandler.assertTotalMessagesEnqueued(1); } @Test @Parameters(method = "getDetectionOrigins") public void process_oldConfidenceIsZero_noNotificationSent( @TimeZoneDetectorStrategy.Origin int origin) { if (origin == ORIGIN_LOCATION) { enableLocationTimeZoneDetection(); } else if (origin == ORIGIN_TELEPHONY) { enableTelephonyTimeZoneDetection(); } else { throw new IllegalStateException( "The given origin has not been implemented for this test: " + origin); } enableNotificationsWithManualChangeTracking(); // Process a first event with zero confidence. // We expect this to be tracked but not to generate a notification. TimeZoneChangeEvent firstEvent = new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 0, /* unixEpochTimeMillis= */ 1726597800000L, /* origin= */ origin, /* userId= */ mUid, /* oldZoneId= */ "Europe/Paris", /* newZoneId= */ "Europe/London", /* oldConfidence= */ TIME_ZONE_CONFIDENCE_LOW, /* newConfidence= */ TIME_ZONE_CONFIDENCE_LOW, // Zero confidence /* cause= */ "NO_REASON"); mTimeZoneChangeTracker.process(firstEvent); // Verify the first event was tracked but did not trigger a notification. TimeZoneChangeRecord firstRecord = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord(); assertEquals(firstEvent, firstRecord.getEvent()); assertEquals(0, mNotificationManager.getNotifications().size()); mHandler.assertTotalMessagesEnqueued(1); // Process a second event with non-zero confidence. TimeZoneChangeEvent secondEvent = new TimeZoneChangeEvent( /* elapsedRealtimeMillis= */ 1000L, /* unixEpochTimeMillis= */ 1726597800000L + 1000L, /* origin= */ origin, /* userId= */ mUid, /* oldZoneId= */ "Europe/London", /* newZoneId= */ "America/New_York", /* oldConfidence= */ TIME_ZONE_CONFIDENCE_LOW, /* newConfidence= */ TIME_ZONE_CONFIDENCE_HIGH, /* cause= */ "NO_REASON"); mTimeZoneChangeTracker.process(secondEvent); // Verify the second event was tracked but did not trigger a notification. TimeZoneChangeRecord secondRecord = mTimeZoneChangeTracker.getLastTimeZoneChangeRecord(); assertEquals(secondEvent, secondRecord.getEvent()); // No notification sent as the previous event had zero confidence. assertEquals(0, mNotificationManager.getNotifications().size()); mHandler.assertTotalMessagesEnqueued(2); } private void enableLocationTimeZoneDetection() { ConfigurationInternal oldConfiguration = mServiceConfigAccessor.getCurrentUserConfigurationInternal(); Loading