From 2856d9e52fa6c6e5045d5accb351282ed7989d88 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Fri, 5 Feb 2021 16:57:16 +0000 Subject: [PATCH] Improve server flags / add more server control Add more server flags that can be pushed to devices to influence geo detection service behavior. This renames DeviceConfig as ServerFlags and introduces an intermediary, the ServiceConfigAccessor, to hide details and handle changes to config values that need the location_time_zone_manager to restart. Simulating server flag changes example: adb shell cmd device_config put \ system_time primary_location_time_zone_provider_enabled_override false Inspecting manager / provider states: adb shell dump location_time_zone_manager The following manual tests were conducted to check the plumbing: Modifying settings behavior: adb shell cmd device_config put \ system_time location_time_zone_detection_setting_enabled_override true adb shell cmd device_config put \ system_time location_time_zone_detection_setting_enabled_override false adb shell cmd device_config delete \ system_time location_time_zone_detection_setting_enabled_override Disabling the feature / location_time_zone_manager: adb shell cmd device_config put \ system_time location_time_zone_detection_feature_supported false Enabling the feature / location_time_zone_manager: adb shell cmd device_config put \ system_time location_time_zone_detection_feature_supported true Note: "cmd device_config" doesn't allow multiple config keys to be changed at once, and any change to service config keys cause the location_time_zone_manager to restart. When changing multiple, set "location_time_zone_detection_feature_supported false" to stop the manager, and "location_time_zone_detection_feature_supported true" when all changes are done. Test: Manual testing (see above) Test: treehugger Bug: 178107773 Change-Id: I07b57add1ed47197587907b9f0a85f38acc0a76a --- .../app/time/LocationTimeZoneManager.java | 2 +- .../server/timedetector/DeviceConfig.java | 126 --------- .../server/timedetector/ServerFlags.java | 238 +++++++++++++++++ .../ConfigurationChangeListener.java | 5 +- .../ConfigurationInternal.java | 51 ++-- .../timezonedetector/EnvironmentImpl.java | 83 ++---- .../ServiceConfigAccessor.java | 249 ++++++++++++++++++ .../TimeZoneDetectorInternal.java | 13 +- .../TimeZoneDetectorService.java | 32 +-- .../TimeZoneDetectorStrategy.java | 10 +- .../TimeZoneDetectorStrategyImpl.java | 7 +- .../location/ControllerEnvironmentImpl.java | 31 +-- .../LocationTimeZoneManagerService.java | 166 +++++++----- .../LocationTimeZoneManagerShellCommand.java | 3 +- .../location/TimeZoneProviderRequest.java | 2 - .../ConfigurationInternalTest.java | 16 +- .../TimeZoneDetectorServiceTest.java | 4 +- .../TimeZoneDetectorStrategyImplTest.java | 28 +- .../location/TestSupport.java | 4 +- 19 files changed, 707 insertions(+), 363 deletions(-) delete mode 100644 services/core/java/com/android/server/timedetector/DeviceConfig.java create mode 100644 services/core/java/com/android/server/timedetector/ServerFlags.java create mode 100644 services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java diff --git a/core/java/android/app/time/LocationTimeZoneManager.java b/core/java/android/app/time/LocationTimeZoneManager.java index 71a800f2085ee..066aadae14760 100644 --- a/core/java/android/app/time/LocationTimeZoneManager.java +++ b/core/java/android/app/time/LocationTimeZoneManager.java @@ -37,7 +37,7 @@ public final class LocationTimeZoneManager { /** * The name of the service for shell commands */ - public static final String SHELL_COMMAND_SERVICE_NAME = "location_time_zone_manager"; + public static final String SERVICE_NAME = "location_time_zone_manager"; /** * A shell command that starts the service (after stop). diff --git a/services/core/java/com/android/server/timedetector/DeviceConfig.java b/services/core/java/com/android/server/timedetector/DeviceConfig.java deleted file mode 100644 index 7b9ad0f531aae..0000000000000 --- a/services/core/java/com/android/server/timedetector/DeviceConfig.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.timedetector; - -import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.StringDef; - -import java.time.Duration; -import java.util.concurrent.Executor; - -/** - * A helper class for reading / monitoring the {@link - * android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME} namespace for server-configured flags. - */ -public final class DeviceConfig { - - /** - * An annotation used to indicate when a {@link - * android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME} key is required. - * - *

Note that the com.android.geotz module deployment of the Offline LocationTimeZoneProvider - * also shares the {@link android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME}, and uses the - * prefix "geotz_" on all of its key strings. - */ - @StringDef(prefix = "KEY_", value = { - KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED, - KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT, - KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS, - KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS, - KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS, - }) - @interface DeviceConfigKey {} - - /** - * The key to force location time zone detection on for a device. Only intended for use during - * release testing with droidfooders. The user can still disable the feature by turning off the - * master location switch, or disabling automatic time zone detection. - */ - @DeviceConfigKey - public static final String KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED = - "force_location_time_zone_detection_enabled"; - - /** - * The key for the default value used to determine whether location time zone detection is - * enabled when the user hasn't explicitly set it yet. - */ - @DeviceConfigKey - public static final String KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT = - "location_time_zone_detection_enabled_default"; - - /** - * The key for the minimum delay after location time zone detection has been enabled before the - * location time zone manager can report it is uncertain about the time zone. - */ - @DeviceConfigKey - public static final String KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS = - "location_time_zone_detection_uncertainty_delay_millis"; - - /** - * The key for the timeout passed to a location time zone provider that tells it how long it has - * to provide an explicit first suggestion without being declared uncertain. - */ - @DeviceConfigKey - public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS = - "ltpz_init_timeout_millis"; - - /** - * The key for the extra time added to {@link - * #KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS} by the location time zone - * manager before the location time zone provider will actually be declared uncertain. - */ - @DeviceConfigKey - public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS = - "ltpz_init_timeout_fuzz_millis"; - - /** Creates an instance. */ - public DeviceConfig() {} - - /** Adds a listener for the system_time namespace. */ - public void addListener( - @NonNull Executor handlerExecutor, @NonNull Runnable listener) { - android.provider.DeviceConfig.addOnPropertiesChangedListener( - NAMESPACE_SYSTEM_TIME, - handlerExecutor, - properties -> listener.run()); - } - - /** - * Returns a boolean value from {@link android.provider.DeviceConfig} from the system_time - * namespace, or {@code defaultValue} if there is no explicit value set. - */ - public boolean getBoolean(@DeviceConfigKey String key, boolean defaultValue) { - return android.provider.DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue); - } - - /** - * Returns a positive duration from {@link android.provider.DeviceConfig} from the system_time - * namespace, or {@code defaultValue} if there is no explicit value set. - */ - @Nullable - public Duration getDurationFromMillis( - @DeviceConfigKey String key, @Nullable Duration defaultValue) { - long deviceConfigValue = - android.provider.DeviceConfig.getLong(NAMESPACE_SYSTEM_TIME, key, -1); - if (deviceConfigValue < 0) { - return defaultValue; - } - return Duration.ofMillis(deviceConfigValue); - } -} diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java new file mode 100644 index 0000000000000..8819b371b2250 --- /dev/null +++ b/services/core/java/com/android/server/timedetector/ServerFlags.java @@ -0,0 +1,238 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.timedetector; + +import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StringDef; +import android.content.Context; +import android.provider.DeviceConfig; +import android.util.ArrayMap; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.timezonedetector.ConfigurationChangeListener; +import com.android.server.timezonedetector.ServiceConfigAccessor; + +import java.time.Duration; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * A helper class for reading / monitoring the {@link DeviceConfig#NAMESPACE_SYSTEM_TIME} namespace + * for server-configured flags. + */ +public final class ServerFlags { + + private static final Optional OPTIONAL_TRUE = Optional.of(true); + private static final Optional OPTIONAL_FALSE = Optional.of(false); + + /** + * An annotation used to indicate when a {@link DeviceConfig#NAMESPACE_SYSTEM_TIME} key is + * required. + * + *

Note that the com.android.geotz module deployment of the Offline LocationTimeZoneProvider + * also shares the {@link DeviceConfig#NAMESPACE_SYSTEM_TIME}, and uses the + * prefix "geotz_" on all of its key strings. + */ + @StringDef(prefix = "KEY_", value = { + KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED, + KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE, + KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE, + KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS, + KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS, + KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS, + KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE, + KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, + }) + @interface DeviceConfigKey {} + + /** + * Controls whether the location time zone manager service will started. Only observed if + * the device build is configured to support location-based time zone detection. See + * {@link ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupportedInConfig()} and {@link + * ServiceConfigAccessor#isGeoTimeZoneDetectionFeatureSupported()}. + */ + @DeviceConfigKey + public static final String KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED = + "location_time_zone_detection_feature_supported"; + + /** + * The key for the server flag that can override the device config for whether the primary + * location time zone provider is enabled or disabled. + */ + @DeviceConfigKey + public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE = + "primary_location_time_zone_provider_enabled_override"; + + /** + * The key for the server flag that can override the device config for whether the secondary + * location time zone provider is enabled or disabled. + */ + @DeviceConfigKey + public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE = + "secondary_location_time_zone_provider_enabled_override"; + + /** + * The key for the minimum delay after location time zone detection has been enabled before the + * location time zone manager can report it is uncertain about the time zone. + */ + @DeviceConfigKey + public static final String KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS = + "location_time_zone_detection_uncertainty_delay_millis"; + + /** + * The key for the timeout passed to a location time zone provider that tells it how long it has + * to provide an explicit first suggestion without being declared uncertain. + */ + @DeviceConfigKey + public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS = + "ltpz_init_timeout_millis"; + + /** + * The key for the extra time added to {@link + * #KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS} by the location time zone + * manager before the location time zone provider will actually be declared uncertain. + */ + @DeviceConfigKey + public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS = + "ltpz_init_timeout_fuzz_millis"; + + /** + * The key for the server flag that can override location time zone detection being enabled for + * a user. Only intended for use during release testing with droidfooders. The user can still + * disable the feature by turning off the master location switch, or by disabling automatic time + * zone detection. + */ + @DeviceConfigKey + public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE = + "location_time_zone_detection_setting_enabled_override"; + + /** + * The key for the default value used to determine whether location time zone detection is + * enabled when the user hasn't explicitly set it yet. + */ + @DeviceConfigKey + public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT = + "location_time_zone_detection_setting_enabled_default"; + + @GuardedBy("mListeners") + private final ArrayMap> mListeners = new ArrayMap<>(); + + private static final Object SLOCK = new Object(); + + @GuardedBy("SLOCK") + @Nullable + private static ServerFlags sInstance; + + private ServerFlags(Context context) { + DeviceConfig.addOnPropertiesChangedListener( + NAMESPACE_SYSTEM_TIME, + context.getMainExecutor(), + this::handlePropertiesChanged); + } + + /** Returns the singleton instance. */ + public static ServerFlags getInstance(Context context) { + synchronized (SLOCK) { + if (sInstance == null) { + sInstance = new ServerFlags(context); + } + return sInstance; + } + } + + private void handlePropertiesChanged(@NonNull DeviceConfig.Properties properties) { + synchronized (mListeners) { + for (Map.Entry> listenerEntry + : mListeners.entrySet()) { + if (intersects(listenerEntry.getValue(), properties.getKeyset())) { + listenerEntry.getKey().onChange(); + } + } + } + } + + private static boolean intersects(@NonNull Set one, @NonNull Set two) { + for (String toFind : one) { + if (two.contains(toFind)) { + return true; + } + } + return false; + } + + /** + * Adds a listener for the system_time namespace that will trigger if any of the specified keys + * change. Listener callbacks are delivered on the main looper thread. + * + *

Note: Only for use by long-lived objects like other singletons. There is deliberately no + * associated remove method. + */ + public void addListener(@NonNull ConfigurationChangeListener listener, + @NonNull Set keys) { + Objects.requireNonNull(listener); + Objects.requireNonNull(keys); + + synchronized (mListeners) { + mListeners.put(listener, keys); + } + } + + /** + * Returns an optional boolean value from {@link DeviceConfig} from the system_time + * namespace, returns {@link Optional#empty()} if there is no explicit value set. + */ + @NonNull + public Optional getOptionalBoolean(@DeviceConfigKey String key) { + String value = DeviceConfig.getProperty(NAMESPACE_SYSTEM_TIME, key); + return parseOptionalBoolean(value); + } + + @NonNull + private static Optional parseOptionalBoolean(@Nullable String value) { + if (value == null) { + return Optional.empty(); + } else { + return Boolean.parseBoolean(value) ? OPTIONAL_TRUE : OPTIONAL_FALSE; + } + } + + /** + * Returns a boolean value from {@link DeviceConfig} from the system_time + * namespace, or {@code defaultValue} if there is no explicit value set. + */ + public boolean getBoolean(@DeviceConfigKey String key, boolean defaultValue) { + return DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue); + } + + /** + * Returns a positive duration from {@link DeviceConfig} from the system_time + * namespace, or {@code defaultValue} if there is no explicit value set. + */ + @Nullable + public Duration getDurationFromMillis( + @DeviceConfigKey String key, @Nullable Duration defaultValue) { + long deviceConfigValue = DeviceConfig.getLong(NAMESPACE_SYSTEM_TIME, key, -1); + if (deviceConfigValue < 0) { + return defaultValue; + } + return Duration.ofMillis(deviceConfigValue); + } +} diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java index 4c7b1f38dd5ae..aa8ad37815bfe 100644 --- a/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationChangeListener.java @@ -17,10 +17,11 @@ package com.android.server.timezonedetector; /** - * A listener used to receive notification that time zone configuration has changed. + * A listener used to receive notification that configuration has / may have changed (depending on + * the usecase). */ @FunctionalInterface public interface ConfigurationChangeListener { - /** Called when the current user or a configuration value has changed. */ + /** Called when the configuration may have changed. */ void onChange(); } diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java index 1f73977444f81..3ae9d641e81c0 100644 --- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java @@ -33,26 +33,27 @@ import com.android.internal.util.Preconditions; import java.util.Objects; /** - * Holds all configuration values that affect time zone behavior and some associated logic, e.g. - * {@link #getAutoDetectionEnabledBehavior()}, {@link #getGeoDetectionEnabledBehavior()} and {@link - * #createCapabilitiesAndConfig()}. + * Holds configuration values that affect user-facing time zone behavior and some associated logic. + * Some configuration is global, some is user scoped, but this class deliberately doesn't make a + * distinction for simplicity. */ public final class ConfigurationInternal { - private final @UserIdInt int mUserId; - private final boolean mUserConfigAllowed; private final boolean mAutoDetectionSupported; private final boolean mGeoDetectionSupported; private final boolean mAutoDetectionEnabled; + private final @UserIdInt int mUserId; + private final boolean mUserConfigAllowed; private final boolean mLocationEnabled; private final boolean mGeoDetectionEnabled; private ConfigurationInternal(Builder builder) { - mUserId = builder.mUserId; - mUserConfigAllowed = builder.mUserConfigAllowed; mAutoDetectionSupported = builder.mAutoDetectionSupported; mGeoDetectionSupported = builder.mGeoDetectionSupported; mAutoDetectionEnabled = builder.mAutoDetectionEnabled; + + mUserId = builder.mUserId; + mUserConfigAllowed = builder.mUserConfigAllowed; mLocationEnabled = builder.mLocationEnabled; mGeoDetectionEnabled = builder.mGeoDetectionEnabled; // if mGeoDetectionSupported then mAutoDetectionSupported, i.e. mGeoDetectionSupported @@ -60,22 +61,6 @@ public final class ConfigurationInternal { Preconditions.checkState(mAutoDetectionSupported || !mGeoDetectionSupported); } - /** Returns the ID of the user this configuration is associated with. */ - public @UserIdInt int getUserId() { - return mUserId; - } - - /** Returns the handle of the user this configuration is associated with. */ - @NonNull - public UserHandle getUserHandle() { - return UserHandle.of(mUserId); - } - - /** Returns true if the user allowed to modify time zone configuration. */ - public boolean isUserConfigAllowed() { - return mUserConfigAllowed; - } - /** Returns true if the device supports any form of auto time zone detection. */ public boolean isAutoDetectionSupported() { return mAutoDetectionSupported; @@ -98,6 +83,22 @@ public final class ConfigurationInternal { return mAutoDetectionSupported && mAutoDetectionEnabled; } + /** Returns the ID of the user this configuration is associated with. */ + public @UserIdInt int getUserId() { + return mUserId; + } + + /** Returns the handle of the user this configuration is associated with. */ + @NonNull + public UserHandle getUserHandle() { + return UserHandle.of(mUserId); + } + + /** Returns true if the user allowed to modify time zone configuration. */ + public boolean isUserConfigAllowed() { + return mUserConfigAllowed; + } + /** Returns true if user's location can be used generally. */ public boolean isLocationEnabled() { return mLocationEnabled; @@ -283,7 +284,7 @@ public final class ConfigurationInternal { /** * Sets whether any form of automatic time zone detection is supported on this device. */ - public Builder setAutoDetectionSupported(boolean supported) { + public Builder setAutoDetectionFeatureSupported(boolean supported) { mAutoDetectionSupported = supported; return this; } @@ -291,7 +292,7 @@ public final class ConfigurationInternal { /** * Sets whether geolocation time zone detection is supported on this device. */ - public Builder setGeoDetectionSupported(boolean supported) { + public Builder setGeoDetectionFeatureSupported(boolean supported) { mGeoDetectionSupported = supported; return this; } diff --git a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java index f52b9b1b1c580..e3caae9482d94 100644 --- a/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java +++ b/services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java @@ -31,9 +31,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.location.LocationManager; -import android.net.ConnectivityManager; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; @@ -42,10 +40,9 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; -import com.android.server.timedetector.DeviceConfig; import java.util.Objects; -import java.util.concurrent.Executor; +import java.util.Optional; /** * The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}. @@ -59,8 +56,7 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir @NonNull private final Handler mHandler; @NonNull private final ContentResolver mCr; @NonNull private final UserManager mUserManager; - @NonNull private final DeviceConfig mDeviceConfig; - @NonNull private final boolean mGeoDetectionSupported; + @NonNull private final ServiceConfigAccessor mServiceConfigAccessor; @NonNull private final LocationManager mLocationManager; // @NonNull after setConfigChangeListener() is called. @@ -68,17 +64,16 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir private ConfigurationChangeListener mConfigChangeListener; EnvironmentImpl(@NonNull Context context, @NonNull Handler handler, - @NonNull DeviceConfig deviceConfig, boolean geoDetectionSupported) { + @NonNull ServiceConfigAccessor serviceConfigAccessor) { mContext = Objects.requireNonNull(context); mHandler = Objects.requireNonNull(handler); - Executor handlerExecutor = new HandlerExecutor(mHandler); mCr = context.getContentResolver(); mUserManager = context.getSystemService(UserManager.class); mLocationManager = context.getSystemService(LocationManager.class); - mDeviceConfig = deviceConfig; - mGeoDetectionSupported = geoDetectionSupported; + mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor); - // Wire up the change listeners. All invocations are performed on the mHandler thread. + // Wire up the config change listeners. All invocations are performed on the mHandler + // thread. // Listen for the user changing / the user's location mode changing. IntentFilter filter = new IntentFilter(); @@ -112,13 +107,6 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir handleConfigChangeOnHandlerThread(); } }, UserHandle.USER_ALL); - - // Add async callbacks for changes to server-side flags: some of the flags affect device / - // user config. All changes can be treated like a config change. If flags that affect config - // haven't changed then call will be a no-op. - mDeviceConfig.addListener( - handlerExecutor, - this::handleConfigChangeOnHandlerThread); } private void handleConfigChangeOnHandlerThread() { @@ -140,10 +128,12 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir @Override public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) { return new ConfigurationInternal.Builder(userId) - .setUserConfigAllowed(isUserConfigAllowed(userId)) - .setAutoDetectionSupported(isAutoDetectionSupported()) - .setGeoDetectionSupported(isGeoDetectionSupported()) + .setAutoDetectionFeatureSupported( + mServiceConfigAccessor.isAutoDetectionFeatureSupported()) + .setGeoDetectionFeatureSupported( + mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) .setAutoDetectionEnabled(isAutoDetectionEnabled()) + .setUserConfigAllowed(isUserConfigAllowed(userId)) .setLocationEnabled(isLocationEnabled(userId)) .setGeoDetectionEnabled(isGeoDetectionEnabled(userId)) .build(); @@ -186,18 +176,19 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir // time zone detection: if we wrote it down then we'd set the value explicitly, which would // prevent detecting "default" later. That might influence what happens on later releases // that support new types of auto detection on the same hardware. - if (isAutoDetectionSupported()) { + if (mServiceConfigAccessor.isAutoDetectionFeatureSupported()) { final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled(); setAutoDetectionEnabledIfRequired(autoDetectionEnabled); - // Avoid writing the geo detection enabled setting for devices that do not support geo - // time zone detection: if we wrote it down then we'd set the value explicitly, which - // would prevent detecting "default" later. That might influence what happens on later - // releases that support geo detection on the same hardware. - // Also avoid writing the geo detection enabled setting for devices that are currently - // force-enabled: otherwise we might overwrite a droidfood user's real setting - // permanently. - if (isGeoDetectionSupported() && !isGeoDetectionForceEnabled()) { + // Avoid writing the geo detection enabled setting for devices with settings that + // are currently overridden by server flags: otherwise we might overwrite a droidfood + // user's real setting permanently. + // Also avoid writing the geo detection enabled setting for devices that do not support + // geo time zone detection: if we wrote it down then we'd set the value explicitly, + // which would prevent detecting "default" later. That might influence what happens on + // later releases that start to support geo detection on the same hardware. + if (!mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride().isPresent() + && mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) { final boolean geoTzDetectionEnabled = configuration.isGeoDetectionEnabled(); setGeoDetectionEnabledIfRequired(userId, geoTzDetectionEnabled); } @@ -209,14 +200,6 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle); } - private boolean isAutoDetectionSupported() { - return deviceHasTelephonyNetwork() || isGeoDetectionSupported(); - } - - private boolean isGeoDetectionSupported() { - return mGeoDetectionSupported; - } - private boolean isAutoDetectionEnabled() { return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0; } @@ -237,24 +220,20 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir private boolean isGeoDetectionEnabled(@UserIdInt int userId) { // We may never use this, but it gives us a way to force location-based time zone detection - // on for testers (where their other settings allow). - boolean forceEnabled = isGeoDetectionForceEnabled(); - if (forceEnabled) { - return true; + // on/off for testers (but only where their other settings would allow them to turn it on + // for themselves). + Optional override = mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride(); + if (override.isPresent()) { + return override.get(); } - final boolean geoDetectionEnabledByDefault = mDeviceConfig.getBoolean( - DeviceConfig.KEY_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT, false); + final boolean geoDetectionEnabledByDefault = + mServiceConfigAccessor.isGeoDetectionEnabledForUsersByDefault(); return Settings.Secure.getIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, (geoDetectionEnabledByDefault ? 1 : 0) /* defaultValue */, userId) != 0; } - private boolean isGeoDetectionForceEnabled() { - return mDeviceConfig.getBoolean( - DeviceConfig.KEY_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED, false); - } - private void setGeoDetectionEnabledIfRequired(@UserIdInt int userId, boolean enabled) { // See comment in setAutoDetectionEnabledIfRequired. http://b/171953500 if (isGeoDetectionEnabled(userId) != enabled) { @@ -262,10 +241,4 @@ public final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Envir enabled ? 1 : 0, userId); } } - - private boolean deviceHasTelephonyNetwork() { - // TODO b/150583524 Avoid the use of a deprecated API. - return mContext.getSystemService(ConnectivityManager.class) - .isNetworkSupported(ConnectivityManager.TYPE_MOBILE); - } } diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java new file mode 100644 index 0000000000000..86c32f8d7b45a --- /dev/null +++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java @@ -0,0 +1,249 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.timezonedetector; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.res.Resources; +import android.net.ConnectivityManager; +import android.os.SystemProperties; +import android.util.ArraySet; + +import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; +import com.android.server.timedetector.ServerFlags; + +import java.time.Duration; +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * A singleton that provides access to service configuration for time zone detection. This hides how + * configuration is split between static, compile-time config and dynamic, server-pushed flags. It + * provides a rudimentary mechanism to signal when values have changed. + */ +public final class ServiceConfigAccessor { + + private static final Set 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, + ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE, + ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE, + ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS, + ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS, + ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS + })); + + // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented + private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(1); + // TODO(b/179488561): Put this back to 1 minute when primary provider is fully implemented + private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ = + Duration.ofSeconds(20); + private static final Duration DEFAULT_PROVIDER_UNCERTAINTY_DELAY = Duration.ofMinutes(5); + + private static final Object SLOCK = new Object(); + + /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */ + @GuardedBy("SLOCK") + @Nullable + private static ServiceConfigAccessor sInstance; + + @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; + + 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); + } + + /** Returns the singleton instance. */ + public static ServiceConfigAccessor getInstance(Context context) { + synchronized (SLOCK) { + if (sInstance == null) { + sInstance = new ServiceConfigAccessor(context); + } + return sInstance; + } + } + + /** + * Adds a listener that will be called server flags related to this class change. The callbacks + * are delivered on the main looper thread. + * + *

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); + } + + /** Returns {@code true} if any form of automatic time zone detection is supported. */ + public boolean isAutoDetectionFeatureSupported() { + return deviceHasTelephonyNetwork() || isGeoTimeZoneDetectionFeatureSupported(); + } + + private boolean deviceHasTelephonyNetwork() { + // TODO b/150583524 Avoid the use of a deprecated API. + return mContext.getSystemService(ConnectivityManager.class) + .isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + } + + /** + * 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. + */ + public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() { + return mGeoDetectionFeatureSupportedInConfig; + } + + /** + * Returns {@code true} if the location-based time zone detection feature is supported on the + * device. This can be used during feature testing on builds that are capable of location time + * zone detection to enable / disable the feature for some users. + */ + public boolean isGeoTimeZoneDetectionFeatureSupported() { + return mGeoDetectionFeatureSupportedInConfig + && isGeoTimeZoneDetectionFeatureSupportedInternal(); + } + + private boolean isGeoTimeZoneDetectionFeatureSupportedInternal() { + final boolean defaultEnabled = true; + return mServerFlags.getBoolean( + ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED, + defaultEnabled); + } + + /** + * Returns {@code true} if the primary location time zone provider can be used. + */ + public boolean isPrimaryLocationTimeZoneProviderEnabled() { + return getPrimaryLocationTimeZoneProviderEnabledOverride() + .orElse(isPrimaryLocationTimeZoneProviderEnabledInConfig()); + } + + private boolean isPrimaryLocationTimeZoneProviderEnabledInConfig() { + int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider; + return getConfigBoolean(providerEnabledConfigId); + } + + @NonNull + private Optional getPrimaryLocationTimeZoneProviderEnabledOverride() { + return mServerFlags.getOptionalBoolean( + ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE); + } + + /** + * Returns {@code true} if the secondary location time zone provider can be used. + */ + public boolean isSecondaryLocationTimeZoneProviderEnabled() { + return getSecondaryLocationTimeZoneProviderEnabledOverride() + .orElse(isSecondaryLocationTimeZoneProviderEnabledInConfig()); + } + + private boolean isSecondaryLocationTimeZoneProviderEnabledInConfig() { + int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider; + return getConfigBoolean(providerEnabledConfigId); + } + + @NonNull + private Optional getSecondaryLocationTimeZoneProviderEnabledOverride() { + return mServerFlags.getOptionalBoolean( + ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE); + } + + /** + * Returns whether location time zone detection is enabled for users when there's no setting + * value. Intended for use during feature release testing to "opt-in" users that haven't shown + * an explicit preference. + */ + public boolean isGeoDetectionEnabledForUsersByDefault() { + return mServerFlags.getBoolean( + ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, false); + } + + /** + * Returns whether location time zone detection is force enabled/disabled for users. Intended + * for use during feature release testing to force a given state. + */ + @NonNull + public Optional getGeoDetectionSettingEnabledOverride() { + return mServerFlags.getOptionalBoolean( + ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE); + } + + /** + * Returns the time to send to a location time zone provider that informs it how long it has + * to return its first time zone suggestion. + */ + @NonNull + public Duration getLocationTimeZoneProviderInitializationTimeout() { + return mServerFlags.getDurationFromMillis( + ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS, + DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT); + } + + /** + * Returns the time added to {@link #getLocationTimeZoneProviderInitializationTimeout()} by the + * server before unilaterally declaring the provider is uncertain. + */ + @NonNull + public Duration getLocationTimeZoneProviderInitializationTimeoutFuzz() { + return mServerFlags.getDurationFromMillis( + ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS, + DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ); + } + + /** + * Returns the time after uncertainty is detected by providers before the location time zone + * manager makes a suggestion to the time zone detector. + */ + @NonNull + public Duration getLocationTimeZoneUncertaintyDelay() { + return mServerFlags.getDurationFromMillis( + ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS, + DEFAULT_PROVIDER_UNCERTAINTY_DELAY); + } + + private boolean getConfigBoolean(int providerEnabledConfigId) { + Resources resources = mContext.getResources(); + return resources.getBoolean(providerEnabledConfigId); + } +} diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java index 203a8a4e02ccf..cd220b164851f 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java @@ -27,16 +27,21 @@ import android.annotation.NonNull; */ public interface TimeZoneDetectorInternal extends Dumpable.Container { - /** Adds a listener that will be invoked when time zone detection configuration is changed. */ - void addConfigurationListener(ConfigurationChangeListener listener); + /** Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed. */ + void addConfigurationListener(@NonNull ConfigurationChangeListener listener); /** * Removes a listener previously added via {@link * #addConfigurationListener(ConfigurationChangeListener)}. */ - void removeConfigurationListener(ConfigurationChangeListener listener); + void removeConfigurationListener(@NonNull ConfigurationChangeListener listener); - /** Returns the {@link ConfigurationInternal} for the current user. */ + /** + * Returns a snapshot of the {@link ConfigurationInternal} for the current user. This is only a + * snapshot so callers must use {@link #addConfigurationListener(ConfigurationChangeListener)} + * to be notified when it changes. + */ + @NonNull ConfigurationInternal getCurrentUserConfigurationInternal(); /** diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index bd71ddf67094f..c20400ae7a4b9 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -33,7 +33,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; -import android.os.SystemProperties; import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -61,27 +60,6 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub static final String TAG = "time_zone_detector"; - /** - * A "feature switch" for location-based time zone detection. If this is {@code false}. It is - * initialized and never refreshed; it affects what services are started on boot so consistency - * is important. - */ - @Nullable - private static Boolean sGeoLocationTimeZoneDetectionSupported; - - /** Returns {@code true} if the location-based time zone detection feature is enabled. */ - public static boolean isGeoLocationTimeZoneDetectionSupported(Context context) { - if (sGeoLocationTimeZoneDetectionSupported == null) { - // The config value is expected to be the main switch. Platform developers can also - // enable the feature using a persistent system property. - sGeoLocationTimeZoneDetectionSupported = context.getResources().getBoolean( - com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection) - || SystemProperties.getBoolean( - "persist.sys.location_time_zone_detection_feature_enabled", false); - } - return sGeoLocationTimeZoneDetectionSupported; - } - /** * Handles the service lifecycle for {@link TimeZoneDetectorService} and * {@link TimeZoneDetectorInternalImpl}. @@ -98,11 +76,10 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub Context context = getContext(); Handler handler = FgThread.getHandler(); - boolean geolocationTimeZoneDetectionSupported = - isGeoLocationTimeZoneDetectionSupported(context); + ServiceConfigAccessor serviceConfigAccessor = + ServiceConfigAccessor.getInstance(context); TimeZoneDetectorStrategy timeZoneDetectorStrategy = - TimeZoneDetectorStrategyImpl.create( - context, handler, geolocationTimeZoneDetectionSupported); + TimeZoneDetectorStrategyImpl.create(context, handler, serviceConfigAccessor); // Create and publish the local service for use by internal callers. TimeZoneDetectorInternal internal = @@ -330,7 +307,8 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub boolean isGeoTimeZoneDetectionSupported() { enforceManageTimeZoneDetectorPermission(); - return isGeoLocationTimeZoneDetectionSupported(mContext); + return ServiceConfigAccessor.getInstance(mContext) + .isGeoTimeZoneDetectionFeatureSupported(); } @Override diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java index 0b1d6d71ea7b6..8266f121822ec 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java @@ -75,17 +75,21 @@ import android.util.IndentingPrintWriter; public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container { /** - * Sets a listener that will be triggered whenever time zone detection configuration is + * Adds a listener that will be triggered whenever {@link ConfigurationInternal} may have * changed. */ void addConfigChangeListener(@NonNull ConfigurationChangeListener listener); - /** Returns the user's time zone configuration. */ + /** + * Returns a snapshot of the configuration that controls time zone detector behavior for the + * specified user. + */ @NonNull ConfigurationInternal getConfigurationInternal(@UserIdInt int userId); /** - * Returns the configuration that controls time zone detector behavior for the current user. + * Returns a snapshot of the configuration that controls time zone detector behavior for the + * current user. */ @NonNull ConfigurationInternal getCurrentUserConfigurationInternal(); diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java index c464b74ca726c..d163a0e223206 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java @@ -38,7 +38,6 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.timedetector.DeviceConfig; import java.util.ArrayList; import java.util.List; @@ -204,11 +203,9 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat */ public static TimeZoneDetectorStrategyImpl create( @NonNull Context context, @NonNull Handler handler, - boolean geoDetectionSupported) { + @NonNull ServiceConfigAccessor serviceConfigAccessor) { - DeviceConfig deviceConfig = new DeviceConfig(); - EnvironmentImpl environment = new EnvironmentImpl( - context, handler, deviceConfig, geoDetectionSupported); + Environment environment = new EnvironmentImpl(context, handler, serviceConfigAccessor); return new TimeZoneDetectorStrategyImpl(environment); } diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java index e463ee22452d5..98e984d2c3aca 100644 --- a/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java +++ b/services/core/java/com/android/server/timezonedetector/location/ControllerEnvironmentImpl.java @@ -19,9 +19,9 @@ package com.android.server.timezonedetector.location; import android.annotation.NonNull; import com.android.server.LocalServices; -import com.android.server.timedetector.DeviceConfig; import com.android.server.timezonedetector.ConfigurationChangeListener; import com.android.server.timezonedetector.ConfigurationInternal; +import com.android.server.timezonedetector.ServiceConfigAccessor; import com.android.server.timezonedetector.TimeZoneDetectorInternal; import java.time.Duration; @@ -33,28 +33,19 @@ import java.util.Objects; */ class ControllerEnvironmentImpl extends LocationTimeZoneProviderController.Environment { - // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented - private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(1); - // TODO(b/179488561): Put this back to 5 minutes when primary provider is fully implemented - private static final Duration DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ = - Duration.ofSeconds(20); - private static final Duration DEFAULT_PROVIDER_UNCERTAINTY_DELAY = Duration.ofMinutes(5); - @NonNull private final TimeZoneDetectorInternal mTimeZoneDetectorInternal; - @NonNull private final LocationTimeZoneProviderController mController; - @NonNull private final DeviceConfig mDeviceConfig; + @NonNull private final ServiceConfigAccessor mServiceConfigAccessor; @NonNull private final ConfigurationChangeListener mConfigurationChangeListener; ControllerEnvironmentImpl(@NonNull ThreadingDomain threadingDomain, - @NonNull DeviceConfig deviceConfig, + @NonNull ServiceConfigAccessor serviceConfigAccessor, @NonNull LocationTimeZoneProviderController controller) { super(threadingDomain); - mController = Objects.requireNonNull(controller); - mDeviceConfig = Objects.requireNonNull(deviceConfig); + mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor); mTimeZoneDetectorInternal = LocalServices.getService(TimeZoneDetectorInternal.class); // Listen for configuration changes. - mConfigurationChangeListener = () -> mThreadingDomain.post(mController::onConfigChanged); + mConfigurationChangeListener = () -> mThreadingDomain.post(controller::onConfigChanged); mTimeZoneDetectorInternal.addConfigurationListener(mConfigurationChangeListener); } @@ -73,24 +64,18 @@ class ControllerEnvironmentImpl extends LocationTimeZoneProviderController.Envir @Override @NonNull Duration getProviderInitializationTimeout() { - return mDeviceConfig.getDurationFromMillis( - DeviceConfig.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS, - DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT); + return mServiceConfigAccessor.getLocationTimeZoneProviderInitializationTimeout(); } @Override @NonNull Duration getProviderInitializationTimeoutFuzz() { - return mDeviceConfig.getDurationFromMillis( - DeviceConfig.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS, - DEFAULT_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ); + return mServiceConfigAccessor.getLocationTimeZoneProviderInitializationTimeoutFuzz(); } @Override @NonNull Duration getUncertaintyDelay() { - return mDeviceConfig.getDurationFromMillis( - DeviceConfig.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS, - DEFAULT_PROVIDER_UNCERTAINTY_DELAY); + return mServiceConfigAccessor.getLocationTimeZoneUncertaintyDelay(); } } diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java index 364eaf8dac041..0d1692a8781d2 100644 --- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java +++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java @@ -21,11 +21,11 @@ import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DI import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE; import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED; import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME; +import static android.app.time.LocationTimeZoneManager.SERVICE_NAME; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.content.res.Resources; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -43,9 +43,8 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.FgThread; import com.android.server.SystemService; -import com.android.server.timedetector.DeviceConfig; +import com.android.server.timezonedetector.ServiceConfigAccessor; import com.android.server.timezonedetector.TimeZoneDetectorInternal; -import com.android.server.timezonedetector.TimeZoneDetectorService; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -96,28 +95,31 @@ public class LocationTimeZoneManagerService extends Binder { private LocationTimeZoneManagerService mService; + @NonNull + private final ServiceConfigAccessor mServerConfigAccessor; + public Lifecycle(@NonNull Context context) { super(Objects.requireNonNull(context)); + mServerConfigAccessor = ServiceConfigAccessor.getInstance(context); } @Override public void onStart() { Context context = getContext(); - if (TimeZoneDetectorService.isGeoLocationTimeZoneDetectionSupported(context)) { + if (mServerConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) { mService = new LocationTimeZoneManagerService(context); // The service currently exposes no LocalService or Binder API, but it extends // Binder and is registered as a binder service so it can receive shell commands. - publishBinderService("location_time_zone_manager", mService); + publishBinderService(SERVICE_NAME, mService); } else { - Slog.i(TAG, getClass() + " is disabled"); + Slog.d(TAG, "Geo time zone detection feature is disabled in config"); } } @Override - public void onBootPhase(int phase) { - Context context = getContext(); - if (TimeZoneDetectorService.isGeoLocationTimeZoneDetectionSupported(context)) { + public void onBootPhase(@BootPhase int phase) { + if (mServerConfigAccessor.isGeoTimeZoneDetectionFeatureSupportedInConfig()) { if (phase == PHASE_SYSTEM_SERVICES_READY) { // The location service must be functioning after this boot phase. mService.onSystemReady(); @@ -159,6 +161,9 @@ public class LocationTimeZoneManagerService extends Binder { /** The shared lock from {@link #mThreadingDomain}. */ @NonNull private final Object mSharedLock; + @NonNull + private final ServiceConfigAccessor mServiceConfigAccessor; + // Lazily initialized. Can be null if the service has been stopped. @GuardedBy("mSharedLock") private ControllerImpl mLocationTimeZoneDetectorController; @@ -180,24 +185,38 @@ public class LocationTimeZoneManagerService extends Binder { mHandler = FgThread.getHandler(); mThreadingDomain = new HandlerThreadingDomain(mHandler); mSharedLock = mThreadingDomain.getLockObject(); + mServiceConfigAccessor = ServiceConfigAccessor.getInstance(mContext); } + // According to the SystemService docs: All lifecycle methods are called from the system + // server's main looper thread. void onSystemReady() { - // Called on an arbitrary thread during initialization. - synchronized (mSharedLock) { - // TODO(b/152744911): LocationManagerService watches for packages disappearing. Need to - // do anything here? + mServiceConfigAccessor.addListener(this::handleServiceConfigurationChangedOnMainThread); + } - // TODO(b/152744911): LocationManagerService watches for foreground app changes. Need to - // do anything here? - // TODO(b/152744911): LocationManagerService watches screen state. Need to do anything - // here? + private void handleServiceConfigurationChangedOnMainThread() { + // This method is called on the main thread, but service logic takes place on the threading + // domain thread, so we post the work there. + + // The way all service-level configuration changes are handled is to just restart this + // service - this is simple and effective, and service configuration changes should be rare. + mThreadingDomain.post(this::restartIfRequiredOnDomainThread); + } + + private void restartIfRequiredOnDomainThread() { + mThreadingDomain.assertCurrentThread(); + + synchronized (mSharedLock) { + // Stop and start the service, waiting until completion. + stopOnDomainThread(); + startOnDomainThread(); } } + // According to the SystemService docs: All lifecycle methods are called from the system + // server's main looper thread. void onSystemThirdPartyAppsCanStart() { - // Called on an arbitrary thread during initialization. We do not want to wait for - // completion as it would delay boot. + // Do not wait for completion as it would delay boot. final boolean waitForCompletion = false; startInternal(waitForCompletion); } @@ -205,6 +224,9 @@ public class LocationTimeZoneManagerService extends Binder { /** * Starts the service during server initialization or during tests after a call to * {@link #stop()}. + * + *

Because this method posts work to the {@code mThreadingDomain} thread and waits for + * completion, it cannot be called from the {@code mThreadingDomain} thread. */ void start() { enforceManageTimeZoneDetectorPermission(); @@ -214,28 +236,17 @@ public class LocationTimeZoneManagerService extends Binder { } /** - * Starts the service during server initialization or during tests after a call to - * {@link #stop()}. + * Starts the service during server initialization, if the configuration changes or during tests + * after a call to {@link #stop()}. * *

To avoid tests needing to sleep, when {@code waitForCompletion} is {@code true}, this * method will not return until all the system server components have started. + * + *

Because this method posts work to the {@code mThreadingDomain} thread, it cannot be + * called from the {@code mThreadingDomain} thread when {@code waitForCompletion} is true. */ private void startInternal(boolean waitForCompletion) { - Runnable runnable = () -> { - synchronized (mSharedLock) { - if (mLocationTimeZoneDetectorController == null) { - LocationTimeZoneProvider primary = createPrimaryProvider(); - LocationTimeZoneProvider secondary = createSecondaryProvider(); - mLocationTimeZoneDetectorController = - new ControllerImpl(mThreadingDomain, primary, secondary); - DeviceConfig deviceConfig = new DeviceConfig(); - mEnvironment = new ControllerEnvironmentImpl( - mThreadingDomain, deviceConfig, mLocationTimeZoneDetectorController); - ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain); - mLocationTimeZoneDetectorController.initialize(mEnvironment, callback); - } - } - }; + Runnable runnable = this::startOnDomainThread; if (waitForCompletion) { mThreadingDomain.postAndWait(runnable, BLOCKING_OP_WAIT_DURATION_MILLIS); } else { @@ -243,11 +254,38 @@ public class LocationTimeZoneManagerService extends Binder { } } + private void startOnDomainThread() { + mThreadingDomain.assertCurrentThread(); + + synchronized (mSharedLock) { + if (!mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) { + debugLog("Not starting " + SERVICE_NAME + ": it is disabled in service config"); + return; + } + + if (mLocationTimeZoneDetectorController == null) { + LocationTimeZoneProvider primary = createPrimaryProvider(); + LocationTimeZoneProvider secondary = createSecondaryProvider(); + + ControllerImpl controller = + new ControllerImpl(mThreadingDomain, primary, secondary); + ControllerEnvironmentImpl environment = new ControllerEnvironmentImpl( + mThreadingDomain, mServiceConfigAccessor, controller); + ControllerCallbackImpl callback = new ControllerCallbackImpl(mThreadingDomain); + controller.initialize(environment, callback); + + mEnvironment = environment; + mLocationTimeZoneDetectorController = controller; + } + } + } + + @NonNull private LocationTimeZoneProvider createPrimaryProvider() { LocationTimeZoneProviderProxy proxy; if (isProviderInSimulationMode(PRIMARY_PROVIDER_NAME)) { proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain); - } else if (isProviderDisabled(PRIMARY_PROVIDER_NAME)) { + } else if (!isProviderEnabled(PRIMARY_PROVIDER_NAME)) { proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain); } else { proxy = new RealLocationTimeZoneProviderProxy( @@ -262,11 +300,12 @@ public class LocationTimeZoneManagerService extends Binder { return new BinderLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy); } + @NonNull private LocationTimeZoneProvider createSecondaryProvider() { LocationTimeZoneProviderProxy proxy; if (isProviderInSimulationMode(SECONDARY_PROVIDER_NAME)) { proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain); - } else if (isProviderDisabled(SECONDARY_PROVIDER_NAME)) { + } else if (!isProviderEnabled(SECONDARY_PROVIDER_NAME)) { proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain); } else { proxy = new RealLocationTimeZoneProviderProxy( @@ -282,33 +321,27 @@ public class LocationTimeZoneManagerService extends Binder { } /** Used for bug triage and in tests to simulate provider events. */ - private boolean isProviderInSimulationMode(String providerName) { + private boolean isProviderInSimulationMode(@NonNull String providerName) { return isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_SIMULATED); } - /** Used for bug triage, tests and experiments to remove a provider. */ - private boolean isProviderDisabled(String providerName) { - return !isProviderEnabledInConfig(providerName) - || isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED); - } + /** Used for bug triage, and by tests and experiments to remove a provider. */ + private boolean isProviderEnabled(@NonNull String providerName) { + if (isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED)) { + return false; + } - private boolean isProviderEnabledInConfig(String providerName) { - int providerEnabledConfigId; switch (providerName) { case PRIMARY_PROVIDER_NAME: { - providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider; - break; + return mServiceConfigAccessor.isPrimaryLocationTimeZoneProviderEnabled(); } case SECONDARY_PROVIDER_NAME: { - providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider; - break; + return mServiceConfigAccessor.isSecondaryLocationTimeZoneProviderEnabled(); } default: { throw new IllegalArgumentException(providerName); } } - Resources resources = mContext.getResources(); - return resources.getBoolean(providerEnabledConfigId); } private boolean isProviderModeOverrideSet(@NonNull String providerName, @NonNull String mode) { @@ -326,22 +359,29 @@ public class LocationTimeZoneManagerService extends Binder { } /** - * Stops the service for tests. To avoid tests needing to sleep, this method will not return - * until all the system server components have stopped. + * Stops the service for tests and other rare cases. To avoid tests needing to sleep, this + * method will not return until all the system server components have stopped. + * + *

Because this method posts work to the {@code mThreadingDomain} thread and waits it cannot + * be called from the {@code mThreadingDomain} thread. */ void stop() { enforceManageTimeZoneDetectorPermission(); - mThreadingDomain.postAndWait(() -> { - synchronized (mSharedLock) { - if (mLocationTimeZoneDetectorController != null) { - mLocationTimeZoneDetectorController.destroy(); - mLocationTimeZoneDetectorController = null; - mEnvironment.destroy(); - mEnvironment = null; - } + mThreadingDomain.postAndWait(this::stopOnDomainThread, BLOCKING_OP_WAIT_DURATION_MILLIS); + } + + private void stopOnDomainThread() { + mThreadingDomain.assertCurrentThread(); + + synchronized (mSharedLock) { + if (mLocationTimeZoneDetectorController != null) { + mLocationTimeZoneDetectorController.destroy(); + mLocationTimeZoneDetectorController = null; + mEnvironment.destroy(); + mEnvironment = null; } - }, BLOCKING_OP_WAIT_DURATION_MILLIS); + } } @Override diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java index b53150c729bc3..bdf4a70a6a2bb 100644 --- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java +++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java @@ -21,6 +21,7 @@ import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DI import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE; import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED; import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME; +import static android.app.time.LocationTimeZoneManager.SERVICE_NAME; import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_DUMP_STATE; import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_RECORD_PROVIDER_STATES; import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND; @@ -102,7 +103,7 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); - pw.println("Location Time Zone Manager (location_time_zone_manager) commands for tests:"); + pw.printf("Location Time Zone Manager (%s) commands for tests:\n", SERVICE_NAME); pw.println(" help"); pw.println(" Print this help text."); pw.printf(" %s\n", SHELL_COMMAND_START); diff --git a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java index 14820319d9dfd..e8386bc22403c 100644 --- a/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java +++ b/services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderRequest.java @@ -63,8 +63,6 @@ final class TimeZoneProviderRequest { return mSendUpdates; } - // TODO(b/152744911) - once there are a couple of implementations, decide whether this needs to - // be passed to the TimeZoneProviderService and remove if it is not useful. /** * Returns the maximum time that the provider is allowed to initialize before it is expected to * send an event of any sort. Only valid when {@link #sendUpdates()} is {@code true}. Failure to diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java index 682a80c9b2975..5d27552212885 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java @@ -46,8 +46,8 @@ public class ConfigurationInternalTest { public void test_unrestricted() { ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) .setGeoDetectionEnabled(true) @@ -108,8 +108,8 @@ public class ConfigurationInternalTest { public void test_restricted() { ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) .setUserConfigAllowed(false) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) .setGeoDetectionEnabled(true) @@ -170,8 +170,8 @@ public class ConfigurationInternalTest { public void test_autoDetectNotSupported() { ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionSupported(false) - .setGeoDetectionSupported(false) + .setAutoDetectionFeatureSupported(false) + .setGeoDetectionFeatureSupported(false) .setAutoDetectionEnabled(true) .setLocationEnabled(true) .setGeoDetectionEnabled(true) @@ -232,8 +232,8 @@ public class ConfigurationInternalTest { public void test_geoDetectNotSupported() { ConfigurationInternal baseConfig = new ConfigurationInternal.Builder(ARBITRARY_USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(false) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(false) .setAutoDetectionEnabled(true) .setLocationEnabled(true) .setGeoDetectionEnabled(true) diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java index d2452eaee6570..14e0bbd6fa429 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java @@ -364,8 +364,8 @@ public class TimeZoneDetectorServiceTest { // the tests. final boolean geoDetectionEnabled = autoDetectionEnabled; return new ConfigurationInternal.Builder(ARBITRARY_USER_ID) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setUserConfigAllowed(true) .setAutoDetectionEnabled(autoDetectionEnabled) .setLocationEnabled(geoDetectionEnabled) diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index c8dba5f40882b..f1f8b2f5e81a0 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -90,8 +90,8 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_DISABLED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(false) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(false) .setLocationEnabled(true) .setGeoDetectionEnabled(false) @@ -100,8 +100,8 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_USER_RESTRICTED_AUTO_ENABLED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(false) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) .setGeoDetectionEnabled(true) @@ -110,8 +110,8 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_DETECT_NOT_SUPPORTED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionSupported(false) - .setGeoDetectionSupported(false) + .setAutoDetectionFeatureSupported(false) + .setGeoDetectionFeatureSupported(false) .setAutoDetectionEnabled(false) .setLocationEnabled(true) .setGeoDetectionEnabled(false) @@ -120,8 +120,8 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_SUPPORTED_GEO_NOT_SUPPORTED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(false) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(false) .setAutoDetectionEnabled(true) .setLocationEnabled(true) .setGeoDetectionEnabled(true) @@ -130,8 +130,8 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_DISABLED_GEO_DISABLED = new ConfigurationInternal.Builder(USER_ID) .setUserConfigAllowed(true) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(false) .setLocationEnabled(true) .setGeoDetectionEnabled(false) @@ -139,8 +139,8 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_DISABLED = new ConfigurationInternal.Builder(USER_ID) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setUserConfigAllowed(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) @@ -149,8 +149,8 @@ public class TimeZoneDetectorStrategyImplTest { private static final ConfigurationInternal CONFIG_INT_AUTO_ENABLED_GEO_ENABLED = new ConfigurationInternal.Builder(USER_ID) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setUserConfigAllowed(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java index d319488ba73b9..8280cdcb18c4b 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/TestSupport.java @@ -44,8 +44,8 @@ final class TestSupport { @UserIdInt int userId, boolean geoDetectionEnabled) { return new ConfigurationInternal.Builder(userId) .setUserConfigAllowed(true) - .setAutoDetectionSupported(true) - .setGeoDetectionSupported(true) + .setAutoDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) .setAutoDetectionEnabled(true) .setLocationEnabled(true) .setGeoDetectionEnabled(geoDetectionEnabled)