Home | History | Annotate | Download | only in timezone
      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>systemRulesVersion</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 mSystemRulesVersion;
    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 
    109     public RulesState(String systemRulesVersion, DistroFormatVersion distroFormatVersionSupported,
    110             boolean operationInProgress,
    111             @StagedOperationType int stagedOperationType,
    112             @Nullable DistroRulesVersion stagedDistroRulesVersion,
    113             @DistroStatus int distroStatus,
    114             @Nullable DistroRulesVersion installedDistroRulesVersion) {
    115         this.mSystemRulesVersion = validateRulesVersion("systemRulesVersion", systemRulesVersion);
    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 
    135     public String getSystemRulesVersion() {
    136         return mSystemRulesVersion;
    137     }
    138 
    139     public boolean isOperationInProgress() {
    140         return mOperationInProgress;
    141     }
    142 
    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      */
    151     public @Nullable DistroRulesVersion getStagedDistroRulesVersion() {
    152         return mStagedDistroRulesVersion;
    153     }
    154 
    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      */
    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      */
    170     public boolean isDistroFormatVersionSupported(DistroFormatVersion distroFormatVersion) {
    171         return mDistroFormatVersionSupported.supports(distroFormatVersion);
    172     }
    173 
    174     /**
    175      * Returns true if the system image 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 system image. Returns false if the system image 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 system image.
    180      */
    181     public boolean isSystemVersionNewerThan(DistroRulesVersion distroRulesVersion) {
    182         return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) > 0;
    183     }
    184 
    185     public static final 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 
    196     private static RulesState createFromParcel(Parcel in) {
    197         String systemRulesVersion = 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(systemRulesVersion, distroFormatVersionSupported, operationInProgress,
    205                 distroStagedState, stagedDistroRulesVersion,
    206                 installedDistroStatus, installedDistroRulesVersion);
    207     }
    208 
    209     @Override
    210     public int describeContents() {
    211         return 0;
    212     }
    213 
    214     @Override
    215     public void writeToParcel(Parcel out, int flags) {
    216         out.writeString(mSystemRulesVersion);
    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
    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 (!mSystemRulesVersion.equals(that.mSystemRulesVersion)) {
    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
    261     public int hashCode() {
    262         int result = mSystemRulesVersion.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
    276     public String toString() {
    277         return "RulesState{"
    278                 + "mSystemRulesVersion='" + mSystemRulesVersion + '\''
    279                 + ", mDistroFormatVersionSupported=" + mDistroFormatVersionSupported
    280                 + ", mOperationInProgress=" + mOperationInProgress
    281                 + ", mStagedOperationType=" + mStagedOperationType
    282                 + ", mStagedDistroRulesVersion=" + mStagedDistroRulesVersion
    283                 + ", mDistroStatus=" + mDistroStatus
    284                 + ", mInstalledDistroRulesVersion=" + mInstalledDistroRulesVersion
    285                 + '}';
    286     }
    287 
    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 
    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