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