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

Commit 8164e677 authored by Neil Fuller's avatar Neil Fuller
Browse files

Change TimeZoneDetectorStrategyImpl to allow geo

Change TimeZoneDetectorStrategyImpl to allow a new "geo only" mode.

The strategy can now exist in one of two modes:
1) Telephony signals only
2) Geolocation signals only

They may later joined by a third "hybrid" mode where we can
experiment with how to blend the two (if that seems like it will provide
better results), or perform a fallback from one to the other.

Note that nothing is actually making Geolocation-based suggestions yet.
The shell command line can be used to simulate geolocation suggestions
in the meantime.

This commit doesn't contain real settings logic: the settings storage and
logic will be added in a follow-up commit.

Bug: 149014708
Test: atest com.android.server.timezonedetector
Test: atest core/tests/coretests/src/android/app/timezonedetector/
Change-Id: I83f8f64d40255567c035a67741b18ecaf6f0561d
parent 4676898b
Loading
Loading
Loading
Loading
+30 −3
Original line number Diff line number Diff line
@@ -91,11 +91,13 @@ public final class TimeZoneCapabilities implements Parcelable {

    private final @UserIdInt int mUserId;
    private final @CapabilityState int mConfigureAutoDetectionEnabled;
    private final @CapabilityState int mConfigureGeoDetectionEnabled;
    private final @CapabilityState int mSuggestManualTimeZone;

    private TimeZoneCapabilities(@NonNull Builder builder) {
        this.mUserId = builder.mUserId;
        this.mConfigureAutoDetectionEnabled = builder.mConfigureAutoDetectionEnabled;
        this.mConfigureGeoDetectionEnabled = builder.mConfigureGeoDetectionEnabled;
        this.mSuggestManualTimeZone = builder.mSuggestManualTimeZone;
    }

@@ -103,6 +105,7 @@ public final class TimeZoneCapabilities implements Parcelable {
    private static TimeZoneCapabilities createFromParcel(Parcel in) {
        return new TimeZoneCapabilities.Builder(in.readInt())
                .setConfigureAutoDetectionEnabled(in.readInt())
                .setConfigureGeoDetectionEnabled(in.readInt())
                .setSuggestManualTimeZone(in.readInt())
                .build();
    }
@@ -111,6 +114,7 @@ public final class TimeZoneCapabilities implements Parcelable {
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(mUserId);
        dest.writeInt(mConfigureAutoDetectionEnabled);
        dest.writeInt(mConfigureGeoDetectionEnabled);
        dest.writeInt(mSuggestManualTimeZone);
    }

@@ -120,8 +124,8 @@ public final class TimeZoneCapabilities implements Parcelable {
    }

    /**
     * Returns the user's capability state for controlling automatic time zone detection via
     * {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
     * Returns the user's capability state for controlling whether automatic time zone detection is
     * enabled via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
     * TimeZoneConfiguration#isAutoDetectionEnabled()}.
     */
    @CapabilityState
@@ -129,6 +133,16 @@ public final class TimeZoneCapabilities implements Parcelable {
        return mConfigureAutoDetectionEnabled;
    }

    /**
     * Returns the user's capability state for controlling whether geolocation can be used to detect
     * time zone via {@link TimeZoneDetector#updateConfiguration(TimeZoneConfiguration)} and {@link
     * TimeZoneConfiguration#isGeoDetectionEnabled()}.
     */
    @CapabilityState
    public int getConfigureGeoDetectionEnabled() {
        return mConfigureGeoDetectionEnabled;
    }

    /**
     * Returns the user's capability state for manually setting the time zone on a device via
     * {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}.
@@ -157,12 +171,16 @@ public final class TimeZoneCapabilities implements Parcelable {
        TimeZoneCapabilities that = (TimeZoneCapabilities) o;
        return mUserId == that.mUserId
                && mConfigureAutoDetectionEnabled == that.mConfigureAutoDetectionEnabled
                && mConfigureGeoDetectionEnabled == that.mConfigureGeoDetectionEnabled
                && mSuggestManualTimeZone == that.mSuggestManualTimeZone;
    }

    @Override
    public int hashCode() {
        return Objects.hash(mUserId, mConfigureAutoDetectionEnabled, mSuggestManualTimeZone);
        return Objects.hash(mUserId,
                mConfigureAutoDetectionEnabled,
                mConfigureGeoDetectionEnabled,
                mSuggestManualTimeZone);
    }

    @Override
@@ -170,6 +188,7 @@ public final class TimeZoneCapabilities implements Parcelable {
        return "TimeZoneDetectorCapabilities{"
                + "mUserId=" + mUserId
                + ", mConfigureAutomaticDetectionEnabled=" + mConfigureAutoDetectionEnabled
                + ", mConfigureGeoDetectionEnabled=" + mConfigureGeoDetectionEnabled
                + ", mSuggestManualTimeZone=" + mSuggestManualTimeZone
                + '}';
    }
@@ -179,6 +198,7 @@ public final class TimeZoneCapabilities implements Parcelable {

        private final @UserIdInt int mUserId;
        private @CapabilityState int mConfigureAutoDetectionEnabled;
        private @CapabilityState int mConfigureGeoDetectionEnabled;
        private @CapabilityState int mSuggestManualTimeZone;

        /**
@@ -194,6 +214,12 @@ public final class TimeZoneCapabilities implements Parcelable {
            return this;
        }

        /** Sets the state for the geolocation time zone detection enabled config. */
        public Builder setConfigureGeoDetectionEnabled(@CapabilityState int value) {
            this.mConfigureGeoDetectionEnabled = value;
            return this;
        }

        /** Sets the state for the suggestManualTimeZone action. */
        public Builder setSuggestManualTimeZone(@CapabilityState int value) {
            this.mSuggestManualTimeZone = value;
@@ -204,6 +230,7 @@ public final class TimeZoneCapabilities implements Parcelable {
        @NonNull
        public TimeZoneCapabilities build() {
            verifyCapabilitySet(mConfigureAutoDetectionEnabled, "configureAutoDetectionEnabled");
            verifyCapabilitySet(mConfigureGeoDetectionEnabled, "configureGeoDetectionEnabled");
            verifyCapabilitySet(mSuggestManualTimeZone, "suggestManualTimeZone");
            return new TimeZoneCapabilities(this);
        }
+34 −1
Original line number Diff line number Diff line
@@ -67,6 +67,10 @@ public final class TimeZoneConfiguration implements Parcelable {
    @Property
    public static final String PROPERTY_AUTO_DETECTION_ENABLED = "autoDetectionEnabled";

    /** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */
    @Property
    public static final String PROPERTY_GEO_DETECTION_ENABLED = "geoDetectionEnabled";

    private final Bundle mBundle;

    private TimeZoneConfiguration(Builder builder) {
@@ -86,7 +90,8 @@ public final class TimeZoneConfiguration implements Parcelable {

    /** Returns {@code true} if all known properties are set. */
    public boolean isComplete() {
        return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED);
        return hasProperty(PROPERTY_AUTO_DETECTION_ENABLED)
                && hasProperty(PROPERTY_GEO_DETECTION_ENABLED);
    }

    /** Returns true if the specified property is set. */
@@ -108,6 +113,28 @@ public final class TimeZoneConfiguration implements Parcelable {
        return mBundle.getBoolean(PROPERTY_AUTO_DETECTION_ENABLED);
    }

    /**
     * Returns the value of the {@link #PROPERTY_GEO_DETECTION_ENABLED} property. This
     * controls whether a device can use location to determine time zone. Only used when
     * {@link #isAutoDetectionEnabled()} is true.
     *
     * @throws IllegalStateException if the field has not been set
     */
    public boolean isGeoDetectionEnabled() {
        if (!mBundle.containsKey(PROPERTY_GEO_DETECTION_ENABLED)) {
            throw new IllegalStateException(PROPERTY_GEO_DETECTION_ENABLED + " is not set");
        }
        return mBundle.getBoolean(PROPERTY_GEO_DETECTION_ENABLED);
    }

    /**
     * Convenience method to merge this with another. The argument configuration properties have
     * precedence.
     */
    public TimeZoneConfiguration with(TimeZoneConfiguration other) {
        return new Builder(this).mergeProperties(other).build();
    }

    @Override
    public int describeContents() {
        return 0;
@@ -174,6 +201,12 @@ public final class TimeZoneConfiguration implements Parcelable {
            return this;
        }

        /** Sets the desired state of the geolocation time zone detection enabled property. */
        public Builder setGeoDetectionEnabled(boolean enabled) {
            this.mBundle.putBoolean(PROPERTY_GEO_DETECTION_ENABLED, enabled);
            return this;
        }

        /** Returns the {@link TimeZoneConfiguration}. */
        @NonNull
        public TimeZoneConfiguration build() {
+20 −0
Original line number Diff line number Diff line
@@ -33,9 +33,11 @@ public class TimeZoneCapabilitiesTest {
    public void testEquals() {
        TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
                .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
                .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
                .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
        TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
                .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
                .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
                .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
        {
            TimeZoneCapabilities one = builder1.build();
@@ -57,6 +59,20 @@ public class TimeZoneCapabilitiesTest {
            assertEquals(one, two);
        }

        builder2.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
        {
            TimeZoneCapabilities one = builder1.build();
            TimeZoneCapabilities two = builder2.build();
            assertNotEquals(one, two);
        }

        builder1.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
        {
            TimeZoneCapabilities one = builder1.build();
            TimeZoneCapabilities two = builder2.build();
            assertEquals(one, two);
        }

        builder2.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
        {
            TimeZoneCapabilities one = builder1.build();
@@ -76,12 +92,16 @@ public class TimeZoneCapabilitiesTest {
    public void testParcelable() {
        TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(ARBITRARY_USER_ID)
                .setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED)
                .setConfigureGeoDetectionEnabled(CAPABILITY_POSSESSED)
                .setSuggestManualTimeZone(CAPABILITY_POSSESSED);
        assertRoundTripParcelable(builder.build());

        builder.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
        assertRoundTripParcelable(builder.build());

        builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_ALLOWED);
        assertRoundTripParcelable(builder.build());

        builder.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED);
        assertRoundTripParcelable(builder.build());
    }
+38 −11
Original line number Diff line number Diff line
@@ -29,8 +29,9 @@ public class TimeZoneConfigurationTest {

    @Test
    public void testBuilder_copyConstructor() {
        TimeZoneConfiguration.Builder builder1 =
                new TimeZoneConfiguration.Builder().setAutoDetectionEnabled(true);
        TimeZoneConfiguration.Builder builder1 = new TimeZoneConfiguration.Builder()
                .setAutoDetectionEnabled(true)
                .setGeoDetectionEnabled(true);
        TimeZoneConfiguration configuration1 = builder1.build();

        TimeZoneConfiguration configuration2 =
@@ -41,16 +42,15 @@ public class TimeZoneConfigurationTest {

    @Test
    public void testIsComplete() {
        TimeZoneConfiguration incompleteConfiguration =
                new TimeZoneConfiguration.Builder()
                        .build();
        assertFalse(incompleteConfiguration.isComplete());
        TimeZoneConfiguration.Builder builder =
                new TimeZoneConfiguration.Builder();
        assertFalse(builder.build().isComplete());

        TimeZoneConfiguration completeConfiguration =
                new TimeZoneConfiguration.Builder()
                        .setAutoDetectionEnabled(true)
                        .build();
        assertTrue(completeConfiguration.isComplete());
        builder.setAutoDetectionEnabled(true);
        assertFalse(builder.build().isComplete());

        builder.setGeoDetectionEnabled(true);
        assertTrue(builder.build().isComplete());
    }

    @Test
@@ -122,6 +122,27 @@ public class TimeZoneConfigurationTest {
            TimeZoneConfiguration two = builder2.build();
            assertEquals(one, two);
        }

        builder1.setGeoDetectionEnabled(true);
        {
            TimeZoneConfiguration one = builder1.build();
            TimeZoneConfiguration two = builder2.build();
            assertNotEquals(one, two);
        }

        builder2.setGeoDetectionEnabled(false);
        {
            TimeZoneConfiguration one = builder1.build();
            TimeZoneConfiguration two = builder2.build();
            assertNotEquals(one, two);
        }

        builder1.setGeoDetectionEnabled(false);
        {
            TimeZoneConfiguration one = builder1.build();
            TimeZoneConfiguration two = builder2.build();
            assertEquals(one, two);
        }
    }

    @Test
@@ -135,5 +156,11 @@ public class TimeZoneConfigurationTest {

        builder.setAutoDetectionEnabled(false);
        assertRoundTripParcelable(builder.build());

        builder.setGeoDetectionEnabled(false);
        assertRoundTripParcelable(builder.build());

        builder.setGeoDetectionEnabled(true);
        assertRoundTripParcelable(builder.build());
    }
}
+18 −2
Original line number Diff line number Diff line
@@ -72,6 +72,10 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
            builder.setConfigureAutoDetectionEnabled(CAPABILITY_POSSESSED);
        }

        // TODO(b/149014708) Replace this with real logic when the settings storage is fully
        // implemented.
        builder.setConfigureGeoDetectionEnabled(CAPABILITY_NOT_SUPPORTED);

        // The ability to make manual time zone suggestions can also be restricted by policy. With
        // the current logic above, this could lead to a situation where a device hardware does not
        // support auto detection, the device has been forced into "auto" mode by an admin and the
@@ -90,6 +94,7 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
    public TimeZoneConfiguration getConfiguration(@UserIdInt int userId) {
        return new TimeZoneConfiguration.Builder()
                .setAutoDetectionEnabled(isAutoDetectionEnabled())
                .setGeoDetectionEnabled(isGeoDetectionEnabled())
                .build();
    }

@@ -105,8 +110,11 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
        // detection: if we wrote it down then we'd set the default explicitly. That might influence
        // what happens on later releases that do support auto detection on the same hardware.
        if (isAutoDetectionSupported()) {
            final int value = configuration.isAutoDetectionEnabled() ? 1 : 0;
            Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, value);
            final int autoEnabledValue = configuration.isAutoDetectionEnabled() ? 1 : 0;
            Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, autoEnabledValue);

            final boolean geoTzDetectionEnabledValue = configuration.isGeoDetectionEnabled();
            // TODO(b/149014708) Write this down to user-scoped settings once implemented.
        }
    }

@@ -125,6 +133,14 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
        return false;
    }

    @Override
    public boolean isGeoDetectionEnabled() {
        // TODO(b/149014708) Read this from user-scoped settings once implemented. The user's
        //  location toggle will act as an override for this setting, i.e. so that the setting will
        //  return false if the location toggle is disabled.
        return false;
    }

    @Override
    public boolean isDeviceTimeZoneInitialized() {
        // timezone.equals("GMT") will be true and only true if the time zone was
Loading