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 static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.app.time.Capabilities.CapabilityState; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.os.UserHandle; 28 29 import java.util.Objects; 30 31 /** 32 * Time zone-related capabilities for a user. 33 * 34 * <p>For configuration settings capabilities, the associated settings value can be found via 35 * {@link TimeManager#getTimeZoneCapabilitiesAndConfig()} and may be changed using {@link 36 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)} (if the user's capabilities 37 * allow). 38 * 39 * @hide 40 */ 41 @SystemApi 42 public final class TimeZoneCapabilities implements Parcelable { 43 44 public static final @NonNull Creator<TimeZoneCapabilities> CREATOR = new Creator<>() { 45 public TimeZoneCapabilities createFromParcel(Parcel in) { 46 return TimeZoneCapabilities.createFromParcel(in); 47 } 48 49 public TimeZoneCapabilities[] newArray(int size) { 50 return new TimeZoneCapabilities[size]; 51 } 52 }; 53 54 /** 55 * The user the capabilities are for. This is used for object equality and debugging but there 56 * is no accessor. 57 */ 58 @NonNull 59 private final UserHandle mUserHandle; 60 private final @CapabilityState int mConfigureAutoDetectionEnabledCapability; 61 62 /** 63 * The values of the user's "Use location" value, AKA the Master Location Switch. 64 * 65 * <p>This is only exposed for SettingsUI and so is not part of the SDK API. 66 * 67 * <p>This is not treated as a CapabilityState as it's a boolean value that all user's have. 68 */ 69 private final boolean mUseLocationEnabled; 70 71 private final @CapabilityState int mConfigureGeoDetectionEnabledCapability; 72 private final @CapabilityState int mSetManualTimeZoneCapability; 73 private final @CapabilityState int mConfigureNotificationsEnabledCapability; 74 TimeZoneCapabilities(@onNull Builder builder)75 private TimeZoneCapabilities(@NonNull Builder builder) { 76 this.mUserHandle = Objects.requireNonNull(builder.mUserHandle); 77 this.mConfigureAutoDetectionEnabledCapability = 78 builder.mConfigureAutoDetectionEnabledCapability; 79 this.mUseLocationEnabled = builder.mUseLocationEnabled; 80 this.mConfigureGeoDetectionEnabledCapability = 81 builder.mConfigureGeoDetectionEnabledCapability; 82 this.mSetManualTimeZoneCapability = builder.mSetManualTimeZoneCapability; 83 this.mConfigureNotificationsEnabledCapability = 84 builder.mConfigureNotificationsEnabledCapability; 85 } 86 87 @NonNull createFromParcel(@onNull Parcel in)88 private static TimeZoneCapabilities createFromParcel(@NonNull Parcel in) { 89 UserHandle userHandle = UserHandle.readFromParcel(in); 90 return new TimeZoneCapabilities.Builder(userHandle) 91 .setConfigureAutoDetectionEnabledCapability(in.readInt()) 92 .setUseLocationEnabled(in.readBoolean()) 93 .setConfigureGeoDetectionEnabledCapability(in.readInt()) 94 .setSetManualTimeZoneCapability(in.readInt()) 95 .setConfigureNotificationsEnabledCapability(in.readInt()) 96 .build(); 97 } 98 99 @Override writeToParcel(@onNull Parcel dest, int flags)100 public void writeToParcel(@NonNull Parcel dest, int flags) { 101 UserHandle.writeToParcel(mUserHandle, dest); 102 dest.writeInt(mConfigureAutoDetectionEnabledCapability); 103 dest.writeBoolean(mUseLocationEnabled); 104 dest.writeInt(mConfigureGeoDetectionEnabledCapability); 105 dest.writeInt(mSetManualTimeZoneCapability); 106 dest.writeInt(mConfigureNotificationsEnabledCapability); 107 } 108 109 /** 110 * Returns the capability state associated with the user's ability to modify the automatic time 111 * zone detection setting. The setting can be updated via {@link 112 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}. 113 */ 114 @CapabilityState getConfigureAutoDetectionEnabledCapability()115 public int getConfigureAutoDetectionEnabledCapability() { 116 return mConfigureAutoDetectionEnabledCapability; 117 } 118 119 /** 120 * Returns {@code true} if the device's location can be used by the Android system, and 121 * therefore the platform components running on behalf of the user. At the time of writing, the 122 * user can change this via the "Use location" setting on the Location settings screen. 123 * 124 * Not part of the SDK API because it is intended for use by SettingsUI, which can display 125 * text about needing it to be on for location-based time zone detection. 126 * 127 * @hide 128 */ isUseLocationEnabled()129 public boolean isUseLocationEnabled() { 130 return mUseLocationEnabled; 131 } 132 133 /** 134 * Returns the capability state associated with the user's ability to modify the geolocation 135 * detection setting. The setting can be updated via {@link 136 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}. 137 */ 138 @CapabilityState getConfigureGeoDetectionEnabledCapability()139 public int getConfigureGeoDetectionEnabledCapability() { 140 return mConfigureGeoDetectionEnabledCapability; 141 } 142 143 /** 144 * Returns the capability state associated with the user's ability to manually set the time zone 145 * on a device. 146 * 147 * <p>The time zone will be ignored in all cases unless the value is {@link 148 * Capabilities#CAPABILITY_POSSESSED}. See also 149 * {@link TimeZoneConfiguration#isAutoDetectionEnabled()}. 150 */ 151 @CapabilityState getSetManualTimeZoneCapability()152 public int getSetManualTimeZoneCapability() { 153 return mSetManualTimeZoneCapability; 154 } 155 156 /** 157 * Returns the capability state associated with the user's ability to modify the time zone 158 * notification setting. The setting can be updated via {@link 159 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}. 160 * 161 * @hide 162 */ 163 @CapabilityState getConfigureNotificationsEnabledCapability()164 public int getConfigureNotificationsEnabledCapability() { 165 return mConfigureNotificationsEnabledCapability; 166 } 167 168 /** 169 * Tries to create a new {@link TimeZoneConfiguration} from the {@code config} and the set of 170 * {@code requestedChanges}, if {@code this} capabilities allow. The new configuration is 171 * returned. If the capabilities do not permit one or more of the requested changes then {@code 172 * null} is returned. 173 * 174 * @hide 175 */ 176 @Nullable tryApplyConfigChanges( @onNull TimeZoneConfiguration config, @NonNull TimeZoneConfiguration requestedChanges)177 public TimeZoneConfiguration tryApplyConfigChanges( 178 @NonNull TimeZoneConfiguration config, 179 @NonNull TimeZoneConfiguration requestedChanges) { 180 TimeZoneConfiguration.Builder newConfigBuilder = new TimeZoneConfiguration.Builder(config); 181 if (requestedChanges.hasIsAutoDetectionEnabled()) { 182 if (this.getConfigureAutoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) { 183 return null; 184 } 185 newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled()); 186 } 187 188 if (requestedChanges.hasIsGeoDetectionEnabled()) { 189 if (this.getConfigureGeoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) { 190 return null; 191 } 192 newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled()); 193 } 194 195 if (requestedChanges.hasIsNotificationsEnabled()) { 196 if (this.getConfigureNotificationsEnabledCapability() < CAPABILITY_NOT_APPLICABLE) { 197 return null; 198 } 199 newConfigBuilder.setNotificationsEnabled(requestedChanges.areNotificationsEnabled()); 200 } 201 return newConfigBuilder.build(); 202 } 203 204 @Override describeContents()205 public int describeContents() { 206 return 0; 207 } 208 209 @Override equals(@ullable Object o)210 public boolean equals(@Nullable Object o) { 211 if (this == o) { 212 return true; 213 } 214 if (o == null || getClass() != o.getClass()) { 215 return false; 216 } 217 TimeZoneCapabilities that = (TimeZoneCapabilities) o; 218 return mUserHandle.equals(that.mUserHandle) 219 && mConfigureAutoDetectionEnabledCapability 220 == that.mConfigureAutoDetectionEnabledCapability 221 && mUseLocationEnabled == that.mUseLocationEnabled 222 && mConfigureGeoDetectionEnabledCapability 223 == that.mConfigureGeoDetectionEnabledCapability 224 && mSetManualTimeZoneCapability == that.mSetManualTimeZoneCapability 225 && mConfigureNotificationsEnabledCapability 226 == that.mConfigureNotificationsEnabledCapability; 227 } 228 229 @Override hashCode()230 public int hashCode() { 231 return Objects.hash(mUserHandle, mConfigureAutoDetectionEnabledCapability, 232 mConfigureGeoDetectionEnabledCapability, mSetManualTimeZoneCapability, 233 mConfigureNotificationsEnabledCapability); 234 } 235 236 @Override toString()237 public String toString() { 238 return "TimeZoneDetectorCapabilities{" 239 + "mUserHandle=" + mUserHandle 240 + ", mConfigureAutoDetectionEnabledCapability=" 241 + mConfigureAutoDetectionEnabledCapability 242 + ", mUseLocationEnabled=" + mUseLocationEnabled 243 + ", mConfigureGeoDetectionEnabledCapability=" 244 + mConfigureGeoDetectionEnabledCapability 245 + ", mSetManualTimeZoneCapability=" + mSetManualTimeZoneCapability 246 + ", mConfigureNotificationsEnabledCapability=" 247 + mConfigureNotificationsEnabledCapability 248 + '}'; 249 } 250 251 /** 252 * A builder of {@link TimeZoneCapabilities} objects. 253 * 254 * @hide 255 */ 256 public static class Builder { 257 258 @NonNull 259 private UserHandle mUserHandle; 260 private @CapabilityState int mConfigureAutoDetectionEnabledCapability; 261 private Boolean mUseLocationEnabled; 262 private @CapabilityState int mConfigureGeoDetectionEnabledCapability; 263 private @CapabilityState int mSetManualTimeZoneCapability; 264 private @CapabilityState int mConfigureNotificationsEnabledCapability; 265 Builder(@onNull UserHandle userHandle)266 public Builder(@NonNull UserHandle userHandle) { 267 mUserHandle = Objects.requireNonNull(userHandle); 268 } 269 Builder(@onNull TimeZoneCapabilities capabilitiesToCopy)270 public Builder(@NonNull TimeZoneCapabilities capabilitiesToCopy) { 271 Objects.requireNonNull(capabilitiesToCopy); 272 mUserHandle = capabilitiesToCopy.mUserHandle; 273 mConfigureAutoDetectionEnabledCapability = 274 capabilitiesToCopy.mConfigureAutoDetectionEnabledCapability; 275 mUseLocationEnabled = capabilitiesToCopy.mUseLocationEnabled; 276 mConfigureGeoDetectionEnabledCapability = 277 capabilitiesToCopy.mConfigureGeoDetectionEnabledCapability; 278 mSetManualTimeZoneCapability = 279 capabilitiesToCopy.mSetManualTimeZoneCapability; 280 mConfigureNotificationsEnabledCapability = 281 capabilitiesToCopy.mConfigureNotificationsEnabledCapability; 282 } 283 284 /** Sets the value for the "configure automatic time zone detection enabled" capability. */ setConfigureAutoDetectionEnabledCapability(@apabilityState int value)285 public Builder setConfigureAutoDetectionEnabledCapability(@CapabilityState int value) { 286 this.mConfigureAutoDetectionEnabledCapability = value; 287 return this; 288 } 289 290 /** Sets the values for "use location". See {@link #isUseLocationEnabled()}. */ setUseLocationEnabled(boolean useLocation)291 public Builder setUseLocationEnabled(boolean useLocation) { 292 mUseLocationEnabled = useLocation; 293 return this; 294 } 295 296 /** 297 * Sets the value for the "configure geolocation time zone detection enabled" capability. 298 */ setConfigureGeoDetectionEnabledCapability(@apabilityState int value)299 public Builder setConfigureGeoDetectionEnabledCapability(@CapabilityState int value) { 300 this.mConfigureGeoDetectionEnabledCapability = value; 301 return this; 302 } 303 304 /** Sets the value for the "set manual time zone" capability. */ setSetManualTimeZoneCapability(@apabilityState int value)305 public Builder setSetManualTimeZoneCapability(@CapabilityState int value) { 306 this.mSetManualTimeZoneCapability = value; 307 return this; 308 } 309 310 /** 311 * Sets the value for the "configure time notifications enabled" capability. 312 */ setConfigureNotificationsEnabledCapability(@apabilityState int value)313 public Builder setConfigureNotificationsEnabledCapability(@CapabilityState int value) { 314 this.mConfigureNotificationsEnabledCapability = value; 315 return this; 316 } 317 318 /** Returns the {@link TimeZoneCapabilities}. */ 319 @NonNull build()320 public TimeZoneCapabilities build() { 321 verifyCapabilitySet(mConfigureAutoDetectionEnabledCapability, 322 "configureAutoDetectionEnabledCapability"); 323 Objects.requireNonNull(mUseLocationEnabled, "useLocationEnabled"); 324 verifyCapabilitySet(mConfigureGeoDetectionEnabledCapability, 325 "configureGeoDetectionEnabledCapability"); 326 verifyCapabilitySet(mSetManualTimeZoneCapability, 327 "setManualTimeZoneCapability"); 328 verifyCapabilitySet(mConfigureNotificationsEnabledCapability, 329 "configureNotificationsEnabledCapability"); 330 return new TimeZoneCapabilities(this); 331 } 332 verifyCapabilitySet(int value, String name)333 private void verifyCapabilitySet(int value, String name) { 334 if (value == 0) { 335 throw new IllegalStateException(name + " not set"); 336 } 337 } 338 } 339 } 340