diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 89b768d7dff70..5137bc14339ff 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11849,7 +11849,13 @@ public final class Settings { /** * Value to specify if the device's UTC system clock should be set automatically, e.g. using - * telephony signals like NITZ, or other sources like GNSS or NTP. 1=yes, 0=no (manual) + * telephony signals like NITZ, or other sources like GNSS or NTP. + * + *

Prefer {@link android.app.time.TimeManager} API calls to determine the state of + * automatic time detection instead of directly observing this setting as it may be ignored + * by the time_detector service under various conditions. + * + *

1=yes, 0=no (manual) */ @Readable public static final String AUTO_TIME = "auto_time"; @@ -11857,11 +11863,34 @@ public final class Settings { /** * Value to specify if the device's time zone system property should be set automatically, * e.g. using telephony signals like MCC and NITZ, or other mechanisms like the location. - * 1=yes, 0=no (manual). + * + *

Prefer {@link android.app.time.TimeManager} API calls to determine the state of + * automatic time zone detection instead of directly observing this setting as it may be + * ignored by the time_zone_detector service under various conditions. + * + *

1=yes, 0=no (manual). */ @Readable public static final String AUTO_TIME_ZONE = "auto_time_zone"; + /** + * Records whether an explicit preference for {@link #AUTO_TIME_ZONE} has been expressed + * instead of the current value being the default. This value is used to tell if the {@link + * #AUTO_TIME_ZONE} value can be influenced by experiment flags that alter the setting's + * value for internal testers: once the user indicates a preference they leave the + * experiment, only users that are still using the default will be affected by the flag. + * + *

Since {@link #AUTO_TIME_ZONE} can be altered by components besides the system server, + * and not just via the time_zone_detector logic that sets this value, this isn't guaranteed + * to be set when the device diverges from the default in all cases. Important AOSP system + * components like SettingsUI do use the time_zone_detector APIs. + * + *

1="has been set explicitly" + * + * @hide + */ + public static final String AUTO_TIME_ZONE_EXPLICIT = "auto_time_zone_explicit"; + /** * URI for the car dock "in" event sound. * @hide diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index e0e37200219ca..a9d14641af9a4 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -137,6 +137,7 @@ public class SettingsBackupTest { Settings.Global.AUTOFILL_LOGGING_LEVEL, Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, + Settings.Global.AUTO_TIME_ZONE_EXPLICIT, Settings.Global.AVERAGE_TIME_TO_DISCHARGE, Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java index 28d34c26e0ddf..2049a0288f5a4 100644 --- a/services/core/java/com/android/server/timedetector/ServerFlags.java +++ b/services/core/java/com/android/server/timedetector/ServerFlags.java @@ -69,6 +69,7 @@ public final class ServerFlags { KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE, KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE, + KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT, KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED, KEY_ENHANCED_METRICS_COLLECTION_ENABLED, }) @@ -153,6 +154,14 @@ public final class ServerFlags { KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT = "location_time_zone_detection_setting_enabled_default"; + /** + * The key to alter a device's "automatic time zone detection enabled" setting default value. + * This flag is only intended for internal testing. + */ + public static final @DeviceConfigKey String + KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT = + "time_zone_detector_auto_detection_enabled_default"; + /** * The key to control support for time zone detection falling back to telephony detection under * certain circumstances. diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java index 6ebaf14c28dbe..a71f9c7f90863 100644 --- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java +++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java @@ -64,6 +64,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { ServerFlags.KEY_ENHANCED_METRICS_COLLECTION_ENABLED, ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE, + ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT, ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED ); @@ -174,7 +175,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { } }, filter, null, null /* main thread */); - // Add async callbacks for global settings being changed. + // Add async callbacks for changes to global settings that influence behavior. ContentResolver contentResolver = mContext.getContentResolver(); ContentObserver contentObserver = new ContentObserver(mContext.getMainThreadHandler()) { @Override @@ -184,6 +185,9 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { }; contentResolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, contentObserver); + contentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE_EXPLICIT), true, + contentObserver); // Add async callbacks for user scoped location settings being changed. contentResolver.registerContentObserver( @@ -239,8 +243,9 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { @Override public synchronized boolean updateConfiguration(@UserIdInt int userId, - @NonNull TimeZoneConfiguration requestedConfiguration, boolean bypassUserPolicyChecks) { - Objects.requireNonNull(requestedConfiguration); + @NonNull TimeZoneConfiguration requestedConfigurationUpdates, + boolean bypassUserPolicyChecks) { + Objects.requireNonNull(requestedConfigurationUpdates); ConfigurationInternal configurationInternal = getConfigurationInternal(userId); TimeZoneCapabilities capabilities = @@ -248,7 +253,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { TimeZoneConfiguration oldConfiguration = configurationInternal.asConfiguration(); final TimeZoneConfiguration newConfiguration = - capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfiguration); + capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfigurationUpdates); if (newConfiguration == null) { // The changes could not be made because the user's capabilities do not allow it. return false; @@ -256,7 +261,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { // Store the configuration / notify as needed. This will cause the mEnvironment to invoke // handleConfigChanged() asynchronously. - storeConfiguration(userId, newConfiguration); + storeConfiguration(userId, requestedConfigurationUpdates, newConfiguration); return true; } @@ -268,15 +273,20 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { */ @GuardedBy("this") private void storeConfiguration(@UserIdInt int userId, - @NonNull TimeZoneConfiguration configuration) { - Objects.requireNonNull(configuration); + @NonNull TimeZoneConfiguration requestedConfigurationUpdates, + @NonNull TimeZoneConfiguration newConfiguration) { + Objects.requireNonNull(newConfiguration); // Avoid writing the auto detection enabled setting for devices that do not support auto // 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 (isAutoDetectionFeatureSupported()) { - final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled(); + if (requestedConfigurationUpdates.hasIsAutoDetectionEnabled()) { + // Record that the auto detection enabled setting has now been set explicitly. + Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE_EXPLICIT, 1); + } + final boolean autoDetectionEnabled = newConfiguration.isAutoDetectionEnabled(); setAutoDetectionEnabledIfRequired(autoDetectionEnabled); // Only write the geo detection enabled setting when its values is used, e.g.: @@ -288,10 +298,10 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { // Not being able to detect if the user has actually expressed a preference could // influence what happens on later releases that start to support geo detection on the // user's same hardware. - if (!getGeoDetectionSettingEnabledOverride().isPresent() + if (getGeoDetectionSettingEnabledOverride().isEmpty() && isGeoTimeZoneDetectionFeatureSupported() && isTelephonyTimeZoneDetectionFeatureSupported()) { - final boolean geoDetectionEnabledSetting = configuration.isGeoDetectionEnabled(); + final boolean geoDetectionEnabledSetting = newConfiguration.isGeoDetectionEnabled(); setGeoDetectionEnabledSettingIfRequired(userId, geoDetectionEnabledSetting); } } @@ -335,7 +345,31 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { } private boolean getAutoDetectionEnabledSetting() { - return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0; + boolean autoDetectionEnabledSetting = + Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0; + + Optional optionalFlagValue = mServerFlags.getOptionalBoolean( + ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT); + if (optionalFlagValue.isPresent()) { + // This branch is rare: it is expected to happen only for internal testers. + + if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE_EXPLICIT, 0) == 0) { + // The device hasn't explicitly had the auto detection enabled setting updated via a + // call to storeConfiguration(). This means the device is allowed to use a server + // flag to determine the default. + boolean flagValue = optionalFlagValue.get(); + + // Best effort to keep the setting in sync with the flag in case something is + // observing the (public API) Settings.Global.AUTO_TIME_ZONE directly. This change + // will cause listeners to fire asynchronously but any cascade should stop after one + // round. + if (flagValue != autoDetectionEnabledSetting) { + Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, flagValue ? 1 : 0); + } + autoDetectionEnabledSetting = flagValue; + } + } + return autoDetectionEnabledSetting; } private boolean getGeoDetectionEnabledSetting(@UserIdInt int userId) { diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java index ab68e834d3377..d1ddb581c0292 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java @@ -37,6 +37,7 @@ import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_RUN_IN_BACKGROUND_ENABLED; import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT; import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE; +import static com.android.server.timedetector.ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT; import static com.android.server.timedetector.ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED; import android.app.time.LocationTimeZoneManager; @@ -308,6 +309,10 @@ class TimeZoneDetectorShellCommand extends ShellCommand { pw.printf(" %s\n", KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE); pw.printf(" Used to override the device's 'geolocation time zone detection enabled'" + " setting [*].\n"); + pw.printf(" %s\n", KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT); + pw.printf(" Used to set the automatic time zone detection enabled default, i.e. when the" + + " device's automatic time zone detection enabled setting hasn't been set" + + " explicitly. Intended for internal testers."); pw.printf(" %s\n", KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED); pw.printf(" Used to enable / disable support for telephony detection fallback. Also see" + " the %s command.\n", SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK);