Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2856d9e5 authored by Neil Fuller's avatar Neil Fuller
Browse files

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
<Confirm the settings value cannot be changed by user>

adb shell cmd device_config put \
    system_time location_time_zone_detection_setting_enabled_override false
<Confirm the settings value can be changed by user>

adb shell cmd device_config delete \
    system_time location_time_zone_detection_setting_enabled_override
<Confirm it returns to normal>

Disabling the feature / location_time_zone_manager:
adb shell cmd device_config put \
    system_time location_time_zone_detection_feature_supported false
<Confirm SettingsUI (after restart) doesn't show the geo detection option>
<Confirm manager is not started>

Enabling the feature / location_time_zone_manager:
adb shell cmd device_config put \
    system_time location_time_zone_detection_feature_supported true
<Confirm manager is restarted>

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
parent 35c53e2a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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).
+238 −0
Original line number Diff line number Diff line
@@ -20,49 +20,74 @@ 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.concurrent.Executor;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

/**
 * A helper class for reading / monitoring the {@link
 * android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME} namespace for server-configured flags.
 * A helper class for reading / monitoring the {@link DeviceConfig#NAMESPACE_SYSTEM_TIME} namespace
 * for server-configured flags.
 */
public final class DeviceConfig {
public final class ServerFlags {

    private static final Optional<Boolean> OPTIONAL_TRUE = Optional.of(true);
    private static final Optional<Boolean> OPTIONAL_FALSE = Optional.of(false);

    /**
     * An annotation used to indicate when a {@link
     * android.provider.DeviceConfig#NAMESPACE_SYSTEM_TIME} key is required.
     * An annotation used to indicate when a {@link DeviceConfig#NAMESPACE_SYSTEM_TIME} key is
     * required.
     *
     * <p>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
     * also shares the {@link 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_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 {}

    /**
     * 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.
     * 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_FORCE_LOCATION_TIME_ZONE_DETECTION_ENABLED =
            "force_location_time_zone_detection_enabled";
    public static final String KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED =
            "location_time_zone_detection_feature_supported";

    /**
     * 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.
     * 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_LOCATION_TIME_ZONE_DETECTION_ENABLED_DEFAULT =
            "location_time_zone_detection_enabled_default";
    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
@@ -89,35 +114,122 @@ public final class DeviceConfig {
    public static final String KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS =
            "ltpz_init_timeout_fuzz_millis";

    /** Creates an instance. */
    public DeviceConfig() {}
    /**
     * 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";

    /** Adds a listener for the system_time namespace. */
    public void addListener(
            @NonNull Executor handlerExecutor, @NonNull Runnable listener) {
        android.provider.DeviceConfig.addOnPropertiesChangedListener(
    /**
     * 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<ConfigurationChangeListener, Set<String>> 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,
                handlerExecutor,
                properties -> listener.run());
                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<ConfigurationChangeListener, Set<String>> listenerEntry
                    : mListeners.entrySet()) {
                if (intersects(listenerEntry.getValue(), properties.getKeyset())) {
                    listenerEntry.getKey().onChange();
                }
            }
        }
    }

    private static boolean intersects(@NonNull Set<String> one, @NonNull Set<String> 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.
     *
     * <p>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<String> 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<Boolean> getOptionalBoolean(@DeviceConfigKey String key) {
        String value = DeviceConfig.getProperty(NAMESPACE_SYSTEM_TIME, key);
        return parseOptionalBoolean(value);
    }

    @NonNull
    private static Optional<Boolean> 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 android.provider.DeviceConfig} from the system_time
     * 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 android.provider.DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue);
        return DeviceConfig.getBoolean(NAMESPACE_SYSTEM_TIME, key, defaultValue);
    }

    /**
     * Returns a positive duration from {@link android.provider.DeviceConfig} from the system_time
     * 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 =
                android.provider.DeviceConfig.getLong(NAMESPACE_SYSTEM_TIME, key, -1);
        long deviceConfigValue = DeviceConfig.getLong(NAMESPACE_SYSTEM_TIME, key, -1);
        if (deviceConfigValue < 0) {
            return defaultValue;
        }
+3 −2
Original line number Diff line number Diff line
@@ -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();
}
+26 −25
Original line number Diff line number Diff line
@@ -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;
        }
+28 −55
Original line number Diff line number Diff line
@@ -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<Boolean> 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);
    }
}
Loading