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 private final UserHandle mUserHandle; 59 private final @CapabilityState int mConfigureAutoDetectionEnabledCapability; 60 61 /** 62 * The values of the user's "Use location" value, AKA the Master Location Switch. 63 * 64 * <p>This is only exposed for SettingsUI and so is not part of the SDK API. 65 * 66 * <p>This is not treated as a CapabilityState as it's a boolean value that all user's have. 67 */ 68 private final boolean mUseLocationEnabled; 69 70 private final @CapabilityState int mConfigureGeoDetectionEnabledCapability; 71 private final @CapabilityState int mSetManualTimeZoneCapability; 72 TimeZoneCapabilities(@onNull Builder builder)73 private TimeZoneCapabilities(@NonNull Builder builder) { 74 this.mUserHandle = Objects.requireNonNull(builder.mUserHandle); 75 this.mConfigureAutoDetectionEnabledCapability = 76 builder.mConfigureAutoDetectionEnabledCapability; 77 this.mUseLocationEnabled = builder.mUseLocationEnabled; 78 this.mConfigureGeoDetectionEnabledCapability = 79 builder.mConfigureGeoDetectionEnabledCapability; 80 this.mSetManualTimeZoneCapability = builder.mSetManualTimeZoneCapability; 81 } 82 83 @NonNull createFromParcel(@onNull Parcel in)84 private static TimeZoneCapabilities createFromParcel(@NonNull Parcel in) { 85 UserHandle userHandle = UserHandle.readFromParcel(in); 86 return new TimeZoneCapabilities.Builder(userHandle) 87 .setConfigureAutoDetectionEnabledCapability(in.readInt()) 88 .setUseLocationEnabled(in.readBoolean()) 89 .setConfigureGeoDetectionEnabledCapability(in.readInt()) 90 .setSetManualTimeZoneCapability(in.readInt()) 91 .build(); 92 } 93 94 @Override writeToParcel(@onNull Parcel dest, int flags)95 public void writeToParcel(@NonNull Parcel dest, int flags) { 96 UserHandle.writeToParcel(mUserHandle, dest); 97 dest.writeInt(mConfigureAutoDetectionEnabledCapability); 98 dest.writeBoolean(mUseLocationEnabled); 99 dest.writeInt(mConfigureGeoDetectionEnabledCapability); 100 dest.writeInt(mSetManualTimeZoneCapability); 101 } 102 103 /** 104 * Returns the capability state associated with the user's ability to modify the automatic time 105 * zone detection setting. The setting can be updated via {@link 106 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}. 107 */ 108 @CapabilityState getConfigureAutoDetectionEnabledCapability()109 public int getConfigureAutoDetectionEnabledCapability() { 110 return mConfigureAutoDetectionEnabledCapability; 111 } 112 113 /** 114 * Returns {@code true} if the device's location can be used by the Android system, and 115 * therefore the platform components running on behalf of the user. At the time of writing, the 116 * user can change this via the "Use location" setting on the Location settings screen. 117 * 118 * Not part of the SDK API because it is intended for use by SettingsUI, which can display 119 * text about needing it to be on for location-based time zone detection. 120 * @hide 121 * 122 */ isUseLocationEnabled()123 public boolean isUseLocationEnabled() { 124 return mUseLocationEnabled; 125 } 126 127 /** 128 * Returns the capability state associated with the user's ability to modify the geolocation 129 * detection setting. The setting can be updated via {@link 130 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}. 131 */ 132 @CapabilityState getConfigureGeoDetectionEnabledCapability()133 public int getConfigureGeoDetectionEnabledCapability() { 134 return mConfigureGeoDetectionEnabledCapability; 135 } 136 137 /** 138 * Returns the capability state associated with the user's ability to manually set the time zone 139 * on a device. 140 * 141 * <p>The time zone will be ignored in all cases unless the value is {@link 142 * Capabilities#CAPABILITY_POSSESSED}. See also 143 * {@link TimeZoneConfiguration#isAutoDetectionEnabled()}. 144 */ 145 @CapabilityState getSetManualTimeZoneCapability()146 public int getSetManualTimeZoneCapability() { 147 return mSetManualTimeZoneCapability; 148 } 149 150 /** 151 * Tries to create a new {@link TimeZoneConfiguration} from the {@code config} and the set of 152 * {@code requestedChanges}, if {@code this} capabilities allow. The new configuration is 153 * returned. If the capabilities do not permit one or more of the requested changes then {@code 154 * null} is returned. 155 * 156 * @hide 157 */ 158 @Nullable tryApplyConfigChanges( @onNull TimeZoneConfiguration config, @NonNull TimeZoneConfiguration requestedChanges)159 public TimeZoneConfiguration tryApplyConfigChanges( 160 @NonNull TimeZoneConfiguration config, 161 @NonNull TimeZoneConfiguration requestedChanges) { 162 TimeZoneConfiguration.Builder newConfigBuilder = new TimeZoneConfiguration.Builder(config); 163 if (requestedChanges.hasIsAutoDetectionEnabled()) { 164 if (this.getConfigureAutoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) { 165 return null; 166 } 167 newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled()); 168 } 169 170 if (requestedChanges.hasIsGeoDetectionEnabled()) { 171 if (this.getConfigureGeoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) { 172 return null; 173 } 174 newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled()); 175 } 176 177 return newConfigBuilder.build(); 178 } 179 180 @Override describeContents()181 public int describeContents() { 182 return 0; 183 } 184 185 @Override equals(@ullable Object o)186 public boolean equals(@Nullable Object o) { 187 if (this == o) { 188 return true; 189 } 190 if (o == null || getClass() != o.getClass()) { 191 return false; 192 } 193 TimeZoneCapabilities that = (TimeZoneCapabilities) o; 194 return mUserHandle.equals(that.mUserHandle) 195 && mConfigureAutoDetectionEnabledCapability 196 == that.mConfigureAutoDetectionEnabledCapability 197 && mUseLocationEnabled == that.mUseLocationEnabled 198 && mConfigureGeoDetectionEnabledCapability 199 == that.mConfigureGeoDetectionEnabledCapability 200 && mSetManualTimeZoneCapability == that.mSetManualTimeZoneCapability; 201 } 202 203 @Override hashCode()204 public int hashCode() { 205 return Objects.hash(mUserHandle, mConfigureAutoDetectionEnabledCapability, 206 mConfigureGeoDetectionEnabledCapability, mSetManualTimeZoneCapability); 207 } 208 209 @Override toString()210 public String toString() { 211 return "TimeZoneDetectorCapabilities{" 212 + "mUserHandle=" + mUserHandle 213 + ", mConfigureAutoDetectionEnabledCapability=" 214 + mConfigureAutoDetectionEnabledCapability 215 + ", mUseLocationEnabled=" + mUseLocationEnabled 216 + ", mConfigureGeoDetectionEnabledCapability=" 217 + mConfigureGeoDetectionEnabledCapability 218 + ", mSetManualTimeZoneCapability=" + mSetManualTimeZoneCapability 219 + '}'; 220 } 221 222 /** 223 * A builder of {@link TimeZoneCapabilities} objects. 224 * 225 * @hide 226 */ 227 public static class Builder { 228 229 @NonNull private UserHandle mUserHandle; 230 private @CapabilityState int mConfigureAutoDetectionEnabledCapability; 231 private Boolean mUseLocationEnabled; 232 private @CapabilityState int mConfigureGeoDetectionEnabledCapability; 233 private @CapabilityState int mSetManualTimeZoneCapability; 234 Builder(@onNull UserHandle userHandle)235 public Builder(@NonNull UserHandle userHandle) { 236 mUserHandle = Objects.requireNonNull(userHandle); 237 } 238 Builder(@onNull TimeZoneCapabilities capabilitiesToCopy)239 public Builder(@NonNull TimeZoneCapabilities capabilitiesToCopy) { 240 Objects.requireNonNull(capabilitiesToCopy); 241 mUserHandle = capabilitiesToCopy.mUserHandle; 242 mConfigureAutoDetectionEnabledCapability = 243 capabilitiesToCopy.mConfigureAutoDetectionEnabledCapability; 244 mUseLocationEnabled = capabilitiesToCopy.mUseLocationEnabled; 245 mConfigureGeoDetectionEnabledCapability = 246 capabilitiesToCopy.mConfigureGeoDetectionEnabledCapability; 247 mSetManualTimeZoneCapability = 248 capabilitiesToCopy.mSetManualTimeZoneCapability; 249 } 250 251 /** Sets the value for the "configure automatic time zone detection enabled" capability. */ setConfigureAutoDetectionEnabledCapability(@apabilityState int value)252 public Builder setConfigureAutoDetectionEnabledCapability(@CapabilityState int value) { 253 this.mConfigureAutoDetectionEnabledCapability = value; 254 return this; 255 } 256 257 /** Sets the values for "use location". See {@link #isUseLocationEnabled()}. */ setUseLocationEnabled(boolean useLocation)258 public Builder setUseLocationEnabled(boolean useLocation) { 259 mUseLocationEnabled = useLocation; 260 return this; 261 } 262 263 /** 264 * Sets the value for the "configure geolocation time zone detection enabled" capability. 265 */ setConfigureGeoDetectionEnabledCapability(@apabilityState int value)266 public Builder setConfigureGeoDetectionEnabledCapability(@CapabilityState int value) { 267 this.mConfigureGeoDetectionEnabledCapability = value; 268 return this; 269 } 270 271 /** Sets the value for the "set manual time zone" capability. */ setSetManualTimeZoneCapability(@apabilityState int value)272 public Builder setSetManualTimeZoneCapability(@CapabilityState int value) { 273 this.mSetManualTimeZoneCapability = value; 274 return this; 275 } 276 277 /** Returns the {@link TimeZoneCapabilities}. */ 278 @NonNull build()279 public TimeZoneCapabilities build() { 280 verifyCapabilitySet(mConfigureAutoDetectionEnabledCapability, 281 "configureAutoDetectionEnabledCapability"); 282 Objects.requireNonNull(mUseLocationEnabled, "useLocationEnabled"); 283 verifyCapabilitySet(mConfigureGeoDetectionEnabledCapability, 284 "configureGeoDetectionEnabledCapability"); 285 verifyCapabilitySet(mSetManualTimeZoneCapability, 286 "mSetManualTimeZoneCapability"); 287 return new TimeZoneCapabilities(this); 288 } 289 verifyCapabilitySet(int value, String name)290 private void verifyCapabilitySet(int value, String name) { 291 if (value == 0) { 292 throw new IllegalStateException(name + " not set"); 293 } 294 } 295 } 296 } 297