Add "Use location" state to TimeZoneCapabilities

Add the user's "Use location" state to TimeZoneCapabilities. This
information is available anyway and saves the SettingsUI needing to call
LocationManager directly (with the small possibility it would get an
inconsistent answer).

Bug: 262407244
Test: atest core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
Change-Id: I0369bd4907584ebd741d47b762792ffbb23c36bf
diff --git a/core/java/android/app/time/TimeZoneCapabilities.java b/core/java/android/app/time/TimeZoneCapabilities.java
index b647fc3..4dee159 100644
--- a/core/java/android/app/time/TimeZoneCapabilities.java
+++ b/core/java/android/app/time/TimeZoneCapabilities.java
@@ -57,6 +57,16 @@
      */
     @NonNull private final UserHandle mUserHandle;
     private final @CapabilityState int mConfigureAutoDetectionEnabledCapability;
+
+    /**
+     * The values of the user's "Use location" value, AKA the Master Location Switch.
+     *
+     * <p>This is only exposed for SettingsUI and so is not part of the SDK API.
+     *
+     * <p>This is not treated as a CapabilityState as it's a boolean value that all user's have.
+     */
+    private final boolean mUseLocationEnabled;
+
     private final @CapabilityState int mConfigureGeoDetectionEnabledCapability;
     private final @CapabilityState int mSetManualTimeZoneCapability;
 
@@ -64,6 +74,7 @@
         this.mUserHandle = Objects.requireNonNull(builder.mUserHandle);
         this.mConfigureAutoDetectionEnabledCapability =
                 builder.mConfigureAutoDetectionEnabledCapability;
+        this.mUseLocationEnabled = builder.mUseLocationEnabled;
         this.mConfigureGeoDetectionEnabledCapability =
                 builder.mConfigureGeoDetectionEnabledCapability;
         this.mSetManualTimeZoneCapability = builder.mSetManualTimeZoneCapability;
@@ -74,6 +85,7 @@
         UserHandle userHandle = UserHandle.readFromParcel(in);
         return new TimeZoneCapabilities.Builder(userHandle)
                 .setConfigureAutoDetectionEnabledCapability(in.readInt())
+                .setUseLocationEnabled(in.readBoolean())
                 .setConfigureGeoDetectionEnabledCapability(in.readInt())
                 .setSetManualTimeZoneCapability(in.readInt())
                 .build();
@@ -83,6 +95,7 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         UserHandle.writeToParcel(mUserHandle, dest);
         dest.writeInt(mConfigureAutoDetectionEnabledCapability);
+        dest.writeBoolean(mUseLocationEnabled);
         dest.writeInt(mConfigureGeoDetectionEnabledCapability);
         dest.writeInt(mSetManualTimeZoneCapability);
     }
@@ -98,6 +111,20 @@
     }
 
     /**
+     * Returns {@code true} if the device's location can be used by the Android system, and
+     * therefore the platform components running on behalf of the user. At the time of writing, the
+     * user can change this via the "Use location" setting on the Location settings screen.
+     *
+     * Not part of the SDK API because it is intended for use by SettingsUI, which can display
+     * text about needing it to be on for location-based time zone detection.
+     * @hide
+     *
+     */
+    public boolean isUseLocationEnabled() {
+        return mUseLocationEnabled;
+    }
+
+    /**
      * Returns the capability state associated with the user's ability to modify the geolocation
      * detection setting. The setting can be updated via {@link
      * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}.
@@ -167,6 +194,7 @@
         return mUserHandle.equals(that.mUserHandle)
                 && mConfigureAutoDetectionEnabledCapability
                 == that.mConfigureAutoDetectionEnabledCapability
+                && mUseLocationEnabled == that.mUseLocationEnabled
                 && mConfigureGeoDetectionEnabledCapability
                 == that.mConfigureGeoDetectionEnabledCapability
                 && mSetManualTimeZoneCapability == that.mSetManualTimeZoneCapability;
@@ -184,6 +212,7 @@
                 + "mUserHandle=" + mUserHandle
                 + ", mConfigureAutoDetectionEnabledCapability="
                 + mConfigureAutoDetectionEnabledCapability
+                + ", mUseLocationEnabled=" + mUseLocationEnabled
                 + ", mConfigureGeoDetectionEnabledCapability="
                 + mConfigureGeoDetectionEnabledCapability
                 + ", mSetManualTimeZoneCapability=" + mSetManualTimeZoneCapability
@@ -199,6 +228,7 @@
 
         @NonNull private UserHandle mUserHandle;
         private @CapabilityState int mConfigureAutoDetectionEnabledCapability;
+        private Boolean mUseLocationEnabled;
         private @CapabilityState int mConfigureGeoDetectionEnabledCapability;
         private @CapabilityState int mSetManualTimeZoneCapability;
 
@@ -211,6 +241,7 @@
             mUserHandle = capabilitiesToCopy.mUserHandle;
             mConfigureAutoDetectionEnabledCapability =
                 capabilitiesToCopy.mConfigureAutoDetectionEnabledCapability;
+            mUseLocationEnabled = capabilitiesToCopy.mUseLocationEnabled;
             mConfigureGeoDetectionEnabledCapability =
                 capabilitiesToCopy.mConfigureGeoDetectionEnabledCapability;
             mSetManualTimeZoneCapability =
@@ -223,6 +254,12 @@
             return this;
         }
 
+        /** Sets the values for "use location". See {@link #isUseLocationEnabled()}. */
+        public Builder setUseLocationEnabled(boolean useLocation) {
+            mUseLocationEnabled = useLocation;
+            return this;
+        }
+
         /**
          * Sets the value for the "configure geolocation time zone detection enabled" capability.
          */
@@ -242,6 +279,7 @@
         public TimeZoneCapabilities build() {
             verifyCapabilitySet(mConfigureAutoDetectionEnabledCapability,
                     "configureAutoDetectionEnabledCapability");
+            Objects.requireNonNull(mUseLocationEnabled, "useLocationEnabled");
             verifyCapabilitySet(mConfigureGeoDetectionEnabledCapability,
                     "configureGeoDetectionEnabledCapability");
             verifyCapabilitySet(mSetManualTimeZoneCapability,
diff --git a/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java b/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
index 8bed31f..6636cbd 100644
--- a/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
+++ b/core/tests/coretests/src/android/app/time/TimeZoneCapabilitiesTest.java
@@ -44,10 +44,12 @@
     public void testEquals() {
         TimeZoneCapabilities.Builder builder1 = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                 .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+                .setUseLocationEnabled(true)
                 .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
                 .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED);
         TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                 .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+                .setUseLocationEnabled(true)
                 .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
                 .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED);
         {
@@ -70,6 +72,20 @@
             assertEquals(one, two);
         }
 
+        builder2.setUseLocationEnabled(false);
+        {
+            TimeZoneCapabilities one = builder1.build();
+            TimeZoneCapabilities two = builder2.build();
+            assertNotEquals(one, two);
+        }
+
+        builder1.setUseLocationEnabled(false);
+        {
+            TimeZoneCapabilities one = builder1.build();
+            TimeZoneCapabilities two = builder2.build();
+            assertEquals(one, two);
+        }
+
         builder2.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
         {
             TimeZoneCapabilities one = builder1.build();
@@ -103,6 +119,7 @@
     public void testParcelable() {
         TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                 .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+                .setUseLocationEnabled(true)
                 .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
                 .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED);
         assertRoundTripParcelable(builder.build());
@@ -110,6 +127,9 @@
         builder.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
         assertRoundTripParcelable(builder.build());
 
+        builder.setUseLocationEnabled(false);
+        assertRoundTripParcelable(builder.build());
+
         builder.setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED);
         assertRoundTripParcelable(builder.build());
 
@@ -126,6 +146,7 @@
                         .build();
         TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                 .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+                .setUseLocationEnabled(true)
                 .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
                 .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED)
                 .build();
@@ -149,6 +170,7 @@
                         .build();
         TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                 .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+                .setUseLocationEnabled(true)
                 .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
                 .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED)
                 .build();
@@ -164,6 +186,7 @@
     public void copyBuilder_copiesAllFields() {
         TimeZoneCapabilities capabilities = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                 .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+                .setUseLocationEnabled(true)
                 .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
                 .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED)
                 .build();
@@ -176,6 +199,24 @@
             TimeZoneCapabilities expectedCapabilities =
                     new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                             .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED)
+                            .setUseLocationEnabled(true)
+                            .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+                            .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED)
+                            .build();
+
+            assertThat(updatedCapabilities).isEqualTo(expectedCapabilities);
+        }
+
+        {
+            TimeZoneCapabilities updatedCapabilities =
+                    new TimeZoneCapabilities.Builder(capabilities)
+                            .setUseLocationEnabled(false)
+                            .build();
+
+            TimeZoneCapabilities expectedCapabilities =
+                    new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
+                            .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+                            .setUseLocationEnabled(false)
                             .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
                             .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED)
                             .build();
@@ -192,6 +233,7 @@
             TimeZoneCapabilities expectedCapabilities =
                     new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                             .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+                            .setUseLocationEnabled(true)
                             .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED)
                             .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED)
                             .build();
@@ -208,6 +250,7 @@
             TimeZoneCapabilities expectedCapabilities =
                     new TimeZoneCapabilities.Builder(TEST_USER_HANDLE)
                             .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
+                            .setUseLocationEnabled(true)
                             .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED)
                             .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED)
                             .build();
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 111b4f6..5fd70a8 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -243,6 +243,8 @@
         }
         builder.setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability);
 
+        builder.setUseLocationEnabled(mLocationEnabledSetting);
+
         boolean deviceHasLocationTimeZoneDetection = isGeoDetectionSupported();
         boolean deviceHasTelephonyDetection = isTelephonyDetectionSupported();