| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.app.timezone; |
| |
| import static android.app.timezone.Utils.validateConditionalNull; |
| import static android.app.timezone.Utils.validateNotNull; |
| import static android.app.timezone.Utils.validateRulesVersion; |
| |
| import android.annotation.IntDef; |
| import android.annotation.Nullable; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * Description of the state of time zone rules on a device. |
| * |
| * <p>The following properties are included: |
| * <dl> |
| * <dt>systemRulesVersion</dt> |
| * <dd>the IANA rules version that shipped with the OS. Always present. e.g. "2017a".</dd> |
| * <dt>distroFormatVersionSupported</dt> |
| * <dd>the distro format version supported by this device. Always present.</dd> |
| * <dt>operationInProgress</dt> |
| * <dd>{@code true} if there is an install / uninstall operation currently happening.</dd> |
| * <dt>stagedOperationType</dt> |
| * <dd>one of {@link #STAGED_OPERATION_UNKNOWN}, {@link #STAGED_OPERATION_NONE}, |
| * {@link #STAGED_OPERATION_UNINSTALL} and {@link #STAGED_OPERATION_INSTALL} indicating whether |
| * there is a currently staged time zone distro operation. {@link #STAGED_OPERATION_UNKNOWN} is |
| * used when {@link #isOperationInProgress()} is {@code true}. Staged operations currently |
| * require a reboot to become active.</dd> |
| * <dt>stagedDistroRulesVersion</dt> |
| * <dd>[present if distroStagedState == STAGED_STATE_INSTALL], the rules version of the distro |
| * currently staged for installation.</dd> |
| * <dt>distroStatus</dt> |
| * <dd>{@link #DISTRO_STATUS_INSTALLED} if there is a time zone distro installed and active, |
| * {@link #DISTRO_STATUS_NONE} if there is no active installed distro. |
| * {@link #DISTRO_STATUS_UNKNOWN} is used when {@link #isOperationInProgress()} is {@code true}. |
| * </dd> |
| * <dt>installedDistroRulesVersion</dt> |
| * <dd>[present if distroStatus == {@link #DISTRO_STATUS_INSTALLED}], the rules version of the |
| * installed and active distro.</dd> |
| * </dl> |
| * |
| * @hide |
| */ |
| // TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728 |
| public final class RulesState implements Parcelable { |
| |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({ |
| STAGED_OPERATION_UNKNOWN, |
| STAGED_OPERATION_NONE, |
| STAGED_OPERATION_UNINSTALL, |
| STAGED_OPERATION_INSTALL }) |
| private @interface StagedOperationType {} |
| |
| /** Staged state could not be determined. */ |
| public static final int STAGED_OPERATION_UNKNOWN = 0; |
| /** Nothing is staged. */ |
| public static final int STAGED_OPERATION_NONE = 1; |
| /** An uninstall is staged. */ |
| public static final int STAGED_OPERATION_UNINSTALL = 2; |
| /** An install is staged. */ |
| public static final int STAGED_OPERATION_INSTALL = 3; |
| |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef({ |
| DISTRO_STATUS_UNKNOWN, |
| DISTRO_STATUS_NONE, |
| DISTRO_STATUS_INSTALLED }) |
| private @interface DistroStatus {} |
| |
| /** The current distro status could not be determined. */ |
| public static final int DISTRO_STATUS_UNKNOWN = 0; |
| /** There is no active installed time zone distro. */ |
| public static final int DISTRO_STATUS_NONE = 1; |
| /** The is an active, installed time zone distro. */ |
| public static final int DISTRO_STATUS_INSTALLED = 2; |
| |
| private static final byte BYTE_FALSE = 0; |
| private static final byte BYTE_TRUE = 1; |
| |
| private final String mSystemRulesVersion; |
| private final DistroFormatVersion mDistroFormatVersionSupported; |
| private final boolean mOperationInProgress; |
| @StagedOperationType private final int mStagedOperationType; |
| @Nullable private final DistroRulesVersion mStagedDistroRulesVersion; |
| @DistroStatus private final int mDistroStatus; |
| @Nullable private final DistroRulesVersion mInstalledDistroRulesVersion; |
| |
| public RulesState(String systemRulesVersion, DistroFormatVersion distroFormatVersionSupported, |
| boolean operationInProgress, |
| @StagedOperationType int stagedOperationType, |
| @Nullable DistroRulesVersion stagedDistroRulesVersion, |
| @DistroStatus int distroStatus, |
| @Nullable DistroRulesVersion installedDistroRulesVersion) { |
| this.mSystemRulesVersion = validateRulesVersion("systemRulesVersion", systemRulesVersion); |
| this.mDistroFormatVersionSupported = |
| validateNotNull("distroFormatVersionSupported", distroFormatVersionSupported); |
| this.mOperationInProgress = operationInProgress; |
| |
| if (operationInProgress && stagedOperationType != STAGED_OPERATION_UNKNOWN) { |
| throw new IllegalArgumentException( |
| "stagedOperationType != STAGED_OPERATION_UNKNOWN"); |
| } |
| this.mStagedOperationType = validateStagedOperation(stagedOperationType); |
| this.mStagedDistroRulesVersion = validateConditionalNull( |
| mStagedOperationType == STAGED_OPERATION_INSTALL /* requireNotNull */, |
| "stagedDistroRulesVersion", stagedDistroRulesVersion); |
| |
| if (operationInProgress && distroStatus != DISTRO_STATUS_UNKNOWN) { |
| throw new IllegalArgumentException("distroInstalled != DISTRO_STATUS_UNKNOWN"); |
| } |
| this.mDistroStatus = validateDistroStatus(distroStatus); |
| this.mInstalledDistroRulesVersion = validateConditionalNull( |
| mDistroStatus == DISTRO_STATUS_INSTALLED/* requireNotNull */, |
| "installedDistroRulesVersion", installedDistroRulesVersion); |
| } |
| |
| public String getSystemRulesVersion() { |
| return mSystemRulesVersion; |
| } |
| |
| public boolean isOperationInProgress() { |
| return mOperationInProgress; |
| } |
| |
| public @StagedOperationType int getStagedOperationType() { |
| return mStagedOperationType; |
| } |
| |
| /** |
| * Returns the staged rules version when {@link #getStagedOperationType()} is |
| * {@link #STAGED_OPERATION_INSTALL}. |
| */ |
| public @Nullable DistroRulesVersion getStagedDistroRulesVersion() { |
| return mStagedDistroRulesVersion; |
| } |
| |
| public @DistroStatus int getDistroStatus() { |
| return mDistroStatus; |
| } |
| |
| /** |
| * Returns the installed rules version when {@link #getDistroStatus()} is |
| * {@link #DISTRO_STATUS_INSTALLED}. |
| */ |
| public @Nullable DistroRulesVersion getInstalledDistroRulesVersion() { |
| return mInstalledDistroRulesVersion; |
| } |
| |
| /** |
| * Returns true if a distro in the specified format is supported on this device. |
| */ |
| public boolean isDistroFormatVersionSupported(DistroFormatVersion distroFormatVersion) { |
| return mDistroFormatVersionSupported.supports(distroFormatVersion); |
| } |
| |
| /** |
| * Returns true if the system image data files contain IANA rules data that are newer than the |
| * distro IANA rules version supplied, i.e. true when the version specified would be "worse" |
| * than the one that is in the system image. Returns false if the system image version is the |
| * same or older, i.e. false when the version specified would be "better" than the one that is |
| * in the system image. |
| */ |
| public boolean isSystemVersionNewerThan(DistroRulesVersion distroRulesVersion) { |
| return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) > 0; |
| } |
| |
| public static final Parcelable.Creator<RulesState> CREATOR = |
| new Parcelable.Creator<RulesState>() { |
| public RulesState createFromParcel(Parcel in) { |
| return RulesState.createFromParcel(in); |
| } |
| |
| public RulesState[] newArray(int size) { |
| return new RulesState[size]; |
| } |
| }; |
| |
| private static RulesState createFromParcel(Parcel in) { |
| String systemRulesVersion = in.readString(); |
| DistroFormatVersion distroFormatVersionSupported = in.readParcelable(null); |
| boolean operationInProgress = in.readByte() == BYTE_TRUE; |
| int distroStagedState = in.readByte(); |
| DistroRulesVersion stagedDistroRulesVersion = in.readParcelable(null); |
| int installedDistroStatus = in.readByte(); |
| DistroRulesVersion installedDistroRulesVersion = in.readParcelable(null); |
| return new RulesState(systemRulesVersion, distroFormatVersionSupported, operationInProgress, |
| distroStagedState, stagedDistroRulesVersion, |
| installedDistroStatus, installedDistroRulesVersion); |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel out, int flags) { |
| out.writeString(mSystemRulesVersion); |
| out.writeParcelable(mDistroFormatVersionSupported, 0); |
| out.writeByte(mOperationInProgress ? BYTE_TRUE : BYTE_FALSE); |
| out.writeByte((byte) mStagedOperationType); |
| out.writeParcelable(mStagedDistroRulesVersion, 0); |
| out.writeByte((byte) mDistroStatus); |
| out.writeParcelable(mInstalledDistroRulesVersion, 0); |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| if (o == null || getClass() != o.getClass()) { |
| return false; |
| } |
| |
| RulesState that = (RulesState) o; |
| |
| if (mOperationInProgress != that.mOperationInProgress) { |
| return false; |
| } |
| if (mStagedOperationType != that.mStagedOperationType) { |
| return false; |
| } |
| if (mDistroStatus != that.mDistroStatus) { |
| return false; |
| } |
| if (!mSystemRulesVersion.equals(that.mSystemRulesVersion)) { |
| return false; |
| } |
| if (!mDistroFormatVersionSupported.equals(that.mDistroFormatVersionSupported)) { |
| return false; |
| } |
| if (mStagedDistroRulesVersion != null ? !mStagedDistroRulesVersion |
| .equals(that.mStagedDistroRulesVersion) : that.mStagedDistroRulesVersion != null) { |
| return false; |
| } |
| return mInstalledDistroRulesVersion != null ? mInstalledDistroRulesVersion |
| .equals(that.mInstalledDistroRulesVersion) |
| : that.mInstalledDistroRulesVersion == null; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = mSystemRulesVersion.hashCode(); |
| result = 31 * result + mDistroFormatVersionSupported.hashCode(); |
| result = 31 * result + (mOperationInProgress ? 1 : 0); |
| result = 31 * result + mStagedOperationType; |
| result = 31 * result + (mStagedDistroRulesVersion != null ? mStagedDistroRulesVersion |
| .hashCode() |
| : 0); |
| result = 31 * result + mDistroStatus; |
| result = 31 * result + (mInstalledDistroRulesVersion != null ? mInstalledDistroRulesVersion |
| .hashCode() : 0); |
| return result; |
| } |
| |
| @Override |
| public String toString() { |
| return "RulesState{" |
| + "mSystemRulesVersion='" + mSystemRulesVersion + '\'' |
| + ", mDistroFormatVersionSupported=" + mDistroFormatVersionSupported |
| + ", mOperationInProgress=" + mOperationInProgress |
| + ", mStagedOperationType=" + mStagedOperationType |
| + ", mStagedDistroRulesVersion=" + mStagedDistroRulesVersion |
| + ", mDistroStatus=" + mDistroStatus |
| + ", mInstalledDistroRulesVersion=" + mInstalledDistroRulesVersion |
| + '}'; |
| } |
| |
| private static int validateStagedOperation(int stagedOperationType) { |
| if (stagedOperationType < STAGED_OPERATION_UNKNOWN |
| || stagedOperationType > STAGED_OPERATION_INSTALL) { |
| throw new IllegalArgumentException("Unknown operation type=" + stagedOperationType); |
| } |
| return stagedOperationType; |
| } |
| |
| private static int validateDistroStatus(int distroStatus) { |
| if (distroStatus < DISTRO_STATUS_UNKNOWN || distroStatus > DISTRO_STATUS_INSTALLED) { |
| throw new IllegalArgumentException("Unknown distro status=" + distroStatus); |
| } |
| return distroStatus; |
| } |
| } |