blob: b0376b503fd90b4f18cadf05c6313c825bab9fef [file] [log] [blame]
Pavel Grafovd65799e2016-12-02 11:21:45 +00001/*
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
17package android.app.admin;
18
Charles Hedea0c3b2017-01-13 10:04:12 +000019import android.annotation.IntDef;
Pavel Grafovd65799e2016-12-02 11:21:45 +000020import android.annotation.Nullable;
21import android.os.Build;
22import android.os.Parcel;
23import android.os.Parcelable;
24
25import org.xmlpull.v1.XmlPullParser;
26import org.xmlpull.v1.XmlSerializer;
27
28import java.io.IOException;
Charles Hedea0c3b2017-01-13 10:04:12 +000029import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
Pavel Grafovd65799e2016-12-02 11:21:45 +000031import java.util.Objects;
32
33/**
34 * A class containing information about a pending system update.
35 */
36public final class SystemUpdateInfo implements Parcelable {
Pavel Grafovd65799e2016-12-02 11:21:45 +000037
Charles Hedea0c3b2017-01-13 10:04:12 +000038 /**
39 * Represents it is unknown whether the system update is a security patch.
40 */
41 public static final int SECURITY_PATCH_STATE_UNKNOWN = 0;
42
43 /**
44 * Represents the system update is not a security patch.
45 */
46 public static final int SECURITY_PATCH_STATE_FALSE = 1;
47
48 /**
49 * Represents the system update is a security patch.
50 */
51 public static final int SECURITY_PATCH_STATE_TRUE = 2;
52
53 /** @hide */
54 @Retention(RetentionPolicy.SOURCE)
Jeff Sharkeyce8db992017-12-13 20:05:05 -070055 @IntDef(prefix = { "SECURITY_PATCH_STATE_" }, value = {
56 SECURITY_PATCH_STATE_FALSE,
57 SECURITY_PATCH_STATE_TRUE,
58 SECURITY_PATCH_STATE_UNKNOWN
59 })
Charles Hedea0c3b2017-01-13 10:04:12 +000060 public @interface SecurityPatchState {}
61
62 private static final String ATTR_RECEIVED_TIME = "received-time";
63 private static final String ATTR_SECURITY_PATCH_STATE = "security-patch-state";
64 // Tag used to store original build fingerprint to detect when the update is applied.
65 private static final String ATTR_ORIGINAL_BUILD = "original-build";
66
67 private final long mReceivedTime;
68 @SecurityPatchState
69 private final int mSecurityPatchState;
70
71 private SystemUpdateInfo(long receivedTime, @SecurityPatchState int securityPatchState) {
Pavel Grafovd65799e2016-12-02 11:21:45 +000072 this.mReceivedTime = receivedTime;
Charles Hedea0c3b2017-01-13 10:04:12 +000073 this.mSecurityPatchState = securityPatchState;
Pavel Grafovd65799e2016-12-02 11:21:45 +000074 }
75
76 private SystemUpdateInfo(Parcel in) {
77 mReceivedTime = in.readLong();
Charles Hedea0c3b2017-01-13 10:04:12 +000078 mSecurityPatchState = in.readInt();
Pavel Grafovd65799e2016-12-02 11:21:45 +000079 }
80
Charles Hedea0c3b2017-01-13 10:04:12 +000081 /** @hide */
Pavel Grafovd65799e2016-12-02 11:21:45 +000082 @Nullable
83 public static SystemUpdateInfo of(long receivedTime) {
Charles Hedea0c3b2017-01-13 10:04:12 +000084 return receivedTime == -1
85 ? null : new SystemUpdateInfo(receivedTime, SECURITY_PATCH_STATE_UNKNOWN);
86 }
87
88 /** @hide */
89 @Nullable
90 public static SystemUpdateInfo of(long receivedTime, boolean isSecurityPatch) {
91 return receivedTime == -1 ? null : new SystemUpdateInfo(receivedTime,
92 isSecurityPatch ? SECURITY_PATCH_STATE_TRUE : SECURITY_PATCH_STATE_FALSE);
Pavel Grafovd65799e2016-12-02 11:21:45 +000093 }
94
95 /**
Pavel Grafov937bb7f2017-04-25 12:12:25 +010096 * Gets time when the update was first available in milliseconds since midnight, January 1,
97 * 1970 UTC.
98 * @return Time in milliseconds as given by {@link System#currentTimeMillis()}
Pavel Grafovd65799e2016-12-02 11:21:45 +000099 */
100 public long getReceivedTime() {
101 return mReceivedTime;
102 }
103
Charles Hedea0c3b2017-01-13 10:04:12 +0000104 /**
105 * Gets whether the update is a security patch.
106 * @return {@link #SECURITY_PATCH_STATE_FALSE}, {@link #SECURITY_PATCH_STATE_TRUE}, or
107 * {@link #SECURITY_PATCH_STATE_UNKNOWN}.
108 */
109 @SecurityPatchState
110 public int getSecurityPatchState() {
111 return mSecurityPatchState;
112 }
113
Pavel Grafovd65799e2016-12-02 11:21:45 +0000114 public static final Creator<SystemUpdateInfo> CREATOR =
115 new Creator<SystemUpdateInfo>() {
116 @Override
117 public SystemUpdateInfo createFromParcel(Parcel in) {
118 return new SystemUpdateInfo(in);
119 }
120
121 @Override
122 public SystemUpdateInfo[] newArray(int size) {
123 return new SystemUpdateInfo[size];
124 }
125 };
126
Charles Hedea0c3b2017-01-13 10:04:12 +0000127 /** @hide */
Pavel Grafovd65799e2016-12-02 11:21:45 +0000128 public void writeToXml(XmlSerializer out, String tag) throws IOException {
129 out.startTag(null, tag);
130 out.attribute(null, ATTR_RECEIVED_TIME, String.valueOf(mReceivedTime));
Charles Hedea0c3b2017-01-13 10:04:12 +0000131 out.attribute(null, ATTR_SECURITY_PATCH_STATE, String.valueOf(mSecurityPatchState));
Pavel Grafovd65799e2016-12-02 11:21:45 +0000132 out.attribute(null, ATTR_ORIGINAL_BUILD , Build.FINGERPRINT);
133 out.endTag(null, tag);
134 }
135
Charles Hedea0c3b2017-01-13 10:04:12 +0000136 /** @hide */
Pavel Grafovd65799e2016-12-02 11:21:45 +0000137 @Nullable
138 public static SystemUpdateInfo readFromXml(XmlPullParser parser) {
139 // If an OTA has been applied (build fingerprint has changed), discard stale info.
140 final String buildFingerprint = parser.getAttributeValue(null, ATTR_ORIGINAL_BUILD );
141 if (!Build.FINGERPRINT.equals(buildFingerprint)) {
142 return null;
143 }
144 final long receivedTime =
145 Long.parseLong(parser.getAttributeValue(null, ATTR_RECEIVED_TIME));
Charles Hedea0c3b2017-01-13 10:04:12 +0000146 final int securityPatchState =
147 Integer.parseInt(parser.getAttributeValue(null, ATTR_SECURITY_PATCH_STATE));
148 return new SystemUpdateInfo(receivedTime, securityPatchState);
Pavel Grafovd65799e2016-12-02 11:21:45 +0000149 }
150
151 @Override
152 public int describeContents() {
153 return 0;
154 }
155
156 @Override
157 public void writeToParcel(Parcel dest, int flags) {
158 dest.writeLong(getReceivedTime());
Charles Hedea0c3b2017-01-13 10:04:12 +0000159 dest.writeInt(getSecurityPatchState());
Pavel Grafovd65799e2016-12-02 11:21:45 +0000160 }
161
162 @Override
163 public String toString() {
Charles Hedea0c3b2017-01-13 10:04:12 +0000164 return String.format("SystemUpdateInfo (receivedTime = %d, securityPatchState = %s)",
165 mReceivedTime, securityPatchStateToString(mSecurityPatchState));
166 }
167
168 private static String securityPatchStateToString(@SecurityPatchState int state) {
169 switch (state) {
170 case SECURITY_PATCH_STATE_FALSE:
171 return "false";
172 case SECURITY_PATCH_STATE_TRUE:
173 return "true";
174 case SECURITY_PATCH_STATE_UNKNOWN:
175 return "unknown";
176 default:
177 throw new IllegalArgumentException("Unrecognized security patch state: " + state);
178 }
Pavel Grafovd65799e2016-12-02 11:21:45 +0000179 }
180
181 @Override
182 public boolean equals(Object o) {
183 if (this == o) return true;
184 if (o == null || getClass() != o.getClass()) return false;
185 SystemUpdateInfo that = (SystemUpdateInfo) o;
Charles Hedea0c3b2017-01-13 10:04:12 +0000186 return mReceivedTime == that.mReceivedTime
187 && mSecurityPatchState == that.mSecurityPatchState;
Pavel Grafovd65799e2016-12-02 11:21:45 +0000188 }
189
190 @Override
191 public int hashCode() {
Charles Hedea0c3b2017-01-13 10:04:12 +0000192 return Objects.hash(mReceivedTime, mSecurityPatchState);
Pavel Grafovd65799e2016-12-02 11:21:45 +0000193 }
194}