• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.timezonedetector;
18 
19 import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
20 import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
21 import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
22 import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
23 
24 import android.annotation.IntDef;
25 import android.annotation.NonNull;
26 import android.annotation.UserIdInt;
27 import android.app.time.Capabilities.CapabilityState;
28 import android.app.time.TimeZoneCapabilities;
29 import android.app.time.TimeZoneConfiguration;
30 import android.os.UserHandle;
31 
32 import java.lang.annotation.ElementType;
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 import java.lang.annotation.Target;
36 import java.util.Objects;
37 
38 /**
39  * Holds configuration values that affect user-facing time zone behavior and some associated logic.
40  * Some configuration is global, some is user scoped, but this class deliberately doesn't make a
41  * distinction for simplicity.
42  */
43 public final class ConfigurationInternal {
44 
45     @IntDef(prefix = "DETECTION_MODE_",
46             value = { DETECTION_MODE_UNKNOWN, DETECTION_MODE_MANUAL, DETECTION_MODE_GEO,
47                     DETECTION_MODE_TELEPHONY }
48     )
49     @Retention(RetentionPolicy.SOURCE)
50     @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER })
51     @interface DetectionMode {};
52 
53     public static final @DetectionMode int DETECTION_MODE_UNKNOWN = 0;
54     public static final @DetectionMode int DETECTION_MODE_MANUAL = 1;
55     public static final @DetectionMode int DETECTION_MODE_GEO = 2;
56     public static final @DetectionMode int DETECTION_MODE_TELEPHONY = 3;
57 
58     private final boolean mTelephonyDetectionSupported;
59     private final boolean mGeoDetectionSupported;
60     private final boolean mTelephonyFallbackSupported;
61     private final boolean mGeoDetectionRunInBackgroundEnabled;
62     private final boolean mEnhancedMetricsCollectionEnabled;
63     private final boolean mAutoDetectionEnabledSetting;
64     private final @UserIdInt int mUserId;
65     private final boolean mUserConfigAllowed;
66     private final boolean mLocationEnabledSetting;
67     private final boolean mGeoDetectionEnabledSetting;
68     private final boolean mNotificationsSupported;
69     private final boolean mNotificationsEnabledSetting;
70     private final boolean mNotificationTrackingSupported;
71     private final boolean mManualChangeTrackingSupported;
72 
ConfigurationInternal(Builder builder)73     private ConfigurationInternal(Builder builder) {
74         mTelephonyDetectionSupported = builder.mTelephonyDetectionSupported;
75         mGeoDetectionSupported = builder.mGeoDetectionSupported;
76         mTelephonyFallbackSupported = builder.mTelephonyFallbackSupported;
77         mGeoDetectionRunInBackgroundEnabled = builder.mGeoDetectionRunInBackgroundEnabled;
78         mEnhancedMetricsCollectionEnabled = builder.mEnhancedMetricsCollectionEnabled;
79         mAutoDetectionEnabledSetting = builder.mAutoDetectionEnabledSetting;
80 
81         mUserId = Objects.requireNonNull(builder.mUserId, "userId must be set");
82         mUserConfigAllowed = builder.mUserConfigAllowed;
83         mLocationEnabledSetting = builder.mLocationEnabledSetting;
84         mGeoDetectionEnabledSetting = builder.mGeoDetectionEnabledSetting;
85         mNotificationsSupported = builder.mNotificationsSupported;
86         mNotificationsEnabledSetting = builder.mNotificationsEnabledSetting;
87         mNotificationTrackingSupported = builder.mNotificationsTrackingSupported;
88         mManualChangeTrackingSupported = builder.mManualChangeTrackingSupported;
89     }
90 
91     /** Returns true if the device supports any form of auto time zone detection. */
isAutoDetectionSupported()92     public boolean isAutoDetectionSupported() {
93         return mTelephonyDetectionSupported || mGeoDetectionSupported;
94     }
95 
96     /** Returns true if the device supports telephony time zone detection. */
isTelephonyDetectionSupported()97     public boolean isTelephonyDetectionSupported() {
98         return mTelephonyDetectionSupported;
99     }
100 
101     /** Returns true if the device supports geolocation time zone detection. */
isGeoDetectionSupported()102     public boolean isGeoDetectionSupported() {
103         return mGeoDetectionSupported;
104     }
105 
106     /**
107      * Returns true if the device supports time zone detection falling back to telephony detection
108      * under certain circumstances.
109      */
isTelephonyFallbackSupported()110     public boolean isTelephonyFallbackSupported() {
111         return mTelephonyFallbackSupported;
112     }
113 
114     /**
115      * Returns true if the device supports time-related notifications.
116      */
areNotificationsSupported()117     public boolean areNotificationsSupported() {
118         return mNotificationsSupported;
119     }
120 
121     /**
122      * Returns true if the device supports tracking of time-related notifications.
123      */
isNotificationTrackingSupported()124     public boolean isNotificationTrackingSupported() {
125         return areNotificationsSupported() && mNotificationTrackingSupported;
126     }
127 
128     /**
129      * Returns true if the device supports tracking of time zone manual changes.
130      */
isManualChangeTrackingSupported()131     public boolean isManualChangeTrackingSupported() {
132         return mManualChangeTrackingSupported;
133     }
134 
135     /**
136      * Returns {@code true} if location time zone detection should run when auto time zone detection
137      * is enabled on supported devices, even when the user has not enabled the algorithm explicitly
138      * in settings. Enabled for internal testing only. See {@link #isGeoDetectionExecutionEnabled()}
139      * and {@link #getDetectionMode()} for details.
140      */
getGeoDetectionRunInBackgroundEnabledSetting()141     boolean getGeoDetectionRunInBackgroundEnabledSetting() {
142         return mGeoDetectionRunInBackgroundEnabled;
143     }
144 
145     /**
146      * Returns {@code true} if the device can collect / report extra metrics information for QA
147      * / testers. These metrics might involve logging more expensive or more revealing data that
148      * would not be collected from the set of public users.
149      */
isEnhancedMetricsCollectionEnabled()150     public boolean isEnhancedMetricsCollectionEnabled() {
151         return mEnhancedMetricsCollectionEnabled;
152     }
153 
154     /** Returns the value of the auto time zone detection enabled setting. */
getAutoDetectionEnabledSetting()155     public boolean getAutoDetectionEnabledSetting() {
156         return mAutoDetectionEnabledSetting;
157     }
158 
159     /**
160      * Returns true if auto time zone detection behavior is actually enabled, which can be distinct
161      * from the raw setting value.
162      */
getAutoDetectionEnabledBehavior()163     public boolean getAutoDetectionEnabledBehavior() {
164         return isAutoDetectionSupported() && getAutoDetectionEnabledSetting();
165     }
166 
167     /** Returns the ID of the user this configuration is associated with. */
getUserId()168     public @UserIdInt int getUserId() {
169         return mUserId;
170     }
171 
172     /** Returns the handle of the user this configuration is associated with. */
173     @NonNull
getUserHandle()174     public UserHandle getUserHandle() {
175         return UserHandle.of(mUserId);
176     }
177 
178     /**
179      * Returns true if the user is allowed to modify time zone configuration, e.g. can be false due
180      * to device policy (enterprise).
181      *
182      * <p>See also {@link #asCapabilities(boolean)} for situations where this value is ignored.
183      */
isUserConfigAllowed()184     public boolean isUserConfigAllowed() {
185         return mUserConfigAllowed;
186     }
187 
188     /** Returns true if user's location can be used generally. */
getLocationEnabledSetting()189     public boolean getLocationEnabledSetting() {
190         return mLocationEnabledSetting;
191     }
192 
193     /** Returns the value of the geolocation time zone detection enabled setting. */
getGeoDetectionEnabledSetting()194     public boolean getGeoDetectionEnabledSetting() {
195         return mGeoDetectionEnabledSetting;
196     }
197 
198     /**
199      * Returns the detection mode to use, i.e. which suggestions to use to determine the device's
200      * time zone.
201      */
getDetectionMode()202     public @DetectionMode int getDetectionMode() {
203         if (!isAutoDetectionSupported()) {
204             // Handle the easy case first: No auto detection algorithms supported must mean manual.
205             return DETECTION_MODE_MANUAL;
206         } else if (!getAutoDetectionEnabledSetting()) {
207             // Auto detection algorithms are supported, but disabled by the user.
208             return DETECTION_MODE_MANUAL;
209         } else if (getGeoDetectionEnabledBehavior()) {
210             return DETECTION_MODE_GEO;
211         } else if (isTelephonyDetectionSupported()) {
212             return DETECTION_MODE_TELEPHONY;
213         } else {
214             // On devices with telephony detection support, telephony is used instead of geo when
215             // geo cannot be used. This "unknown" case can occur on devices with only the location
216             // detection algorithm supported when the user's master location setting prevents its
217             // use.
218             return DETECTION_MODE_UNKNOWN;
219         }
220     }
221 
getGeoDetectionEnabledBehavior()222     private boolean getGeoDetectionEnabledBehavior() {
223         // isAutoDetectionSupported() should already have been checked before calling this method.
224         if (isGeoDetectionSupported() && getLocationEnabledSetting()) {
225             if (isTelephonyDetectionSupported()) {
226                 // This is the "normal" case for smartphones that have both telephony and geo
227                 // detection: the user chooses which type of detection to use.
228                 return getGeoDetectionEnabledSetting();
229             } else {
230                 // When only geo detection is supported then there is no choice for the user to
231                 // make between detection modes, so no user setting is consulted.
232                 return true;
233             }
234         }
235         return false;
236     }
237 
238     /**
239      * Returns true if geolocation time zone detection behavior can execute. Typically, this will
240      * agree with {@link #getDetectionMode()}, but under rare circumstances the geolocation detector
241      * may be run in the background if the user's settings allow.
242      */
isGeoDetectionExecutionEnabled()243     public boolean isGeoDetectionExecutionEnabled() {
244         return getDetectionMode() == DETECTION_MODE_GEO
245                 || getGeoDetectionRunInBackgroundEnabledBehavior();
246     }
247 
getGeoDetectionRunInBackgroundEnabledBehavior()248     private boolean getGeoDetectionRunInBackgroundEnabledBehavior() {
249         return isGeoDetectionSupported()
250                 && getLocationEnabledSetting()
251                 && getAutoDetectionEnabledSetting()
252                 && getGeoDetectionRunInBackgroundEnabledSetting();
253     }
254 
255     /** Returns true if time-related notifications can be shown on this device. */
getNotificationsEnabledBehavior()256     public boolean getNotificationsEnabledBehavior() {
257         return areNotificationsSupported() && getNotificationsEnabledSetting();
258     }
259 
getNotificationsEnabledSetting()260     private boolean getNotificationsEnabledSetting() {
261         return mNotificationsEnabledSetting;
262     }
263 
264     @NonNull
asCapabilities(boolean bypassUserPolicyChecks)265     public TimeZoneCapabilities asCapabilities(boolean bypassUserPolicyChecks) {
266         UserHandle userHandle = UserHandle.of(mUserId);
267         TimeZoneCapabilities.Builder builder = new TimeZoneCapabilities.Builder(userHandle);
268 
269         boolean allowConfigDateTime = isUserConfigAllowed() || bypassUserPolicyChecks;
270 
271         // Automatic time zone detection is only supported on devices if there is a telephony
272         // network available or geolocation time zone detection is possible.
273         boolean deviceHasAutoTimeZoneDetection = isAutoDetectionSupported();
274 
275         final @CapabilityState int configureAutoDetectionEnabledCapability;
276         if (!deviceHasAutoTimeZoneDetection) {
277             configureAutoDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
278         } else if (!allowConfigDateTime) {
279             configureAutoDetectionEnabledCapability = CAPABILITY_NOT_ALLOWED;
280         } else {
281             configureAutoDetectionEnabledCapability = CAPABILITY_POSSESSED;
282         }
283         builder.setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability);
284 
285         builder.setUseLocationEnabled(mLocationEnabledSetting);
286 
287         boolean deviceHasLocationTimeZoneDetection = isGeoDetectionSupported();
288         boolean deviceHasTelephonyDetection = isTelephonyDetectionSupported();
289 
290         // Note: allowConfigDateTime does not restrict the ability to change location time zone
291         // detection enabled. This is intentional as it has user privacy implications and so it
292         // makes sense to leave this under a user's control. The only time this is not true is
293         // on devices that only support location-based detection and the main auto detection setting
294         // is used to influence whether location can be used.
295         final @CapabilityState int configureGeolocationDetectionEnabledCapability;
296         if (!deviceHasLocationTimeZoneDetection || !deviceHasTelephonyDetection) {
297             // If the device doesn't have geolocation detection support OR it ONLY has geolocation
298             // detection support (no telephony) then the user doesn't need the ability to toggle the
299             // location-based detection on and off (the auto detection toggle is considered
300             // sufficient).
301             configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
302         } else if (!mAutoDetectionEnabledSetting || !getLocationEnabledSetting()) {
303             configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_APPLICABLE;
304         } else {
305             configureGeolocationDetectionEnabledCapability = CAPABILITY_POSSESSED;
306         }
307         builder.setConfigureGeoDetectionEnabledCapability(
308                 configureGeolocationDetectionEnabledCapability);
309 
310         // The ability to make manual time zone suggestions can also be restricted by policy. With
311         // the current logic above, this could lead to a situation where a device hardware does not
312         // support auto detection, the device has been forced into "auto" mode by an admin and the
313         // user is unable to disable auto detection.
314         final @CapabilityState int suggestManualTimeZoneCapability;
315         if (!allowConfigDateTime) {
316             suggestManualTimeZoneCapability = CAPABILITY_NOT_ALLOWED;
317         } else if (getAutoDetectionEnabledBehavior()) {
318             suggestManualTimeZoneCapability = CAPABILITY_NOT_APPLICABLE;
319         } else {
320             suggestManualTimeZoneCapability = CAPABILITY_POSSESSED;
321         }
322         builder.setSetManualTimeZoneCapability(suggestManualTimeZoneCapability);
323 
324         final @CapabilityState int configureNotificationsEnabledCapability;
325         if (areNotificationsSupported()) {
326             configureNotificationsEnabledCapability = CAPABILITY_POSSESSED;
327         } else {
328             configureNotificationsEnabledCapability = CAPABILITY_NOT_SUPPORTED;
329         }
330         builder.setConfigureNotificationsEnabledCapability(configureNotificationsEnabledCapability);
331 
332         return builder.build();
333     }
334 
335     /** Returns a {@link TimeZoneConfiguration} from the configuration values. */
asConfiguration()336     public TimeZoneConfiguration asConfiguration() {
337         return new TimeZoneConfiguration.Builder()
338                 .setAutoDetectionEnabled(getAutoDetectionEnabledSetting())
339                 .setGeoDetectionEnabled(getGeoDetectionEnabledSetting())
340                 .setNotificationsEnabled(getNotificationsEnabledSetting())
341                 .build();
342     }
343 
344     /**
345      * Merges the configuration values from this with any properties set in {@code
346      * newConfiguration}. The new configuration has precedence. Used to apply user updates to
347      * internal configuration.
348      */
merge(TimeZoneConfiguration newConfiguration)349     public ConfigurationInternal merge(TimeZoneConfiguration newConfiguration) {
350         Builder builder = new Builder(this);
351         if (newConfiguration.hasIsAutoDetectionEnabled()) {
352             builder.setAutoDetectionEnabledSetting(newConfiguration.isAutoDetectionEnabled());
353         }
354         if (newConfiguration.hasIsGeoDetectionEnabled()) {
355             builder.setGeoDetectionEnabledSetting(newConfiguration.isGeoDetectionEnabled());
356         }
357         if (newConfiguration.hasIsNotificationsEnabled()) {
358             builder.setNotificationsEnabledSetting(newConfiguration.areNotificationsEnabled());
359         }
360         return builder.build();
361     }
362 
363     @Override
equals(Object o)364     public boolean equals(Object o) {
365         if (this == o) {
366             return true;
367         }
368         if (o == null || getClass() != o.getClass()) {
369             return false;
370         }
371         ConfigurationInternal that = (ConfigurationInternal) o;
372         return mUserId == that.mUserId
373                 && mUserConfigAllowed == that.mUserConfigAllowed
374                 && mTelephonyDetectionSupported == that.mTelephonyDetectionSupported
375                 && mGeoDetectionSupported == that.mGeoDetectionSupported
376                 && mTelephonyFallbackSupported == that.mTelephonyFallbackSupported
377                 && mGeoDetectionRunInBackgroundEnabled == that.mGeoDetectionRunInBackgroundEnabled
378                 && mEnhancedMetricsCollectionEnabled == that.mEnhancedMetricsCollectionEnabled
379                 && mAutoDetectionEnabledSetting == that.mAutoDetectionEnabledSetting
380                 && mLocationEnabledSetting == that.mLocationEnabledSetting
381                 && mGeoDetectionEnabledSetting == that.mGeoDetectionEnabledSetting
382                 && mNotificationsSupported == that.mNotificationsSupported
383                 && mNotificationsEnabledSetting == that.mNotificationsEnabledSetting
384                 && mNotificationTrackingSupported == that.mNotificationTrackingSupported
385                 && mManualChangeTrackingSupported == that.mManualChangeTrackingSupported;
386     }
387 
388     @Override
hashCode()389     public int hashCode() {
390         return Objects.hash(mUserId, mUserConfigAllowed, mTelephonyDetectionSupported,
391                 mGeoDetectionSupported, mTelephonyFallbackSupported,
392                 mGeoDetectionRunInBackgroundEnabled, mEnhancedMetricsCollectionEnabled,
393                 mAutoDetectionEnabledSetting, mLocationEnabledSetting, mGeoDetectionEnabledSetting,
394                 mNotificationsSupported, mNotificationsEnabledSetting,
395                 mNotificationTrackingSupported, mManualChangeTrackingSupported);
396     }
397 
398     @Override
toString()399     public String toString() {
400         return "ConfigurationInternal{"
401                 + "mUserId=" + mUserId
402                 + ", mUserConfigAllowed=" + mUserConfigAllowed
403                 + ", mTelephonyDetectionSupported=" + mTelephonyDetectionSupported
404                 + ", mGeoDetectionSupported=" + mGeoDetectionSupported
405                 + ", mTelephonyFallbackSupported=" + mTelephonyFallbackSupported
406                 + ", mGeoDetectionRunInBackgroundEnabled=" + mGeoDetectionRunInBackgroundEnabled
407                 + ", mEnhancedMetricsCollectionEnabled=" + mEnhancedMetricsCollectionEnabled
408                 + ", mAutoDetectionEnabledSetting=" + mAutoDetectionEnabledSetting
409                 + ", mLocationEnabledSetting=" + mLocationEnabledSetting
410                 + ", mGeoDetectionEnabledSetting=" + mGeoDetectionEnabledSetting
411                 + ", mNotificationsSupported=" + mNotificationsSupported
412                 + ", mNotificationsEnabledSetting=" + mNotificationsEnabledSetting
413                 + ", mNotificationTrackingSupported=" + mNotificationTrackingSupported
414                 + ", mManualChangeTrackingSupported=" + mManualChangeTrackingSupported
415                 + '}';
416     }
417 
418     /**
419      * A Builder for {@link ConfigurationInternal}.
420      */
421     public static class Builder {
422 
423         private @UserIdInt Integer mUserId;
424         private boolean mUserConfigAllowed;
425         private boolean mTelephonyDetectionSupported;
426         private boolean mGeoDetectionSupported;
427         private boolean mTelephonyFallbackSupported;
428         private boolean mGeoDetectionRunInBackgroundEnabled;
429         private boolean mEnhancedMetricsCollectionEnabled;
430         private boolean mAutoDetectionEnabledSetting;
431         private boolean mLocationEnabledSetting;
432         private boolean mGeoDetectionEnabledSetting;
433         private boolean mNotificationsSupported;
434         private boolean mNotificationsEnabledSetting;
435         private boolean mNotificationsTrackingSupported;
436         private boolean mManualChangeTrackingSupported;
437 
438         /**
439          * Creates a new Builder.
440          */
Builder()441         public Builder() {}
442 
443         /**
444          * Creates a new Builder by copying values from an existing instance.
445          */
Builder(ConfigurationInternal toCopy)446         public Builder(ConfigurationInternal toCopy) {
447             this.mUserId = toCopy.mUserId;
448             this.mUserConfigAllowed = toCopy.mUserConfigAllowed;
449             this.mTelephonyDetectionSupported = toCopy.mTelephonyDetectionSupported;
450             this.mTelephonyFallbackSupported = toCopy.mTelephonyFallbackSupported;
451             this.mGeoDetectionSupported = toCopy.mGeoDetectionSupported;
452             this.mGeoDetectionRunInBackgroundEnabled = toCopy.mGeoDetectionRunInBackgroundEnabled;
453             this.mEnhancedMetricsCollectionEnabled = toCopy.mEnhancedMetricsCollectionEnabled;
454             this.mAutoDetectionEnabledSetting = toCopy.mAutoDetectionEnabledSetting;
455             this.mLocationEnabledSetting = toCopy.mLocationEnabledSetting;
456             this.mGeoDetectionEnabledSetting = toCopy.mGeoDetectionEnabledSetting;
457             this.mNotificationsSupported = toCopy.mNotificationsSupported;
458             this.mNotificationsEnabledSetting = toCopy.mNotificationsEnabledSetting;
459             this.mNotificationsTrackingSupported = toCopy.mNotificationTrackingSupported;
460             this.mManualChangeTrackingSupported = toCopy.mManualChangeTrackingSupported;
461         }
462 
463         /**
464          * Sets the user ID the configuration is for.
465          */
setUserId(@serIdInt int userId)466         public Builder setUserId(@UserIdInt int userId) {
467             mUserId = userId;
468             return this;
469         }
470 
471         /**
472          * Sets whether the user is allowed to configure time zone settings on this device.
473          */
setUserConfigAllowed(boolean configAllowed)474         public Builder setUserConfigAllowed(boolean configAllowed) {
475             mUserConfigAllowed = configAllowed;
476             return this;
477         }
478 
479         /**
480          * Sets whether telephony time zone detection is supported on this device.
481          */
setTelephonyDetectionFeatureSupported(boolean supported)482         public Builder setTelephonyDetectionFeatureSupported(boolean supported) {
483             mTelephonyDetectionSupported = supported;
484             return this;
485         }
486 
487         /**
488          * Sets whether geolocation time zone detection is supported on this device.
489          */
setGeoDetectionFeatureSupported(boolean supported)490         public Builder setGeoDetectionFeatureSupported(boolean supported) {
491             mGeoDetectionSupported = supported;
492             return this;
493         }
494 
495         /**
496          * Sets whether time zone detection supports falling back to telephony detection under
497          * certain circumstances.
498          */
setTelephonyFallbackSupported(boolean supported)499         public Builder setTelephonyFallbackSupported(boolean supported) {
500             mTelephonyFallbackSupported = supported;
501             return this;
502         }
503 
504         /**
505          * Sets whether location time zone detection should run when auto time zone detection is
506          * enabled on supported devices, even when the user has not enabled the algorithm explicitly
507          * in settings. Enabled for internal testing only.
508          */
setGeoDetectionRunInBackgroundEnabled(boolean enabled)509         public Builder setGeoDetectionRunInBackgroundEnabled(boolean enabled) {
510             mGeoDetectionRunInBackgroundEnabled = enabled;
511             return this;
512         }
513 
514         /**
515          * Sets the value for enhanced metrics collection.
516          */
setEnhancedMetricsCollectionEnabled(boolean enabled)517         public Builder setEnhancedMetricsCollectionEnabled(boolean enabled) {
518             mEnhancedMetricsCollectionEnabled = enabled;
519             return this;
520         }
521 
522         /**
523          * Sets the value of the automatic time zone detection enabled setting for this device.
524          */
setAutoDetectionEnabledSetting(boolean enabled)525         public Builder setAutoDetectionEnabledSetting(boolean enabled) {
526             mAutoDetectionEnabledSetting = enabled;
527             return this;
528         }
529 
530         /**
531          * Sets the value of the location mode setting for this user.
532          */
setLocationEnabledSetting(boolean enabled)533         public Builder setLocationEnabledSetting(boolean enabled) {
534             mLocationEnabledSetting = enabled;
535             return this;
536         }
537 
538         /**
539          * Sets the value of the geolocation time zone detection setting for this user.
540          */
setGeoDetectionEnabledSetting(boolean enabled)541         public Builder setGeoDetectionEnabledSetting(boolean enabled) {
542             mGeoDetectionEnabledSetting = enabled;
543             return this;
544         }
545 
546         /**
547          * Sets the value of the time notification setting for this user.
548          */
setNotificationsEnabledSetting(boolean enabled)549         public Builder setNotificationsEnabledSetting(boolean enabled) {
550             mNotificationsEnabledSetting = enabled;
551             return this;
552         }
553 
554         /**
555          * Sets whether time zone notifications are supported on this device.
556          */
setNotificationsSupported(boolean enabled)557         public Builder setNotificationsSupported(boolean enabled) {
558             mNotificationsSupported = enabled;
559             return this;
560         }
561 
562         /**
563          * Sets whether time zone notification tracking is supported on this device.
564          */
setNotificationsTrackingSupported(boolean supported)565         public Builder setNotificationsTrackingSupported(boolean supported) {
566             mNotificationsTrackingSupported = supported;
567             return this;
568         }
569 
570         /**
571          * Sets whether time zone manual change tracking are supported on this device.
572          */
setManualChangeTrackingSupported(boolean supported)573         public Builder setManualChangeTrackingSupported(boolean supported) {
574             mManualChangeTrackingSupported = supported;
575             return this;
576         }
577 
578         /** Returns a new {@link ConfigurationInternal}. */
579         @NonNull
build()580         public ConfigurationInternal build() {
581             return new ConfigurationInternal(this);
582         }
583     }
584 }
585