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.app.timezonedetector.ManualTimeZoneSuggestion; 26 import android.app.timezonedetector.TimeZoneDetector; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.os.UserHandle; 30 31 import java.util.Objects; 32 33 /** 34 * Time zone-related capabilities for a user. 35 * 36 * <p>For configuration settings capabilities, the associated settings value can be found via 37 * {@link TimeManager#getTimeZoneCapabilitiesAndConfig()} and may be changed using {@link 38 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)} (if the user's capabilities 39 * allow). 40 * 41 * @hide 42 */ 43 @SystemApi 44 public final class TimeZoneCapabilities implements Parcelable { 45 46 public static final @NonNull Creator<TimeZoneCapabilities> CREATOR = 47 new Creator<TimeZoneCapabilities>() { 48 public TimeZoneCapabilities createFromParcel(Parcel in) { 49 return TimeZoneCapabilities.createFromParcel(in); 50 } 51 52 public TimeZoneCapabilities[] newArray(int size) { 53 return new TimeZoneCapabilities[size]; 54 } 55 }; 56 57 /** 58 * The user the capabilities are for. This is used for object equality and debugging but there 59 * is no accessor. 60 */ 61 @NonNull private final UserHandle mUserHandle; 62 private final @CapabilityState int mConfigureAutoDetectionEnabledCapability; 63 private final @CapabilityState int mConfigureGeoDetectionEnabledCapability; 64 private final @CapabilityState int mSuggestManualTimeZoneCapability; 65 TimeZoneCapabilities(@onNull Builder builder)66 private TimeZoneCapabilities(@NonNull Builder builder) { 67 this.mUserHandle = Objects.requireNonNull(builder.mUserHandle); 68 this.mConfigureAutoDetectionEnabledCapability = 69 builder.mConfigureAutoDetectionEnabledCapability; 70 this.mConfigureGeoDetectionEnabledCapability = 71 builder.mConfigureGeoDetectionEnabledCapability; 72 this.mSuggestManualTimeZoneCapability = builder.mSuggestManualTimeZoneCapability; 73 } 74 75 @NonNull createFromParcel(Parcel in)76 private static TimeZoneCapabilities createFromParcel(Parcel in) { 77 UserHandle userHandle = UserHandle.readFromParcel(in); 78 return new TimeZoneCapabilities.Builder(userHandle) 79 .setConfigureAutoDetectionEnabledCapability(in.readInt()) 80 .setConfigureGeoDetectionEnabledCapability(in.readInt()) 81 .setSuggestManualTimeZoneCapability(in.readInt()) 82 .build(); 83 } 84 85 @Override writeToParcel(@onNull Parcel dest, int flags)86 public void writeToParcel(@NonNull Parcel dest, int flags) { 87 UserHandle.writeToParcel(mUserHandle, dest); 88 dest.writeInt(mConfigureAutoDetectionEnabledCapability); 89 dest.writeInt(mConfigureGeoDetectionEnabledCapability); 90 dest.writeInt(mSuggestManualTimeZoneCapability); 91 } 92 93 /** 94 * Returns the capability state associated with the user's ability to modify the automatic time 95 * zone detection setting. The setting can be updated via {@link 96 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}. 97 */ 98 @CapabilityState getConfigureAutoDetectionEnabledCapability()99 public int getConfigureAutoDetectionEnabledCapability() { 100 return mConfigureAutoDetectionEnabledCapability; 101 } 102 103 /** 104 * Returns the capability state associated with the user's ability to modify the geolocation 105 * detection setting. The setting can be updated via {@link 106 * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}. 107 */ 108 @CapabilityState getConfigureGeoDetectionEnabledCapability()109 public int getConfigureGeoDetectionEnabledCapability() { 110 return mConfigureGeoDetectionEnabledCapability; 111 } 112 113 /** 114 * Returns the capability state associated with the user's ability to manually set the time zone 115 * on a device via {@link TimeZoneDetector#suggestManualTimeZone(ManualTimeZoneSuggestion)}. 116 * 117 * <p>The suggestion will be ignored in all cases unless the value is {@link 118 * Capabilities#CAPABILITY_POSSESSED}. See also 119 * {@link TimeZoneConfiguration#isAutoDetectionEnabled()}. 120 * 121 * @hide 122 */ 123 @CapabilityState getSuggestManualTimeZoneCapability()124 public int getSuggestManualTimeZoneCapability() { 125 return mSuggestManualTimeZoneCapability; 126 } 127 128 /** 129 * Tries to create a new {@link TimeZoneConfiguration} from the {@code config} and the set of 130 * {@code requestedChanges}, if {@code this} capabilities allow. The new configuration is 131 * returned. If the capabilities do not permit one or more of the requested changes then {@code 132 * null} is returned. 133 * 134 * @hide 135 */ 136 @Nullable tryApplyConfigChanges( @onNull TimeZoneConfiguration config, @NonNull TimeZoneConfiguration requestedChanges)137 public TimeZoneConfiguration tryApplyConfigChanges( 138 @NonNull TimeZoneConfiguration config, 139 @NonNull TimeZoneConfiguration requestedChanges) { 140 TimeZoneConfiguration.Builder newConfigBuilder = new TimeZoneConfiguration.Builder(config); 141 if (requestedChanges.hasIsAutoDetectionEnabled()) { 142 if (this.getConfigureAutoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) { 143 return null; 144 } 145 newConfigBuilder.setAutoDetectionEnabled(requestedChanges.isAutoDetectionEnabled()); 146 } 147 148 if (requestedChanges.hasIsGeoDetectionEnabled()) { 149 if (this.getConfigureGeoDetectionEnabledCapability() < CAPABILITY_NOT_APPLICABLE) { 150 return null; 151 } 152 newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled()); 153 } 154 155 return newConfigBuilder.build(); 156 } 157 158 @Override describeContents()159 public int describeContents() { 160 return 0; 161 } 162 163 @Override equals(@ullable Object o)164 public boolean equals(@Nullable Object o) { 165 if (this == o) { 166 return true; 167 } 168 if (o == null || getClass() != o.getClass()) { 169 return false; 170 } 171 TimeZoneCapabilities that = (TimeZoneCapabilities) o; 172 return mUserHandle.equals(that.mUserHandle) 173 && mConfigureAutoDetectionEnabledCapability 174 == that.mConfigureAutoDetectionEnabledCapability 175 && mConfigureGeoDetectionEnabledCapability 176 == that.mConfigureGeoDetectionEnabledCapability 177 && mSuggestManualTimeZoneCapability == that.mSuggestManualTimeZoneCapability; 178 } 179 180 @Override hashCode()181 public int hashCode() { 182 return Objects.hash(mUserHandle, mConfigureAutoDetectionEnabledCapability, 183 mConfigureGeoDetectionEnabledCapability, mSuggestManualTimeZoneCapability); 184 } 185 186 @Override toString()187 public String toString() { 188 return "TimeZoneDetectorCapabilities{" 189 + "mUserHandle=" + mUserHandle 190 + ", mConfigureAutoDetectionEnabledCapability=" 191 + mConfigureAutoDetectionEnabledCapability 192 + ", mConfigureGeoDetectionEnabledCapability=" 193 + mConfigureGeoDetectionEnabledCapability 194 + ", mSuggestManualTimeZoneCapability=" + mSuggestManualTimeZoneCapability 195 + '}'; 196 } 197 198 /** @hide */ 199 public static class Builder { 200 201 @NonNull private UserHandle mUserHandle; 202 private @CapabilityState int mConfigureAutoDetectionEnabledCapability; 203 private @CapabilityState int mConfigureGeoDetectionEnabledCapability; 204 private @CapabilityState int mSuggestManualTimeZoneCapability; 205 Builder(@onNull UserHandle userHandle)206 public Builder(@NonNull UserHandle userHandle) { 207 mUserHandle = Objects.requireNonNull(userHandle); 208 } 209 Builder(@onNull TimeZoneCapabilities capabilitiesToCopy)210 public Builder(@NonNull TimeZoneCapabilities capabilitiesToCopy) { 211 Objects.requireNonNull(capabilitiesToCopy); 212 mUserHandle = capabilitiesToCopy.mUserHandle; 213 mConfigureAutoDetectionEnabledCapability = 214 capabilitiesToCopy.mConfigureAutoDetectionEnabledCapability; 215 mConfigureGeoDetectionEnabledCapability = 216 capabilitiesToCopy.mConfigureGeoDetectionEnabledCapability; 217 mSuggestManualTimeZoneCapability = 218 capabilitiesToCopy.mSuggestManualTimeZoneCapability; 219 } 220 221 /** Sets the state for the automatic time zone detection enabled config. */ setConfigureAutoDetectionEnabledCapability(@apabilityState int value)222 public Builder setConfigureAutoDetectionEnabledCapability(@CapabilityState int value) { 223 this.mConfigureAutoDetectionEnabledCapability = value; 224 return this; 225 } 226 227 /** Sets the state for the geolocation time zone detection enabled config. */ setConfigureGeoDetectionEnabledCapability(@apabilityState int value)228 public Builder setConfigureGeoDetectionEnabledCapability(@CapabilityState int value) { 229 this.mConfigureGeoDetectionEnabledCapability = value; 230 return this; 231 } 232 233 /** Sets the state for the suggestManualTimeZone action. */ setSuggestManualTimeZoneCapability(@apabilityState int value)234 public Builder setSuggestManualTimeZoneCapability(@CapabilityState int value) { 235 this.mSuggestManualTimeZoneCapability = value; 236 return this; 237 } 238 239 /** Returns the {@link TimeZoneCapabilities}. */ 240 @NonNull build()241 public TimeZoneCapabilities build() { 242 verifyCapabilitySet(mConfigureAutoDetectionEnabledCapability, 243 "configureAutoDetectionEnabledCapability"); 244 verifyCapabilitySet(mConfigureGeoDetectionEnabledCapability, 245 "configureGeoDetectionEnabledCapability"); 246 verifyCapabilitySet(mSuggestManualTimeZoneCapability, 247 "suggestManualTimeZoneCapability"); 248 return new TimeZoneCapabilities(this); 249 } 250 verifyCapabilitySet(int value, String name)251 private void verifyCapabilitySet(int value, String name) { 252 if (value == 0) { 253 throw new IllegalStateException(name + " not set"); 254 } 255 } 256 } 257 } 258