Merge "A mixed bag of tidy ups / refactoring"
This commit is contained in:
@@ -24,18 +24,4 @@ public interface Dumpable {
|
||||
|
||||
/** Dump internal state. */
|
||||
void dump(@NonNull IndentingPrintWriter pw, @Nullable String[] args);
|
||||
|
||||
/**
|
||||
* An interface that can be used expose when one component allows another to be registered so
|
||||
* that it is dumped at the same time.
|
||||
*/
|
||||
interface Container {
|
||||
|
||||
/**
|
||||
* Registers the supplied {@link Dumpable}. When the implementation is dumped
|
||||
* {@link Dumpable#dump(IndentingPrintWriter, String[])} should be called on the
|
||||
* {@code dumpable}.
|
||||
*/
|
||||
void addDumpable(@NonNull Dumpable dumpable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment
|
||||
mLocationManager = context.getSystemService(LocationManager.class);
|
||||
mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);
|
||||
|
||||
// Wire up the config change listeners. All invocations are performed on the mHandler
|
||||
// thread.
|
||||
// Wire up the config change listeners for anything that could affect the return values from
|
||||
// this object. All listener invocations are performed on the mHandler thread.
|
||||
|
||||
// Listen for the user changing / the user's location mode changing.
|
||||
IntentFilter filter = new IntentFilter();
|
||||
@@ -88,25 +88,19 @@ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment
|
||||
|
||||
// Add async callbacks for global settings being changed.
|
||||
ContentResolver contentResolver = mContext.getContentResolver();
|
||||
ContentObserver contentObserver = new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
handleConfigChangeOnHandlerThread();
|
||||
}
|
||||
};
|
||||
contentResolver.registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
handleConfigChangeOnHandlerThread();
|
||||
}
|
||||
});
|
||||
Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, contentObserver);
|
||||
|
||||
// Add async callbacks for user scoped location settings being changed.
|
||||
contentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED),
|
||||
true,
|
||||
new ContentObserver(mHandler) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
handleConfigChangeOnHandlerThread();
|
||||
}
|
||||
}, UserHandle.USER_ALL);
|
||||
true, contentObserver, UserHandle.USER_ALL);
|
||||
}
|
||||
|
||||
private void handleConfigChangeOnHandlerThread() {
|
||||
|
||||
@@ -39,12 +39,11 @@ import java.util.StringTokenizer;
|
||||
* <ul>
|
||||
* <li>{@code effectiveFromElapsedMillis}: The time according to the elapsed realtime clock
|
||||
* after which the suggestion should be considered in effect. For example, when a location fix
|
||||
* used to establish the time zone is old, then the suggestion
|
||||
* {@code effectiveFromElapsedMillis} should reflect this and indicates the time zone that was
|
||||
* detected / correct at that time. The time_zone_detector is only expected to use the latest
|
||||
* suggestion it has received, and so later suggestions always counteract previous suggestions.
|
||||
* The inclusion of this information means that the time_zone_detector can take into account
|
||||
* ordering when comparing suggestions from different sources.
|
||||
* used to establish the time zone is old, then the suggestion's {@code
|
||||
* effectiveFromElapsedMillis} should reflect this and indicates the time zone that was
|
||||
* detected / correct at that time. The inclusion of this information means that the
|
||||
* time_zone_detector <em>may</em> take this into account if comparing suggestions or signals
|
||||
* from different sources.
|
||||
* <br />Note: Because the times can be back-dated, time_zone_detector can be sent a sequence of
|
||||
* suggestions where the {@code effectiveFromElapsedMillis} of later suggestions is before
|
||||
* the {@code effectiveFromElapsedMillis} of an earlier one.</li>
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.annotation.StringDef;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -64,11 +63,11 @@ public final class ServiceConfigAccessor {
|
||||
public static final @ProviderMode String PROVIDER_MODE_ENABLED = "enabled";
|
||||
|
||||
/**
|
||||
* Device config keys that affect the {@link TimeZoneDetectorService} service and {@link
|
||||
* com.android.server.timezonedetector.location.LocationTimeZoneManagerService}.
|
||||
* Device config keys that can affect {@link
|
||||
* com.android.server.timezonedetector.location.LocationTimeZoneManagerService} behavior.
|
||||
*/
|
||||
private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet(
|
||||
new ArraySet<>(new String[] {
|
||||
private static final Set<String> LOCATION_TIME_ZONE_MANAGER_SERVER_FLAGS_KEYS_TO_WATCH =
|
||||
Collections.unmodifiableSet(new ArraySet<>(new String[] {
|
||||
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED,
|
||||
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
|
||||
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
|
||||
@@ -94,14 +93,6 @@ public final class ServiceConfigAccessor {
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
|
||||
/**
|
||||
* An ultimate "feature switch" for location-based time zone detection. If this is
|
||||
* {@code false}, the device cannot support the feature without a config change or a reboot:
|
||||
* This affects what services are started on boot to minimize expense when the feature is not
|
||||
* wanted.
|
||||
*/
|
||||
private final boolean mGeoDetectionFeatureSupportedInConfig;
|
||||
|
||||
@NonNull private final ServerFlags mServerFlags;
|
||||
|
||||
/**
|
||||
@@ -148,14 +139,6 @@ public final class ServiceConfigAccessor {
|
||||
private ServiceConfigAccessor(@NonNull Context context) {
|
||||
mContext = Objects.requireNonNull(context);
|
||||
|
||||
// The config value is expected to be the main feature flag. Platform developers can also
|
||||
// force enable the feature using a persistent system property. Because system properties
|
||||
// can change, this value is cached and only changes on reboot.
|
||||
mGeoDetectionFeatureSupportedInConfig = context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection)
|
||||
|| SystemProperties.getBoolean(
|
||||
"persist.sys.location_time_zone_detection_feature_supported", false);
|
||||
|
||||
mServerFlags = ServerFlags.getInstance(mContext);
|
||||
}
|
||||
|
||||
@@ -170,14 +153,15 @@ public final class ServiceConfigAccessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener that will be called when server flags related to this class change. The
|
||||
* callbacks are delivered on the main looper thread.
|
||||
* Adds a listener that will be called when server flags related to location_time_zone_manager
|
||||
* change. The callbacks are delivered on the main looper thread.
|
||||
*
|
||||
* <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
|
||||
* method.
|
||||
*/
|
||||
public void addListener(@NonNull ConfigurationChangeListener listener) {
|
||||
mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH);
|
||||
public void addLocationTimeZoneManagerConfigListener(
|
||||
@NonNull ConfigurationChangeListener listener) {
|
||||
mServerFlags.addListener(listener, LOCATION_TIME_ZONE_MANAGER_SERVER_FLAGS_KEYS_TO_WATCH);
|
||||
}
|
||||
|
||||
/** Returns {@code true} if any form of automatic time zone detection is supported. */
|
||||
@@ -197,11 +181,19 @@ public final class ServiceConfigAccessor {
|
||||
/**
|
||||
* Returns {@code true} if the location-based time zone detection feature can be supported on
|
||||
* this device at all according to config. When {@code false}, implies that various other
|
||||
* location-based settings will be turned off or rendered meaningless. Typically {@link
|
||||
* #isGeoTimeZoneDetectionFeatureSupported()} should be used instead.
|
||||
* location-based services and settings will be turned off or rendered meaningless.
|
||||
*
|
||||
* <p>This is the ultimate "feature switch" for location-based time zone detection. If this is
|
||||
* {@code false}, the device cannot support the feature without a config change or a reboot:
|
||||
* This affects what services are started on boot to minimize expense when the feature is not
|
||||
* wanted.
|
||||
*
|
||||
* Typically {@link #isGeoTimeZoneDetectionFeatureSupported()} should be used except during
|
||||
* boot.
|
||||
*/
|
||||
public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() {
|
||||
return mGeoDetectionFeatureSupportedInConfig;
|
||||
return mContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +205,7 @@ public final class ServiceConfigAccessor {
|
||||
// 1) Be turned on in config.
|
||||
// 2) Not be turned off via a server flag.
|
||||
// 3) There must be at least one location time zone provider enabled / configured.
|
||||
return mGeoDetectionFeatureSupportedInConfig
|
||||
return isGeoTimeZoneDetectionFeatureSupportedInConfig()
|
||||
&& isGeoTimeZoneDetectionFeatureSupportedInternal()
|
||||
&& atLeastOneProviderIsEnabled();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import android.annotation.NonNull;
|
||||
* <p>The methods on this class can be called from any thread.
|
||||
* @hide
|
||||
*/
|
||||
public interface TimeZoneDetectorInternal extends Dumpable.Container {
|
||||
public interface TimeZoneDetectorInternal {
|
||||
|
||||
/** Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed. */
|
||||
void addConfigurationListener(@NonNull ConfigurationChangeListener listener);
|
||||
|
||||
@@ -56,11 +56,6 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDumpable(@NonNull Dumpable dumpable) {
|
||||
mTimeZoneDetectorStrategy.addDumpable(dumpable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConfigurationListener(ConfigurationChangeListener listener) {
|
||||
synchronized (mConfigurationListeners) {
|
||||
|
||||
@@ -45,6 +45,8 @@ import com.android.server.SystemService;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -59,6 +61,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
implements IBinder.DeathRecipient {
|
||||
|
||||
static final String TAG = "time_zone_detector";
|
||||
static final boolean DBG = false;
|
||||
|
||||
/**
|
||||
* Handles the service lifecycle for {@link TimeZoneDetectorService} and
|
||||
@@ -112,17 +115,22 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
*/
|
||||
@GuardedBy("mListeners")
|
||||
@NonNull
|
||||
private final ArrayMap<IBinder, ITimeZoneDetectorListener> mListeners =
|
||||
new ArrayMap<>();
|
||||
private final ArrayMap<IBinder, ITimeZoneDetectorListener> mListeners = new ArrayMap<>();
|
||||
|
||||
/**
|
||||
* References to components that should be dumped when {@link
|
||||
* #dump(FileDescriptor, PrintWriter, String[])} is called on the service.
|
||||
*/
|
||||
@GuardedBy("mDumpables")
|
||||
private final List<Dumpable> mDumpables = new ArrayList<>();
|
||||
|
||||
private static TimeZoneDetectorService create(
|
||||
@NonNull Context context, @NonNull Handler handler,
|
||||
@NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
|
||||
|
||||
CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL;
|
||||
TimeZoneDetectorService service = new TimeZoneDetectorService(
|
||||
return new TimeZoneDetectorService(
|
||||
context, handler, callerIdentityInjector, timeZoneDetectorStrategy);
|
||||
return service;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -251,7 +259,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
if (!removedListener) {
|
||||
Slog.w(TAG, "Notified of binder death for who=" + who
|
||||
+ ", but did not remove any listeners."
|
||||
+ " mConfigurationListeners=" + mListeners);
|
||||
+ " mListeners=" + mListeners);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,8 +322,17 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
boolean isGeoTimeZoneDetectionSupported() {
|
||||
enforceManageTimeZoneDetectorPermission();
|
||||
|
||||
return ServiceConfigAccessor.getInstance(mContext)
|
||||
.isGeoTimeZoneDetectionFeatureSupported();
|
||||
return ServiceConfigAccessor.getInstance(mContext).isGeoTimeZoneDetectionFeatureSupported();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the supplied {@link Dumpable} for dumping. When the service is dumped
|
||||
* {@link Dumpable#dump(IndentingPrintWriter, String[])} will be called on the {@code dumpable}.
|
||||
*/
|
||||
void addDumpable(@NonNull Dumpable dumpable) {
|
||||
synchronized (mDumpables) {
|
||||
mDumpables.add(dumpable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -325,6 +342,13 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
|
||||
|
||||
IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
|
||||
mTimeZoneDetectorStrategy.dump(ipw, args);
|
||||
|
||||
synchronized (mDumpables) {
|
||||
for (Dumpable dumpable : mDumpables) {
|
||||
dumpable.dump(ipw, args);
|
||||
}
|
||||
}
|
||||
|
||||
ipw.flush();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import android.util.IndentingPrintWriter;
|
||||
* Suggestions are acted on or ignored as needed, depending on previously received suggestions and
|
||||
* the current user's configuration (see {@link ConfigurationInternal}).
|
||||
*
|
||||
* <p>Devices can have zero, one or two automatic time zone detection algorithm available at any
|
||||
* <p>Devices can have zero, one or two automatic time zone detection algorithms available at any
|
||||
* point in time.
|
||||
*
|
||||
* <p>The two automatic detection algorithms supported are "telephony" and "geolocation". Algorithm
|
||||
@@ -63,6 +63,13 @@ import android.util.IndentingPrintWriter;
|
||||
* have an empty suggestion submitted in order to "withdraw" their previous suggestion otherwise it
|
||||
* will remain in use.
|
||||
*
|
||||
* <p>The strategy uses only one algorithm at a time and does not attempt consensus even when
|
||||
* more than one is available on a device. This "use only one" behavior is deliberate as different
|
||||
* algorithms have edge cases and blind spots that lead to incorrect answers or uncertainty;
|
||||
* different algorithms aren't guaranteed to agree, and algorithms may frequently lose certainty as
|
||||
* users enter areas without the necessary signals. Ultimately, with no perfect algorithm available,
|
||||
* the user is left to choose which algorithm works best for their circumstances.
|
||||
*
|
||||
* <p>Threading:
|
||||
*
|
||||
* <p>Suggestion calls with a void return type may be handed off to a separate thread and handled
|
||||
@@ -73,7 +80,7 @@ import android.util.IndentingPrintWriter;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
|
||||
public interface TimeZoneDetectorStrategy extends Dumpable {
|
||||
|
||||
/**
|
||||
* Adds a listener that will be triggered whenever {@link ConfigurationInternal} may have
|
||||
|
||||
@@ -98,7 +98,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
}
|
||||
|
||||
private static final String LOG_TAG = TimeZoneDetectorService.TAG;
|
||||
private static final boolean DBG = false;
|
||||
private static final boolean DBG = TimeZoneDetectorService.DBG;
|
||||
|
||||
/**
|
||||
* The abstract score for an empty or invalid telephony suggestion.
|
||||
@@ -168,7 +168,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
|
||||
@GuardedBy("this")
|
||||
@NonNull
|
||||
private List<ConfigurationChangeListener> mConfigChangeListeners = new ArrayList<>();
|
||||
private final List<ConfigurationChangeListener> mConfigChangeListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* A log that records the decisions / decision metadata that affected the device's time zone.
|
||||
@@ -183,7 +183,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
* to be stable.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private ArrayMapWithHistory<Integer, QualifiedTelephonyTimeZoneSuggestion>
|
||||
private final ArrayMapWithHistory<Integer, QualifiedTelephonyTimeZoneSuggestion>
|
||||
mTelephonySuggestionsBySlotIndex =
|
||||
new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
|
||||
|
||||
@@ -192,18 +192,16 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
* detection then the latest suggestion is cleared.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion =
|
||||
private final ReferenceWithHistory<GeolocationTimeZoneSuggestion> mLatestGeoLocationSuggestion =
|
||||
new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
|
||||
|
||||
/**
|
||||
* The latest manual suggestion received.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
private ReferenceWithHistory<ManualTimeZoneSuggestion> mLatestManualSuggestion =
|
||||
private final ReferenceWithHistory<ManualTimeZoneSuggestion> mLatestManualSuggestion =
|
||||
new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
|
||||
|
||||
@GuardedBy("this")
|
||||
private final List<Dumpable> mDumpables = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link TimeZoneDetectorStrategyImpl}.
|
||||
@@ -293,7 +291,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
|
||||
if (currentUserConfig.getGeoDetectionEnabledBehavior()) {
|
||||
// Only store a geolocation suggestion if geolocation detection is currently enabled.
|
||||
// See also clearGeolocationSuggestionIfNeeded().
|
||||
// See also handleConfigChanged(), which can clear mLatestGeoLocationSuggestion.
|
||||
// The suggestion's "effective from" time is ignored: we currently assume suggestions
|
||||
// are made in a sensible order and the most recent is always the best one to use.
|
||||
mLatestGeoLocationSuggestion.set(suggestion);
|
||||
|
||||
// Now perform auto time zone detection. The new suggestion may be used to modify the
|
||||
@@ -427,7 +427,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the right suggestions based on the current configuration.
|
||||
// Use the correct algorithm based on the user's current configuration.
|
||||
if (currentUserConfig.getGeoDetectionEnabledBehavior()) {
|
||||
doGeolocationTimeZoneDetection(detectionReason);
|
||||
} else {
|
||||
@@ -598,15 +598,6 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
Slog.d(LOG_TAG, "handleConfigChanged()");
|
||||
}
|
||||
|
||||
clearGeolocationSuggestionIfNeeded();
|
||||
|
||||
for (ConfigurationChangeListener listener : mConfigChangeListeners) {
|
||||
listener.onChange();
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("this")
|
||||
private void clearGeolocationSuggestionIfNeeded() {
|
||||
// This method is called whenever the user changes or the config for any user changes. We
|
||||
// don't know what happened, so we capture the current user's config, check to see if we
|
||||
// need to clear state associated with a previous user, and rerun detection.
|
||||
@@ -623,15 +614,17 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
// said it is ok to do so.
|
||||
mLatestGeoLocationSuggestion.set(null);
|
||||
mTimeZoneChangesLog.log(
|
||||
"clearGeolocationSuggestionIfNeeded: Cleared latest Geolocation suggestion.");
|
||||
"handleConfigChanged: Cleared latest Geolocation suggestion.");
|
||||
}
|
||||
|
||||
doAutoTimeZoneDetection(currentUserConfig, "clearGeolocationSuggestionIfNeeded()");
|
||||
}
|
||||
// The configuration change may have changed available suggestions or the way suggestions
|
||||
// are used, so re-run detection.
|
||||
doAutoTimeZoneDetection(currentUserConfig, "handleConfigChanged()");
|
||||
|
||||
@Override
|
||||
public synchronized void addDumpable(@NonNull Dumpable dumpable) {
|
||||
mDumpables.add(dumpable);
|
||||
// Pass on the signal to sub-components.
|
||||
for (ConfigurationChangeListener listener : mConfigChangeListeners) {
|
||||
listener.onChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -671,10 +664,6 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
|
||||
mTelephonySuggestionsBySlotIndex.dump(ipw);
|
||||
ipw.decreaseIndent(); // level 2
|
||||
ipw.decreaseIndent(); // level 1
|
||||
|
||||
for (Dumpable dumpable : mDumpables) {
|
||||
dumpable.dump(ipw, args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -168,7 +168,8 @@ public class LocationTimeZoneManagerService extends Binder {
|
||||
// According to the SystemService docs: All lifecycle methods are called from the system
|
||||
// server's main looper thread.
|
||||
void onSystemReady() {
|
||||
mServiceConfigAccessor.addListener(this::handleServiceConfigurationChangedOnMainThread);
|
||||
mServiceConfigAccessor.addLocationTimeZoneManagerConfigListener(
|
||||
this::handleServiceConfigurationChangedOnMainThread);
|
||||
}
|
||||
|
||||
private void handleServiceConfigurationChangedOnMainThread() {
|
||||
|
||||
@@ -29,9 +29,6 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
|
||||
private ConfigurationChangeListener mConfigurationChangeListener;
|
||||
@@ -44,7 +41,6 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
private ManualTimeZoneSuggestion mLastManualSuggestion;
|
||||
private TelephonyTimeZoneSuggestion mLastTelephonySuggestion;
|
||||
private boolean mDumpCalled;
|
||||
private final List<Dumpable> mDumpables = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void addConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
|
||||
@@ -122,11 +118,6 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDumpable(Dumpable dumpable) {
|
||||
mDumpables.add(dumpable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(IndentingPrintWriter pw, String[] args) {
|
||||
mDumpCalled = true;
|
||||
@@ -159,8 +150,4 @@ class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
|
||||
void verifyDumpCalled() {
|
||||
assertTrue(mDumpCalled);
|
||||
}
|
||||
|
||||
void verifyHasDumpable(Dumpable expected) {
|
||||
assertTrue(mDumpables.contains(expected));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,16 +77,6 @@ public class TimeZoneDetectorInternalImplTest {
|
||||
mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDumpable() throws Exception {
|
||||
Dumpable stubbedDumpable = mock(Dumpable.class);
|
||||
|
||||
mTimeZoneDetectorInternal.addDumpable(stubbedDumpable);
|
||||
mTestHandler.assertTotalMessagesEnqueued(0);
|
||||
|
||||
mFakeTimeZoneDetectorStrategy.verifyHasDumpable(stubbedDumpable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddConfigurationListener() throws Exception {
|
||||
boolean[] changeCalled = new boolean[2];
|
||||
|
||||
@@ -60,12 +60,12 @@ public class TimeZoneDetectorServiceTest {
|
||||
private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234L;
|
||||
|
||||
private Context mMockContext;
|
||||
private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategy;
|
||||
|
||||
private TimeZoneDetectorService mTimeZoneDetectorService;
|
||||
private HandlerThread mHandlerThread;
|
||||
private TestHandler mTestHandler;
|
||||
private TestCallerIdentityInjector mTestCallerIdentityInjector;
|
||||
private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategy;
|
||||
|
||||
|
||||
@Before
|
||||
@@ -349,11 +349,15 @@ public class TimeZoneDetectorServiceTest {
|
||||
when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
|
||||
.thenReturn(PackageManager.PERMISSION_GRANTED);
|
||||
|
||||
Dumpable dumpable = mock(Dumpable.class);
|
||||
mTimeZoneDetectorService.addDumpable(dumpable);
|
||||
|
||||
PrintWriter pw = new PrintWriter(new StringWriter());
|
||||
mTimeZoneDetectorService.dump(null, pw, null);
|
||||
|
||||
verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
|
||||
mFakeTimeZoneDetectorStrategy.verifyDumpCalled();
|
||||
verify(dumpable).dump(any(), any());
|
||||
}
|
||||
|
||||
private static TimeZoneConfiguration createTimeZoneConfiguration(boolean autoDetectionEnabled) {
|
||||
|
||||
@@ -47,18 +47,15 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
|
||||
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
|
||||
import android.util.IndentingPrintWriter;
|
||||
|
||||
import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
@@ -66,8 +63,8 @@ import java.util.function.Function;
|
||||
*/
|
||||
public class TimeZoneDetectorStrategyImplTest {
|
||||
|
||||
/** A time zone used for initialization that does not occur elsewhere in tests. */
|
||||
private static final @UserIdInt int USER_ID = 9876;
|
||||
/** A time zone used for initialization that does not occur elsewhere in tests. */
|
||||
private static final String ARBITRARY_TIME_ZONE_ID = "Etc/UTC";
|
||||
private static final int SLOT_INDEX1 = 10000;
|
||||
private static final int SLOT_INDEX2 = 20000;
|
||||
@@ -790,7 +787,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(suggestion)
|
||||
.verifyTimeZoneChangedAndReset("Europe/London");
|
||||
.verifyTimeZoneChangedAndReset(suggestion);
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
@@ -815,7 +812,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(londonOnlySuggestion)
|
||||
.verifyTimeZoneChangedAndReset("Europe/London");
|
||||
.verifyTimeZoneChangedAndReset(londonOnlySuggestion);
|
||||
assertEquals(londonOnlySuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
|
||||
@@ -826,7 +823,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(parisOnlySuggestion)
|
||||
.verifyTimeZoneChangedAndReset("Europe/Paris");
|
||||
.verifyTimeZoneChangedAndReset(parisOnlySuggestion);
|
||||
assertEquals(parisOnlySuggestion,
|
||||
mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
|
||||
@@ -848,7 +845,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
|
||||
|
||||
script.simulateGeolocationTimeZoneSuggestion(suggestion)
|
||||
.verifyTimeZoneChangedAndReset("Europe/London");
|
||||
.verifyTimeZoneChangedAndReset(suggestion);
|
||||
|
||||
// Assert internal service state.
|
||||
assertEquals(suggestion, mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
@@ -903,7 +900,7 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
USER_ID, CONFIG_GEO_DETECTION_ENABLED, true /* expectedResult */)
|
||||
.verifyTimeZoneNotChanged()
|
||||
.simulateGeolocationTimeZoneSuggestion(geolocationSuggestion)
|
||||
.verifyTimeZoneChangedAndReset(geolocationSuggestion.getZoneIds().get(0));
|
||||
.verifyTimeZoneChangedAndReset(geolocationSuggestion);
|
||||
|
||||
// Changing the detection to disable geo detection should cause the device tz setting to
|
||||
// change to the telephony suggestion.
|
||||
@@ -914,28 +911,6 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
assertNull(mTimeZoneDetectorStrategy.getLatestGeolocationSuggestion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDumpable() {
|
||||
new Script()
|
||||
.initializeConfig(CONFIG_INT_AUTO_DISABLED_GEO_DISABLED)
|
||||
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
|
||||
|
||||
AtomicBoolean dumpCalled = new AtomicBoolean(false);
|
||||
class FakeDumpable implements Dumpable {
|
||||
@Override
|
||||
public void dump(IndentingPrintWriter pw, String[] args) {
|
||||
dumpCalled.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
mTimeZoneDetectorStrategy.addDumpable(new FakeDumpable());
|
||||
IndentingPrintWriter ipw = new IndentingPrintWriter(new StringWriter());
|
||||
String[] args = {"ArgOne", "ArgTwo"};
|
||||
mTimeZoneDetectorStrategy.dump(ipw, args);
|
||||
|
||||
assertTrue(dumpCalled.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateMetricsState() {
|
||||
ConfigurationInternal expectedInternalConfig = CONFIG_INT_AUTO_DISABLED_GEO_DISABLED;
|
||||
@@ -1254,6 +1229,14 @@ public class TimeZoneDetectorStrategyImplTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
Script verifyTimeZoneChangedAndReset(GeolocationTimeZoneSuggestion suggestion) {
|
||||
assertEquals("Only use this method with unambiguous geo suggestions",
|
||||
1, suggestion.getZoneIds().size());
|
||||
mFakeEnvironment.assertTimeZoneChangedTo(suggestion.getZoneIds().get(0));
|
||||
mFakeEnvironment.commitAllChanges();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the configuration has been changed to the expected value.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user