Loading services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java +7 −163 Original line number Diff line number Diff line Loading @@ -16,126 +16,44 @@ package com.android.server.timezonedetector; import static android.content.Intent.ACTION_USER_SWITCHED; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.time.TimeZoneConfiguration; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.location.LocationManager; import android.os.Handler; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import java.util.Objects; import java.util.Optional; /** * The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}. */ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment { private static final String LOG_TAG = TimeZoneDetectorService.TAG; private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; @NonNull private final Context mContext; @NonNull private final Handler mHandler; @NonNull private final ContentResolver mCr; @NonNull private final UserManager mUserManager; @NonNull private final ServiceConfigAccessor mServiceConfigAccessor; @NonNull private final LocationManager mLocationManager; // @NonNull after setConfigChangeListener() is called. @GuardedBy("this") private ConfigurationChangeListener mConfigChangeListener; EnvironmentImpl(@NonNull Context context, @NonNull Handler handler, @NonNull ServiceConfigAccessor serviceConfigAccessor) { mContext = Objects.requireNonNull(context); mHandler = Objects.requireNonNull(handler); mCr = context.getContentResolver(); mUserManager = context.getSystemService(UserManager.class); mLocationManager = context.getSystemService(LocationManager.class); mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor); // 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(); filter.addAction(ACTION_USER_SWITCHED); filter.addAction(LocationManager.MODE_CHANGED_ACTION); mContext.registerReceiverForAllUsers(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { handleConfigChangeOnHandlerThread(); } }, filter, null, mHandler); // 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, contentObserver); // Add async callbacks for user scoped location settings being changed. contentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED), true, contentObserver, UserHandle.USER_ALL); } private void handleConfigChangeOnHandlerThread() { synchronized (this) { if (mConfigChangeListener == null) { Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null"); } mConfigChangeListener.onChange(); } } @Override public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) { synchronized (this) { mConfigChangeListener = Objects.requireNonNull(listener); } public void setConfigurationInternalChangeListener( @NonNull ConfigurationChangeListener listener) { ConfigurationChangeListener configurationChangeListener = () -> mHandler.post(listener::onChange); mServiceConfigAccessor.addConfigurationInternalChangeListener(configurationChangeListener); } @Override public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) { return new ConfigurationInternal.Builder(userId) .setTelephonyDetectionFeatureSupported( mServiceConfigAccessor.isTelephonyTimeZoneDetectionFeatureSupported()) .setGeoDetectionFeatureSupported( mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) .setAutoDetectionEnabled(isAutoDetectionEnabled()) .setUserConfigAllowed(isUserConfigAllowed(userId)) .setLocationEnabled(isLocationEnabled(userId)) .setGeoDetectionEnabled(isGeoDetectionEnabled(userId)) .build(); } @Override public @UserIdInt int getCurrentUserId() { return LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId(); public ConfigurationInternal getCurrentUserConfigurationInternal() { return mServiceConfigAccessor.getCurrentUserConfigurationInternal(); } @Override Loading @@ -161,78 +79,4 @@ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class); alarmManager.setTimeZone(zoneId); } @Override public void storeConfiguration(@UserIdInt int userId, TimeZoneConfiguration configuration) { Objects.requireNonNull(configuration); // 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 (mServiceConfigAccessor.isAutoDetectionFeatureSupported()) { final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled(); setAutoDetectionEnabledIfRequired(autoDetectionEnabled); // 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); } } } private boolean isUserConfigAllowed(@UserIdInt int userId) { UserHandle userHandle = UserHandle.of(userId); return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle); } private boolean isAutoDetectionEnabled() { return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0; } private void setAutoDetectionEnabledIfRequired(boolean enabled) { // This check is racey, but the whole settings update process is racey. This check prevents // a ConfigurationChangeListener callback triggering due to ContentObserver's still // triggering *sometimes* for no-op updates. Because callbacks are async this is necessary // for stable behavior during tests. if (isAutoDetectionEnabled() != enabled) { Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, enabled ? 1 : 0); } } private boolean isLocationEnabled(@UserIdInt int userId) { return mLocationManager.isLocationEnabledForUser(UserHandle.of(userId)); } 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/off for testers (but only where their other settings would allow them to turn it on // for themselves). Optional<Boolean> override = mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride(); if (override.isPresent()) { return override.get(); } final boolean geoDetectionEnabledByDefault = mServiceConfigAccessor.isGeoDetectionEnabledForUsersByDefault(); return Settings.Secure.getIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, (geoDetectionEnabledByDefault ? 1 : 0) /* defaultValue */, userId) != 0; } private void setGeoDetectionEnabledIfRequired(@UserIdInt int userId, boolean enabled) { // See comment in setAutoDetectionEnabledIfRequired. http://b/171953500 if (isGeoDetectionEnabled(userId) != enabled) { Settings.Secure.putIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, enabled ? 1 : 0, userId); } } } Loading
services/core/java/com/android/server/timezonedetector/EnvironmentImpl.java +7 −163 Original line number Diff line number Diff line Loading @@ -16,126 +16,44 @@ package com.android.server.timezonedetector; import static android.content.Intent.ACTION_USER_SWITCHED; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.time.TimeZoneConfiguration; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.location.LocationManager; import android.os.Handler; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import java.util.Objects; import java.util.Optional; /** * The real implementation of {@link TimeZoneDetectorStrategyImpl.Environment}. */ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment { private static final String LOG_TAG = TimeZoneDetectorService.TAG; private static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; @NonNull private final Context mContext; @NonNull private final Handler mHandler; @NonNull private final ContentResolver mCr; @NonNull private final UserManager mUserManager; @NonNull private final ServiceConfigAccessor mServiceConfigAccessor; @NonNull private final LocationManager mLocationManager; // @NonNull after setConfigChangeListener() is called. @GuardedBy("this") private ConfigurationChangeListener mConfigChangeListener; EnvironmentImpl(@NonNull Context context, @NonNull Handler handler, @NonNull ServiceConfigAccessor serviceConfigAccessor) { mContext = Objects.requireNonNull(context); mHandler = Objects.requireNonNull(handler); mCr = context.getContentResolver(); mUserManager = context.getSystemService(UserManager.class); mLocationManager = context.getSystemService(LocationManager.class); mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor); // 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(); filter.addAction(ACTION_USER_SWITCHED); filter.addAction(LocationManager.MODE_CHANGED_ACTION); mContext.registerReceiverForAllUsers(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { handleConfigChangeOnHandlerThread(); } }, filter, null, mHandler); // 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, contentObserver); // Add async callbacks for user scoped location settings being changed. contentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED), true, contentObserver, UserHandle.USER_ALL); } private void handleConfigChangeOnHandlerThread() { synchronized (this) { if (mConfigChangeListener == null) { Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null"); } mConfigChangeListener.onChange(); } } @Override public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) { synchronized (this) { mConfigChangeListener = Objects.requireNonNull(listener); } public void setConfigurationInternalChangeListener( @NonNull ConfigurationChangeListener listener) { ConfigurationChangeListener configurationChangeListener = () -> mHandler.post(listener::onChange); mServiceConfigAccessor.addConfigurationInternalChangeListener(configurationChangeListener); } @Override public ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) { return new ConfigurationInternal.Builder(userId) .setTelephonyDetectionFeatureSupported( mServiceConfigAccessor.isTelephonyTimeZoneDetectionFeatureSupported()) .setGeoDetectionFeatureSupported( mServiceConfigAccessor.isGeoTimeZoneDetectionFeatureSupported()) .setAutoDetectionEnabled(isAutoDetectionEnabled()) .setUserConfigAllowed(isUserConfigAllowed(userId)) .setLocationEnabled(isLocationEnabled(userId)) .setGeoDetectionEnabled(isGeoDetectionEnabled(userId)) .build(); } @Override public @UserIdInt int getCurrentUserId() { return LocalServices.getService(ActivityManagerInternal.class).getCurrentUserId(); public ConfigurationInternal getCurrentUserConfigurationInternal() { return mServiceConfigAccessor.getCurrentUserConfigurationInternal(); } @Override Loading @@ -161,78 +79,4 @@ final class EnvironmentImpl implements TimeZoneDetectorStrategyImpl.Environment AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class); alarmManager.setTimeZone(zoneId); } @Override public void storeConfiguration(@UserIdInt int userId, TimeZoneConfiguration configuration) { Objects.requireNonNull(configuration); // 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 (mServiceConfigAccessor.isAutoDetectionFeatureSupported()) { final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled(); setAutoDetectionEnabledIfRequired(autoDetectionEnabled); // 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); } } } private boolean isUserConfigAllowed(@UserIdInt int userId) { UserHandle userHandle = UserHandle.of(userId); return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle); } private boolean isAutoDetectionEnabled() { return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0; } private void setAutoDetectionEnabledIfRequired(boolean enabled) { // This check is racey, but the whole settings update process is racey. This check prevents // a ConfigurationChangeListener callback triggering due to ContentObserver's still // triggering *sometimes* for no-op updates. Because callbacks are async this is necessary // for stable behavior during tests. if (isAutoDetectionEnabled() != enabled) { Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, enabled ? 1 : 0); } } private boolean isLocationEnabled(@UserIdInt int userId) { return mLocationManager.isLocationEnabledForUser(UserHandle.of(userId)); } 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/off for testers (but only where their other settings would allow them to turn it on // for themselves). Optional<Boolean> override = mServiceConfigAccessor.getGeoDetectionSettingEnabledOverride(); if (override.isPresent()) { return override.get(); } final boolean geoDetectionEnabledByDefault = mServiceConfigAccessor.isGeoDetectionEnabledForUsersByDefault(); return Settings.Secure.getIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, (geoDetectionEnabledByDefault ? 1 : 0) /* defaultValue */, userId) != 0; } private void setGeoDetectionEnabledIfRequired(@UserIdInt int userId, boolean enabled) { // See comment in setAutoDetectionEnabledIfRequired. http://b/171953500 if (isGeoDetectionEnabled(userId) != enabled) { Settings.Secure.putIntForUser(mCr, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, enabled ? 1 : 0, userId); } } }