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 android.app.time; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.StringDef; 22 import android.annotation.SystemApi; 23 import android.os.Bundle; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.util.Objects; 30 31 /** 32 * User visible settings that control the behavior of the time zone detector / manual time zone 33 * entry. 34 * 35 * <p>When reading the configuration, values for all settings will be provided. In some cases, such 36 * as when the device behavior relies on optional hardware / OEM configuration, or the value of 37 * several settings, the device behavior may not be directly affected by the setting value. 38 * 39 * <p>Settings can be left absent when updating configuration via {@link 40 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)} and those settings will not be 41 * changed. Not all configuration settings can be modified by all users: see {@link 42 * TimeManager#getTimeZoneCapabilitiesAndConfig()} and {@link TimeZoneCapabilities} for details. 43 * 44 * @hide 45 */ 46 @SystemApi 47 public final class TimeZoneConfiguration implements Parcelable { 48 49 public static final @NonNull Creator<TimeZoneConfiguration> CREATOR = 50 new Creator<TimeZoneConfiguration>() { 51 public TimeZoneConfiguration createFromParcel(Parcel in) { 52 return TimeZoneConfiguration.createFromParcel(in); 53 } 54 55 public TimeZoneConfiguration[] newArray(int size) { 56 return new TimeZoneConfiguration[size]; 57 } 58 }; 59 60 /** 61 * All configuration properties 62 * 63 * @hide 64 */ 65 @StringDef({SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED, 66 SETTING_NOTIFICATIONS_ENABLED}) 67 @Retention(RetentionPolicy.SOURCE) 68 @interface Setting {} 69 70 /** See {@link TimeZoneConfiguration#isAutoDetectionEnabled()} for details. */ 71 @Setting 72 private static final String SETTING_AUTO_DETECTION_ENABLED = "autoDetectionEnabled"; 73 74 /** See {@link TimeZoneConfiguration#isGeoDetectionEnabled()} for details. */ 75 @Setting 76 private static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled"; 77 78 /** See {@link TimeZoneConfiguration#areNotificationsEnabled()} for details. */ 79 @Setting 80 private static final String SETTING_NOTIFICATIONS_ENABLED = "notificationsEnabled"; 81 82 @NonNull private final Bundle mBundle; 83 TimeZoneConfiguration(Builder builder)84 private TimeZoneConfiguration(Builder builder) { 85 this.mBundle = Objects.requireNonNull(builder.mBundle); 86 } 87 createFromParcel(Parcel in)88 private static TimeZoneConfiguration createFromParcel(Parcel in) { 89 return new TimeZoneConfiguration.Builder() 90 .setPropertyBundleInternal(in.readBundle()) 91 .build(); 92 } 93 94 @Override writeToParcel(@onNull Parcel dest, int flags)95 public void writeToParcel(@NonNull Parcel dest, int flags) { 96 dest.writeBundle(mBundle); 97 } 98 99 /** 100 * Returns {@code true} if all known settings are present. 101 * 102 * @hide 103 */ isComplete()104 public boolean isComplete() { 105 return hasIsAutoDetectionEnabled() 106 && hasIsGeoDetectionEnabled() 107 && hasIsNotificationsEnabled(); 108 } 109 110 /** 111 * Returns the value of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. This 112 * controls whether a device will attempt to determine the time zone automatically using 113 * contextual information if the device supports auto detection. 114 * 115 * <p>See {@link TimeZoneCapabilities#getConfigureAutoDetectionEnabledCapability()} for how to 116 * tell if the setting is meaningful for the current user at this time. 117 * 118 * @throws IllegalStateException if the setting is not present 119 */ isAutoDetectionEnabled()120 public boolean isAutoDetectionEnabled() { 121 enforceSettingPresent(SETTING_AUTO_DETECTION_ENABLED); 122 return mBundle.getBoolean(SETTING_AUTO_DETECTION_ENABLED); 123 } 124 125 /** 126 * Returns {@code true} if the {@link #isAutoDetectionEnabled()} setting is present. 127 * 128 * @hide 129 */ hasIsAutoDetectionEnabled()130 public boolean hasIsAutoDetectionEnabled() { 131 return mBundle.containsKey(SETTING_AUTO_DETECTION_ENABLED); 132 } 133 134 /** 135 * Returns the value of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. This 136 * controls whether the device can use geolocation to determine time zone. This value may only 137 * be used by Android under some circumstances. 138 * 139 * <p>See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabledCapability()} for how to 140 * tell if the setting is meaningful for the current user at this time. 141 * 142 * @throws IllegalStateException if the setting is not present 143 */ isGeoDetectionEnabled()144 public boolean isGeoDetectionEnabled() { 145 enforceSettingPresent(SETTING_GEO_DETECTION_ENABLED); 146 return mBundle.getBoolean(SETTING_GEO_DETECTION_ENABLED); 147 } 148 149 /** 150 * Returns {@code true} if the {@link #isGeoDetectionEnabled()} setting is present. 151 * 152 * @hide 153 */ hasIsGeoDetectionEnabled()154 public boolean hasIsGeoDetectionEnabled() { 155 return mBundle.containsKey(SETTING_GEO_DETECTION_ENABLED); 156 } 157 158 /** 159 * Returns the value of the {@link #SETTING_NOTIFICATIONS_ENABLED} setting. This controls 160 * whether the device can send time and time zone related notifications. This value may only 161 * be used by Android under some circumstances. 162 * 163 * <p>See {@link TimeZoneCapabilities#getConfigureNotificationsEnabledCapability()} ()} for how 164 * to tell if the setting is meaningful for the current user at this time. 165 * 166 * @throws IllegalStateException if the setting is not present 167 * 168 * @hide 169 */ areNotificationsEnabled()170 public boolean areNotificationsEnabled() { 171 enforceSettingPresent(SETTING_NOTIFICATIONS_ENABLED); 172 return mBundle.getBoolean(SETTING_NOTIFICATIONS_ENABLED); 173 } 174 175 /** 176 * Returns {@code true} if the {@link #areNotificationsEnabled()} setting is present. 177 * 178 * @hide 179 */ hasIsNotificationsEnabled()180 public boolean hasIsNotificationsEnabled() { 181 return mBundle.containsKey(SETTING_NOTIFICATIONS_ENABLED); 182 } 183 184 @Override describeContents()185 public int describeContents() { 186 return 0; 187 } 188 189 @Override equals(@ullable Object o)190 public boolean equals(@Nullable Object o) { 191 if (this == o) { 192 return true; 193 } 194 if (o == null || getClass() != o.getClass()) { 195 return false; 196 } 197 TimeZoneConfiguration that = (TimeZoneConfiguration) o; 198 return mBundle.kindofEquals(that.mBundle); 199 } 200 201 @Override hashCode()202 public int hashCode() { 203 return Objects.hash(mBundle); 204 } 205 206 @Override toString()207 public String toString() { 208 return "TimeZoneConfiguration{" 209 + "mBundle=" + mBundle 210 + '}'; 211 } 212 enforceSettingPresent(@etting String setting)213 private void enforceSettingPresent(@Setting String setting) { 214 if (!mBundle.containsKey(setting)) { 215 throw new IllegalStateException(setting + " is not set"); 216 } 217 } 218 219 /** 220 * A builder for {@link TimeZoneConfiguration} objects. 221 * 222 * @hide 223 */ 224 @SystemApi 225 public static final class Builder { 226 227 private final Bundle mBundle = new Bundle(); 228 229 /** 230 * Creates a new Builder with no settings held. 231 */ Builder()232 public Builder() { 233 } 234 235 /** 236 * Creates a new Builder by copying the settings from an existing instance. 237 */ Builder(@onNull TimeZoneConfiguration toCopy)238 public Builder(@NonNull TimeZoneConfiguration toCopy) { 239 mergeProperties(toCopy); 240 } 241 242 /** 243 * Merges {@code other} settings into this instances, replacing existing values in this 244 * where the settings appear in both. 245 * 246 * @hide 247 */ 248 @NonNull mergeProperties(@onNull TimeZoneConfiguration other)249 public Builder mergeProperties(@NonNull TimeZoneConfiguration other) { 250 this.mBundle.putAll(other.mBundle); 251 return this; 252 } 253 254 @NonNull setPropertyBundleInternal(@onNull Bundle bundle)255 Builder setPropertyBundleInternal(@NonNull Bundle bundle) { 256 this.mBundle.putAll(bundle); 257 return this; 258 } 259 260 /** 261 * Sets the state of the {@link #SETTING_AUTO_DETECTION_ENABLED} setting. 262 */ 263 @NonNull setAutoDetectionEnabled(boolean enabled)264 public Builder setAutoDetectionEnabled(boolean enabled) { 265 this.mBundle.putBoolean(SETTING_AUTO_DETECTION_ENABLED, enabled); 266 return this; 267 } 268 269 /** 270 * Sets the state of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. 271 */ 272 @NonNull setGeoDetectionEnabled(boolean enabled)273 public Builder setGeoDetectionEnabled(boolean enabled) { 274 this.mBundle.putBoolean(SETTING_GEO_DETECTION_ENABLED, enabled); 275 return this; 276 } 277 278 /** 279 * Sets the state of the {@link #SETTING_NOTIFICATIONS_ENABLED} setting. * 280 * 281 * @hide 282 */ 283 @NonNull setNotificationsEnabled(boolean enabled)284 public Builder setNotificationsEnabled(boolean enabled) { 285 this.mBundle.putBoolean(SETTING_NOTIFICATIONS_ENABLED, enabled); 286 return this; 287 } 288 289 /** Returns the {@link TimeZoneConfiguration}. */ 290 @NonNull build()291 public TimeZoneConfiguration build() { 292 return new TimeZoneConfiguration(this); 293 } 294 } 295 } 296 297