Tidy-ups and refactoring

Extracted changes to reduce the size of upcoming changes. These do not
alter behavior.

The biggest change is associated with async execution of logic in the
time_detector. The time_zone_detector will need something similar soon
and this new approach is easier to test. Changing the time_detector will
ensure consistency.

Other changes are renames of parameters, variables and javadoc
improvements.

Bug: 222295093
Test: atest services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
Change-Id: Ibedeafa10f7d73bbdaf6055073c7cf1a79026e83
This commit is contained in:
Neil Fuller
2023-01-16 17:20:48 +00:00
parent bac13cfa56
commit b9080f55ee
13 changed files with 118 additions and 96 deletions

View File

@@ -263,11 +263,11 @@ public final class GnssTimeUpdateService extends Binder {
long gnssUnixEpochTimeMillis = locationTime.getUnixEpochTimeMillis();
long elapsedRealtimeMs = locationTime.getElapsedRealtimeNanos() / 1_000_000L;
UnixEpochTime timeSignal = new UnixEpochTime(elapsedRealtimeMs, gnssUnixEpochTimeMillis);
mLastSuggestedGnssTime = timeSignal;
UnixEpochTime unixEpochTime = new UnixEpochTime(elapsedRealtimeMs, gnssUnixEpochTimeMillis);
mLastSuggestedGnssTime = unixEpochTime;
GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
mTimeDetectorInternal.suggestGnssTime(timeSuggestion);
GnssTimeSuggestion suggestion = new GnssTimeSuggestion(unixEpochTime);
mTimeDetectorInternal.suggestGnssTime(suggestion);
}
@Override

View File

@@ -56,11 +56,19 @@ public interface TimeDetectorInternal {
* valid but does not change the time because it matches the current device time is considered
* accepted.
*/
boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion manualTimeSuggestion);
boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion suggestion);
/** Used to pass new network time suggestions to the time detector. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal);
/**
* Suggests a network time to the time detector. The suggestion may not be used by the time
* detector to set the device's time depending on device configuration and user settings, but
* can replace previous network suggestions received.
*/
void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
/** Used to pass new GNSS time suggestions to the time detector. */
void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal);
}
/**
* Suggests a GNSS-derived time to the time detector. The suggestion may not be used by the time
* detector to set the device's time depending on device configuration and user settings, but
* can replace previous GNSS suggestions received.
*/
void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion);
}

View File

@@ -72,24 +72,24 @@ public class TimeDetectorInternalImpl implements TimeDetectorInternal {
}
@Override
public boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion timeSignal) {
Objects.requireNonNull(timeSignal);
public boolean setManualTimeForDpm(@NonNull ManualTimeSuggestion suggestion) {
Objects.requireNonNull(suggestion);
int userId = mCurrentUserIdentityInjector.getCurrentUserId();
return mTimeDetectorStrategy.suggestManualTime(userId, timeSignal, false);
return mTimeDetectorStrategy.suggestManualTime(userId, suggestion, false);
}
@Override
public void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
Objects.requireNonNull(timeSignal);
public void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion) {
Objects.requireNonNull(suggestion);
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(suggestion));
}
@Override
public void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) {
Objects.requireNonNull(timeSignal);
public void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion) {
Objects.requireNonNull(suggestion);
mHandler.post(() -> mTimeDetectorStrategy.suggestGnssTime(timeSignal));
mHandler.post(() -> mTimeDetectorStrategy.suggestGnssTime(suggestion));
}
}

View File

@@ -319,9 +319,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
}
@Override
public boolean setManualTime(@NonNull ManualTimeSuggestion timeSignal) {
public boolean setManualTime(@NonNull ManualTimeSuggestion suggestion) {
enforceManageTimeDetectorPermission();
Objects.requireNonNull(timeSignal);
Objects.requireNonNull(suggestion);
// This calls suggestManualTime() as the logic is identical, it only differs in the
// permission required, which is handled on the line above.
@@ -330,7 +330,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
try {
final boolean bypassUserPolicyChecks = false;
return mTimeDetectorStrategy.suggestManualTime(
userId, timeSignal, bypassUserPolicyChecks);
userId, suggestion, bypassUserPolicyChecks);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -363,11 +363,11 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
/**
* Suggests network time with permission checks. For use by {@link TimeDetectorShellCommand}.
*/
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion) {
enforceSuggestNetworkTimePermission();
Objects.requireNonNull(timeSignal);
Objects.requireNonNull(suggestion);
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(suggestion));
}
/**

View File

@@ -87,7 +87,7 @@ public interface TimeDetectorStrategy extends Dumpable {
boolean confirmTime(@NonNull UnixEpochTime confirmationTime);
/** Processes the suggested time from telephony sources. */
void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion suggestion);
/**
* Processes the suggested manually entered time. Returns {@code false} if the suggestion was
@@ -98,11 +98,15 @@ public interface TimeDetectorStrategy extends Dumpable {
* @param bypassUserPolicyChecks {@code true} for device policy manager use cases where device
* policy restrictions that should apply to actual users can be ignored
*/
boolean suggestManualTime(@UserIdInt int userId, @NonNull ManualTimeSuggestion timeSuggestion,
boolean suggestManualTime(@UserIdInt int userId, @NonNull ManualTimeSuggestion suggestion,
boolean bypassUserPolicyChecks);
/** Processes the suggested time from network sources. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
/**
* Processes the suggested network time. The suggestion may not be used to set the device's time
* depending on device configuration and user settings, but can replace previous network
* suggestions received.
*/
void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion);
/**
* Returns the latest (accepted) network time suggestion. Returns {@code null} if there isn't
@@ -119,10 +123,10 @@ public interface TimeDetectorStrategy extends Dumpable {
void clearLatestNetworkSuggestion();
/** Processes the suggested time from gnss sources. */
void suggestGnssTime(@NonNull GnssTimeSuggestion timeSuggestion);
void suggestGnssTime(@NonNull GnssTimeSuggestion suggestion);
/** Processes the suggested time from external sources. */
void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSuggestion);
void suggestExternalTime(@NonNull ExternalTimeSuggestion suggestion);
// Utility methods below are to be moved to a better home when one becomes more obvious.

View File

@@ -208,7 +208,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
if (DBG) {
Slog.d(LOG_TAG, "External suggestion received."
+ " currentUserConfig=" + currentUserConfig
+ " newSuggestion=" + suggestion);
+ " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
@@ -230,7 +230,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
if (DBG) {
Slog.d(LOG_TAG, "GNSS suggestion received."
+ " currentUserConfig=" + currentUserConfig
+ " newSuggestion=" + suggestion);
+ " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
@@ -289,7 +289,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
if (DBG) {
Slog.d(LOG_TAG, "Network suggestion received."
+ " currentUserConfig=" + currentUserConfig
+ " newSuggestion=" + suggestion);
+ " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
@@ -311,7 +311,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
// Now perform auto time detection. The new suggestion may be used to modify the system
// clock.
String reason = "New network time suggested. timeSuggestion=" + suggestion;
String reason = "New network time suggested. suggestion=" + suggestion;
doAutoTimeDetection(reason);
}
@@ -396,29 +396,29 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
@Override
public synchronized void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion) {
public synchronized void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion suggestion) {
// Empty time suggestion means that telephony network connectivity has been lost.
// The passage of time is relentless, and we don't expect our users to use a time machine,
// so we can continue relying on previous suggestions when we lose connectivity. This is
// unlike time zone, where a user may lose connectivity when boarding a flight and where we
// do want to "forget" old signals. Suggestions that are too old are discarded later in the
// detection algorithm.
if (timeSuggestion.getUnixEpochTime() == null) {
if (suggestion.getUnixEpochTime() == null) {
return;
}
if (!validateAutoSuggestionTime(timeSuggestion.getUnixEpochTime(), timeSuggestion)) {
if (!validateAutoSuggestionTime(suggestion.getUnixEpochTime(), suggestion)) {
return;
}
// Perform input filtering and record the validated suggestion against the slotIndex.
if (!storeTelephonySuggestion(timeSuggestion)) {
if (!storeTelephonySuggestion(suggestion)) {
return;
}
// Now perform auto time detection. The new suggestion may be used to modify the system
// clock.
String reason = "New telephony time suggested. timeSuggestion=" + timeSuggestion;
String reason = "New telephony time suggested. suggestion=" + suggestion;
doAutoTimeDetection(reason);
}
@@ -623,19 +623,19 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
+ ", detectionReason=" + detectionReason;
}
} else if (origin == ORIGIN_GNSS) {
GnssTimeSuggestion gnssTimeSuggestion = findLatestValidGnssSuggestion();
if (gnssTimeSuggestion != null) {
newUnixEpochTime = gnssTimeSuggestion.getUnixEpochTime();
GnssTimeSuggestion gnssSuggestion = findLatestValidGnssSuggestion();
if (gnssSuggestion != null) {
newUnixEpochTime = gnssSuggestion.getUnixEpochTime();
cause = "Found good gnss suggestion."
+ ", gnssTimeSuggestion=" + gnssTimeSuggestion
+ ", gnssSuggestion=" + gnssSuggestion
+ ", detectionReason=" + detectionReason;
}
} else if (origin == ORIGIN_EXTERNAL) {
ExternalTimeSuggestion externalTimeSuggestion = findLatestValidExternalSuggestion();
if (externalTimeSuggestion != null) {
newUnixEpochTime = externalTimeSuggestion.getUnixEpochTime();
ExternalTimeSuggestion externalSuggestion = findLatestValidExternalSuggestion();
if (externalSuggestion != null) {
newUnixEpochTime = externalSuggestion.getUnixEpochTime();
cause = "Found good external suggestion."
+ ", externalTimeSuggestion=" + externalTimeSuggestion
+ ", externalSuggestion=" + externalSuggestion
+ ", detectionReason=" + detectionReason;
}
} else {
@@ -742,14 +742,14 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
private static int scoreTelephonySuggestion(
@ElapsedRealtimeLong long elapsedRealtimeMillis,
@NonNull TelephonyTimeSuggestion timeSuggestion) {
@NonNull TelephonyTimeSuggestion suggestion) {
// Validate first.
UnixEpochTime unixEpochTime = timeSuggestion.getUnixEpochTime();
UnixEpochTime unixEpochTime = suggestion.getUnixEpochTime();
if (!validateSuggestionUnixEpochTime(elapsedRealtimeMillis, unixEpochTime)) {
Slog.w(LOG_TAG, "Existing suggestion found to be invalid"
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ ", timeSuggestion=" + timeSuggestion);
+ ", suggestion=" + suggestion);
return TELEPHONY_INVALID_SCORE;
}

View File

@@ -18,6 +18,7 @@ package com.android.server.timezonedetector;
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -27,6 +28,7 @@ import com.android.server.SystemTimeZone;
import com.android.server.SystemTimeZone.TimeZoneConfidence;
import java.io.PrintWriter;
import java.util.Objects;
/**
* The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}.
@@ -35,7 +37,10 @@ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment
private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
EnvironmentImpl() {
@NonNull private final Handler mHandler;
EnvironmentImpl(@NonNull Handler handler) {
mHandler = Objects.requireNonNull(handler);
}
@Override
@@ -72,4 +77,9 @@ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment
public void dumpDebugLog(@NonNull PrintWriter printWriter) {
SystemTimeZone.dump(printWriter);
}
@Override
public void runAsync(@NonNull Runnable runnable) {
mHandler.post(runnable);
}
}

View File

@@ -56,7 +56,7 @@ public interface TimeZoneDetectorInternal {
* valid but does not change the time zone because it matches the current device time zone is
* considered accepted.
*/
boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion);
boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion suggestion);
/**
* Handles the supplied {@link LocationAlgorithmEvent}. The detector may ignore the event based

View File

@@ -66,13 +66,13 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter
}
@Override
public boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
Objects.requireNonNull(timeZoneSuggestion);
public boolean setManualTimeZoneForDpm(@NonNull ManualTimeZoneSuggestion suggestion) {
Objects.requireNonNull(suggestion);
int currentUserId = mCurrentUserIdentityInjector.getCurrentUserId();
final boolean bypassUserPolicyChecks = true;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
currentUserId, timeZoneSuggestion, bypassUserPolicyChecks);
currentUserId, suggestion, bypassUserPolicyChecks);
}
@Override

View File

@@ -346,7 +346,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
}
@Override
public boolean setManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
public boolean setManualTimeZone(@NonNull ManualTimeZoneSuggestion suggestion) {
enforceManageTimeZoneDetectorPermission();
// This calls suggestManualTimeZone() as the logic is identical, it only differs in the
@@ -356,34 +356,34 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
try {
final boolean bypassUserPolicyChecks = false;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
userId, timeZoneSuggestion, bypassUserPolicyChecks);
userId, suggestion, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@Override
public boolean suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
public boolean suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion suggestion) {
enforceSuggestManualTimeZonePermission();
Objects.requireNonNull(timeZoneSuggestion);
Objects.requireNonNull(suggestion);
int userId = mCallerIdentityInjector.getCallingUserId();
final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
final boolean bypassUserPolicyChecks = false;
return mTimeZoneDetectorStrategy.suggestManualTimeZone(
userId, timeZoneSuggestion, bypassUserPolicyChecks);
userId, suggestion, bypassUserPolicyChecks);
} finally {
mCallerIdentityInjector.restoreCallingIdentity(token);
}
}
@Override
public void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion timeZoneSuggestion) {
public void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion) {
enforceSuggestTelephonyTimeZonePermission();
Objects.requireNonNull(timeZoneSuggestion);
Objects.requireNonNull(suggestion);
mHandler.post(() -> mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion));
mHandler.post(() -> mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(suggestion));
}
boolean isTelephonyTimeZoneDetectionSupported() {

View File

@@ -102,6 +102,11 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
* Dumps the time zone debug log to the supplied {@link PrintWriter}.
*/
void dumpDebugLog(PrintWriter printWriter);
/**
* Requests that the supplied runnable be invoked asynchronously.
*/
void runAsync(@NonNull Runnable runnable);
}
private static final String LOG_TAG = TimeZoneDetectorService.TAG;
@@ -200,10 +205,6 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
@NonNull
private final ServiceConfigAccessor mServiceConfigAccessor;
/** The handler used for asynchronous operations triggered by this. */
@NonNull
private final Handler mStateChangeHandler;
@GuardedBy("this")
@NonNull private final List<StateChangeListener> mStateChangeListeners = new ArrayList<>();
@@ -246,17 +247,16 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
public static TimeZoneDetectorStrategyImpl create(
@NonNull Handler handler, @NonNull ServiceConfigAccessor serviceConfigAccessor) {
Environment environment = new EnvironmentImpl();
return new TimeZoneDetectorStrategyImpl(serviceConfigAccessor, handler, environment);
Environment environment = new EnvironmentImpl(handler);
return new TimeZoneDetectorStrategyImpl(serviceConfigAccessor, environment);
}
@VisibleForTesting
public TimeZoneDetectorStrategyImpl(
@NonNull ServiceConfigAccessor serviceConfigAccessor,
@NonNull Handler handler, @NonNull Environment environment) {
@NonNull Environment environment) {
mEnvironment = Objects.requireNonNull(environment);
mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
mStateChangeHandler = Objects.requireNonNull(handler);
// Start with telephony fallback enabled.
mTelephonyTimeZoneFallbackEnabled =
@@ -349,7 +349,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
private void notifyStateChangeListenersAsynchronously() {
for (StateChangeListener listener : mStateChangeListeners) {
// This is queuing asynchronous notification, so no need to surrender the "this" lock.
mStateChangeHandler.post(listener::onChange);
mEnvironment.runAsync(listener::onChange);
}
}
@@ -479,7 +479,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
if (DBG) {
Slog.d(LOG_TAG, "Telephony suggestion received. currentUserConfig=" + currentUserConfig
+ " newSuggestion=" + suggestion);
+ " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);

View File

@@ -48,17 +48,17 @@ public class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
}
@Override
public void suggestTelephonyTime(TelephonyTimeSuggestion timeSuggestion) {
public void suggestTelephonyTime(TelephonyTimeSuggestion suggestion) {
}
@Override
public boolean suggestManualTime(@UserIdInt int userId, ManualTimeSuggestion timeSuggestion,
public boolean suggestManualTime(@UserIdInt int userId, ManualTimeSuggestion suggestion,
boolean bypassUserPolicyChecks) {
return true;
}
@Override
public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
public void suggestNetworkTime(NetworkTimeSuggestion suggestion) {
}
@Override
@@ -71,11 +71,11 @@ public class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
}
@Override
public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
public void suggestGnssTime(GnssTimeSuggestion suggestion) {
}
@Override
public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
public void suggestExternalTime(ExternalTimeSuggestion suggestion) {
}
@Override

View File

@@ -67,18 +67,17 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
import android.os.HandlerThread;
import android.service.timezone.TimeZoneProviderStatus;
import com.android.server.SystemTimeZone.TimeZoneConfidence;
import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -208,8 +207,6 @@ public class TimeZoneDetectorStrategyImplTest {
private FakeServiceConfigAccessor mFakeServiceConfigAccessorSpy;
private FakeEnvironment mFakeEnvironment;
private HandlerThread mHandlerThread;
private TestHandler mTestHandler;
private TimeZoneDetectorStrategyImpl mTimeZoneDetectorStrategy;
@@ -220,18 +217,8 @@ public class TimeZoneDetectorStrategyImplTest {
mFakeServiceConfigAccessorSpy.initializeCurrentUserConfiguration(
CONFIG_AUTO_DISABLED_GEO_DISABLED);
// Create a thread + handler for processing the work that the strategy posts.
mHandlerThread = new HandlerThread("TimeZoneDetectorStrategyImplTest");
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
mTimeZoneDetectorStrategy = new TimeZoneDetectorStrategyImpl(
mFakeServiceConfigAccessorSpy, mTestHandler, mFakeEnvironment);
}
@After
public void tearDown() throws Exception {
mHandlerThread.quit();
mHandlerThread.join();
mFakeServiceConfigAccessorSpy, mFakeEnvironment);
}
@Test
@@ -1723,6 +1710,7 @@ public class TimeZoneDetectorStrategyImplTest {
private final TestState<String> mTimeZoneId = new TestState<>();
private final TestState<Integer> mTimeZoneConfidence = new TestState<>();
private final List<Runnable> mAsyncRunnables = new ArrayList<>();
private @ElapsedRealtimeLong long mElapsedRealtimeMillis;
FakeEnvironment() {
@@ -1795,12 +1783,24 @@ public class TimeZoneDetectorStrategyImplTest {
public void dumpDebugLog(PrintWriter printWriter) {
// No-op for tests
}
@Override
public void runAsync(Runnable runnable) {
mAsyncRunnables.add(runnable);
}
public void runAsyncRunnables() {
for (Runnable runnable : mAsyncRunnables) {
runnable.run();
}
mAsyncRunnables.clear();
}
}
private void assertStateChangeNotificationsSent(
TestStateChangeListener stateChangeListener, int expectedCount) {
// State change notifications are asynchronous, so we have to wait.
mTestHandler.waitForMessagesToBeProcessed();
// The fake environment needs to be told to run posted work.
mFakeEnvironment.runAsyncRunnables();
stateChangeListener.assertNotificationsReceivedAndReset(expectedCount);
}