1 /* 2 * Copyright (C) 2017 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.timezone; 18 19 import static android.app.timezone.Utils.validateConditionalNull; 20 import static android.app.timezone.Utils.validateNotNull; 21 import static android.app.timezone.Utils.validateRulesVersion; 22 23 import android.annotation.IntDef; 24 import android.annotation.Nullable; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 31 /** 32 * Description of the state of time zone rules on a device. 33 * 34 * <p>The following properties are included: 35 * <dl> 36 * <dt>baseRulesVersion</dt> 37 * <dd>the IANA rules version that shipped with the OS. Always present. e.g. "2017a".</dd> 38 * <dt>distroFormatVersionSupported</dt> 39 * <dd>the distro format version supported by this device. Always present.</dd> 40 * <dt>operationInProgress</dt> 41 * <dd>{@code true} if there is an install / uninstall operation currently happening.</dd> 42 * <dt>stagedOperationType</dt> 43 * <dd>one of {@link #STAGED_OPERATION_UNKNOWN}, {@link #STAGED_OPERATION_NONE}, 44 * {@link #STAGED_OPERATION_UNINSTALL} and {@link #STAGED_OPERATION_INSTALL} indicating whether 45 * there is a currently staged time zone distro operation. {@link #STAGED_OPERATION_UNKNOWN} is 46 * used when {@link #isOperationInProgress()} is {@code true}. Staged operations currently 47 * require a reboot to become active.</dd> 48 * <dt>stagedDistroRulesVersion</dt> 49 * <dd>[present if distroStagedState == STAGED_STATE_INSTALL], the rules version of the distro 50 * currently staged for installation.</dd> 51 * <dt>distroStatus</dt> 52 * <dd>{@link #DISTRO_STATUS_INSTALLED} if there is a time zone distro installed and active, 53 * {@link #DISTRO_STATUS_NONE} if there is no active installed distro. 54 * {@link #DISTRO_STATUS_UNKNOWN} is used when {@link #isOperationInProgress()} is {@code true}. 55 * </dd> 56 * <dt>installedDistroRulesVersion</dt> 57 * <dd>[present if distroStatus == {@link #DISTRO_STATUS_INSTALLED}], the rules version of the 58 * installed and active distro.</dd> 59 * </dl> 60 * 61 * @hide 62 */ 63 public final class RulesState implements Parcelable { 64 65 @Retention(RetentionPolicy.SOURCE) 66 @IntDef(prefix = { "STAGED_OPERATION_" }, value = { 67 STAGED_OPERATION_UNKNOWN, 68 STAGED_OPERATION_NONE, 69 STAGED_OPERATION_UNINSTALL, 70 STAGED_OPERATION_INSTALL 71 }) 72 private @interface StagedOperationType {} 73 74 /** Staged state could not be determined. */ 75 public static final int STAGED_OPERATION_UNKNOWN = 0; 76 /** Nothing is staged. */ 77 public static final int STAGED_OPERATION_NONE = 1; 78 /** An uninstall is staged. */ 79 public static final int STAGED_OPERATION_UNINSTALL = 2; 80 /** An install is staged. */ 81 public static final int STAGED_OPERATION_INSTALL = 3; 82 83 @Retention(RetentionPolicy.SOURCE) 84 @IntDef(prefix = { "DISTRO_STATUS_" }, value = { 85 DISTRO_STATUS_UNKNOWN, 86 DISTRO_STATUS_NONE, 87 DISTRO_STATUS_INSTALLED 88 }) 89 private @interface DistroStatus {} 90 91 /** The current distro status could not be determined. */ 92 public static final int DISTRO_STATUS_UNKNOWN = 0; 93 /** There is no active installed time zone distro. */ 94 public static final int DISTRO_STATUS_NONE = 1; 95 /** The is an active, installed time zone distro. */ 96 public static final int DISTRO_STATUS_INSTALLED = 2; 97 98 private static final byte BYTE_FALSE = 0; 99 private static final byte BYTE_TRUE = 1; 100 101 private final String mBaseRulesVersion; 102 private final DistroFormatVersion mDistroFormatVersionSupported; 103 private final boolean mOperationInProgress; 104 @StagedOperationType private final int mStagedOperationType; 105 @Nullable private final DistroRulesVersion mStagedDistroRulesVersion; 106 @DistroStatus private final int mDistroStatus; 107 @Nullable private final DistroRulesVersion mInstalledDistroRulesVersion; 108 RulesState(String baseRulesVersion, DistroFormatVersion distroFormatVersionSupported, boolean operationInProgress, @StagedOperationType int stagedOperationType, @Nullable DistroRulesVersion stagedDistroRulesVersion, @DistroStatus int distroStatus, @Nullable DistroRulesVersion installedDistroRulesVersion)109 public RulesState(String baseRulesVersion, DistroFormatVersion distroFormatVersionSupported, 110 boolean operationInProgress, 111 @StagedOperationType int stagedOperationType, 112 @Nullable DistroRulesVersion stagedDistroRulesVersion, 113 @DistroStatus int distroStatus, 114 @Nullable DistroRulesVersion installedDistroRulesVersion) { 115 this.mBaseRulesVersion = validateRulesVersion("baseRulesVersion", baseRulesVersion); 116 this.mDistroFormatVersionSupported = 117 validateNotNull("distroFormatVersionSupported", distroFormatVersionSupported); 118 this.mOperationInProgress = operationInProgress; 119 120 if (operationInProgress && stagedOperationType != STAGED_OPERATION_UNKNOWN) { 121 throw new IllegalArgumentException( 122 "stagedOperationType != STAGED_OPERATION_UNKNOWN"); 123 } 124 this.mStagedOperationType = validateStagedOperation(stagedOperationType); 125 this.mStagedDistroRulesVersion = validateConditionalNull( 126 mStagedOperationType == STAGED_OPERATION_INSTALL /* requireNotNull */, 127 "stagedDistroRulesVersion", stagedDistroRulesVersion); 128 129 this.mDistroStatus = validateDistroStatus(distroStatus); 130 this.mInstalledDistroRulesVersion = validateConditionalNull( 131 mDistroStatus == DISTRO_STATUS_INSTALLED/* requireNotNull */, 132 "installedDistroRulesVersion", installedDistroRulesVersion); 133 } 134 getBaseRulesVersion()135 public String getBaseRulesVersion() { 136 return mBaseRulesVersion; 137 } 138 isOperationInProgress()139 public boolean isOperationInProgress() { 140 return mOperationInProgress; 141 } 142 getStagedOperationType()143 public @StagedOperationType int getStagedOperationType() { 144 return mStagedOperationType; 145 } 146 147 /** 148 * Returns the staged rules version when {@link #getStagedOperationType()} is 149 * {@link #STAGED_OPERATION_INSTALL}. 150 */ getStagedDistroRulesVersion()151 public @Nullable DistroRulesVersion getStagedDistroRulesVersion() { 152 return mStagedDistroRulesVersion; 153 } 154 getDistroStatus()155 public @DistroStatus int getDistroStatus() { 156 return mDistroStatus; 157 } 158 159 /** 160 * Returns the installed rules version when {@link #getDistroStatus()} is 161 * {@link #DISTRO_STATUS_INSTALLED}. 162 */ getInstalledDistroRulesVersion()163 public @Nullable DistroRulesVersion getInstalledDistroRulesVersion() { 164 return mInstalledDistroRulesVersion; 165 } 166 167 /** 168 * Returns true if a distro in the specified format is supported on this device. 169 */ isDistroFormatVersionSupported(DistroFormatVersion distroFormatVersion)170 public boolean isDistroFormatVersionSupported(DistroFormatVersion distroFormatVersion) { 171 return mDistroFormatVersionSupported.supports(distroFormatVersion); 172 } 173 174 /** 175 * Returns true if the base data files contain IANA rules data that are newer than the 176 * distro IANA rules version supplied, i.e. true when the version specified would be "worse" 177 * than the one that is in the base data. Returns false if the base version is the 178 * same or older, i.e. false when the version specified would be "better" than the one that is 179 * in the base set. 180 */ isBaseVersionNewerThan(DistroRulesVersion distroRulesVersion)181 public boolean isBaseVersionNewerThan(DistroRulesVersion distroRulesVersion) { 182 return mBaseRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) > 0; 183 } 184 185 public static final @android.annotation.NonNull Parcelable.Creator<RulesState> CREATOR = 186 new Parcelable.Creator<RulesState>() { 187 public RulesState createFromParcel(Parcel in) { 188 return RulesState.createFromParcel(in); 189 } 190 191 public RulesState[] newArray(int size) { 192 return new RulesState[size]; 193 } 194 }; 195 createFromParcel(Parcel in)196 private static RulesState createFromParcel(Parcel in) { 197 String baseRulesVersion = in.readString(); 198 DistroFormatVersion distroFormatVersionSupported = in.readParcelable(null); 199 boolean operationInProgress = in.readByte() == BYTE_TRUE; 200 int distroStagedState = in.readByte(); 201 DistroRulesVersion stagedDistroRulesVersion = in.readParcelable(null); 202 int installedDistroStatus = in.readByte(); 203 DistroRulesVersion installedDistroRulesVersion = in.readParcelable(null); 204 return new RulesState(baseRulesVersion, distroFormatVersionSupported, operationInProgress, 205 distroStagedState, stagedDistroRulesVersion, 206 installedDistroStatus, installedDistroRulesVersion); 207 } 208 209 @Override describeContents()210 public int describeContents() { 211 return 0; 212 } 213 214 @Override writeToParcel(Parcel out, int flags)215 public void writeToParcel(Parcel out, int flags) { 216 out.writeString(mBaseRulesVersion); 217 out.writeParcelable(mDistroFormatVersionSupported, 0); 218 out.writeByte(mOperationInProgress ? BYTE_TRUE : BYTE_FALSE); 219 out.writeByte((byte) mStagedOperationType); 220 out.writeParcelable(mStagedDistroRulesVersion, 0); 221 out.writeByte((byte) mDistroStatus); 222 out.writeParcelable(mInstalledDistroRulesVersion, 0); 223 } 224 225 @Override equals(Object o)226 public boolean equals(Object o) { 227 if (this == o) { 228 return true; 229 } 230 if (o == null || getClass() != o.getClass()) { 231 return false; 232 } 233 234 RulesState that = (RulesState) o; 235 236 if (mOperationInProgress != that.mOperationInProgress) { 237 return false; 238 } 239 if (mStagedOperationType != that.mStagedOperationType) { 240 return false; 241 } 242 if (mDistroStatus != that.mDistroStatus) { 243 return false; 244 } 245 if (!mBaseRulesVersion.equals(that.mBaseRulesVersion)) { 246 return false; 247 } 248 if (!mDistroFormatVersionSupported.equals(that.mDistroFormatVersionSupported)) { 249 return false; 250 } 251 if (mStagedDistroRulesVersion != null ? !mStagedDistroRulesVersion 252 .equals(that.mStagedDistroRulesVersion) : that.mStagedDistroRulesVersion != null) { 253 return false; 254 } 255 return mInstalledDistroRulesVersion != null ? mInstalledDistroRulesVersion 256 .equals(that.mInstalledDistroRulesVersion) 257 : that.mInstalledDistroRulesVersion == null; 258 } 259 260 @Override hashCode()261 public int hashCode() { 262 int result = mBaseRulesVersion.hashCode(); 263 result = 31 * result + mDistroFormatVersionSupported.hashCode(); 264 result = 31 * result + (mOperationInProgress ? 1 : 0); 265 result = 31 * result + mStagedOperationType; 266 result = 31 * result + (mStagedDistroRulesVersion != null ? mStagedDistroRulesVersion 267 .hashCode() 268 : 0); 269 result = 31 * result + mDistroStatus; 270 result = 31 * result + (mInstalledDistroRulesVersion != null ? mInstalledDistroRulesVersion 271 .hashCode() : 0); 272 return result; 273 } 274 275 @Override toString()276 public String toString() { 277 return "RulesState{" 278 + "mBaseRulesVersion='" + mBaseRulesVersion + '\'' 279 + ", mDistroFormatVersionSupported=" + mDistroFormatVersionSupported 280 + ", mOperationInProgress=" + mOperationInProgress 281 + ", mStagedOperationType=" + mStagedOperationType 282 + ", mStagedDistroRulesVersion=" + mStagedDistroRulesVersion 283 + ", mDistroStatus=" + mDistroStatus 284 + ", mInstalledDistroRulesVersion=" + mInstalledDistroRulesVersion 285 + '}'; 286 } 287 validateStagedOperation(int stagedOperationType)288 private static int validateStagedOperation(int stagedOperationType) { 289 if (stagedOperationType < STAGED_OPERATION_UNKNOWN 290 || stagedOperationType > STAGED_OPERATION_INSTALL) { 291 throw new IllegalArgumentException("Unknown operation type=" + stagedOperationType); 292 } 293 return stagedOperationType; 294 } 295 validateDistroStatus(int distroStatus)296 private static int validateDistroStatus(int distroStatus) { 297 if (distroStatus < DISTRO_STATUS_UNKNOWN || distroStatus > DISTRO_STATUS_INSTALLED) { 298 throw new IllegalArgumentException("Unknown distro status=" + distroStatus); 299 } 300 return distroStatus; 301 } 302 } 303