1 /*
2  * Copyright (C) 2015 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.content.om;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 
24 import java.lang.annotation.Retention;
25 import java.lang.annotation.RetentionPolicy;
26 
27 /**
28  * Immutable overlay information about a package. All PackageInfos that
29  * represent an overlay package will have a corresponding OverlayInfo.
30  *
31  * @hide
32  */
33 public final class OverlayInfo implements Parcelable {
34 
35     @IntDef(prefix = "STATE_", value = {
36             STATE_UNKNOWN,
37             STATE_MISSING_TARGET,
38             STATE_NO_IDMAP,
39             STATE_DISABLED,
40             STATE_ENABLED,
41             STATE_ENABLED_STATIC,
42             STATE_TARGET_UPGRADING,
43             STATE_OVERLAY_UPGRADING,
44     })
45     @Retention(RetentionPolicy.SOURCE)
46     public @interface State {}
47 
48     /**
49      * An internal state used as the initial state of an overlay. OverlayInfo
50      * objects exposed outside the {@link
51      * com.android.server.om.OverlayManagerService} should never have this
52      * state.
53      */
54     public static final int STATE_UNKNOWN = -1;
55 
56     /**
57      * The target package of the overlay is not installed. The overlay cannot be enabled.
58      */
59     public static final int STATE_MISSING_TARGET = 0;
60 
61     /**
62      * Creation of idmap file failed (e.g. no matching resources). The overlay
63      * cannot be enabled.
64      */
65     public static final int STATE_NO_IDMAP = 1;
66 
67     /**
68      * The overlay is currently disabled. It can be enabled.
69      *
70      * @see IOverlayManager#setEnabled
71      */
72     public static final int STATE_DISABLED = 2;
73 
74     /**
75      * The overlay is currently enabled. It can be disabled.
76      *
77      * @see IOverlayManager#setEnabled
78      */
79     public static final int STATE_ENABLED = 3;
80 
81     /**
82      * The target package is currently being upgraded; the state will change
83      * once the package installation has finished.
84      */
85     public static final int STATE_TARGET_UPGRADING = 4;
86 
87     /**
88      * The overlay package is currently being upgraded; the state will change
89      * once the package installation has finished.
90      */
91     public static final int STATE_OVERLAY_UPGRADING = 5;
92 
93     /**
94      * The overlay package is currently enabled because it is marked as
95      * 'static'. It cannot be disabled but will change state if for instance
96      * its target is uninstalled.
97      */
98     public static final int STATE_ENABLED_STATIC = 6;
99 
100     /**
101      * Overlay category: theme.
102      * <p>
103      * Change how Android (including the status bar, dialogs, ...) looks.
104      */
105     public static final String CATEGORY_THEME = "android.theme";
106 
107     /**
108      * Package name of the overlay package
109      */
110     public final String packageName;
111 
112     /**
113      * Package name of the target package
114      */
115     public final String targetPackageName;
116 
117     /**
118      * Category of the overlay package
119      */
120     public final String category;
121 
122     /**
123      * Full path to the base APK for this overlay package
124      */
125     public final String baseCodePath;
126 
127     /**
128      * The state of this OverlayInfo as defined by the STATE_* constants in this class.
129      */
130     public final @State int state;
131 
132     /**
133      * User handle for which this overlay applies
134      */
135     public final int userId;
136 
137     /**
138      * Priority as read from the manifest. Used if isStatic is true. Not
139      * intended to be exposed to 3rd party.
140      *
141      * @hide
142      */
143     public final int priority;
144 
145     /**
146      * isStatic as read from the manifest. If true, the overlay is
147      * unconditionally loaded and cannot be unloaded. Not intended to be
148      * exposed to 3rd party.
149      *
150      * @hide
151      */
152     public final boolean isStatic;
153 
154     /**
155      * Create a new OverlayInfo based on source with an updated state.
156      *
157      * @param source the source OverlayInfo to base the new instance on
158      * @param state the new state for the source OverlayInfo
159      */
OverlayInfo(@onNull OverlayInfo source, @State int state)160     public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
161         this(source.packageName, source.targetPackageName, source.category, source.baseCodePath,
162                 state, source.userId, source.priority, source.isStatic);
163     }
164 
OverlayInfo(@onNull String packageName, @NonNull String targetPackageName, @NonNull String category, @NonNull String baseCodePath, int state, int userId, int priority, boolean isStatic)165     public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
166             @NonNull String category, @NonNull String baseCodePath, int state, int userId,
167             int priority, boolean isStatic) {
168         this.packageName = packageName;
169         this.targetPackageName = targetPackageName;
170         this.category = category;
171         this.baseCodePath = baseCodePath;
172         this.state = state;
173         this.userId = userId;
174         this.priority = priority;
175         this.isStatic = isStatic;
176         ensureValidState();
177     }
178 
OverlayInfo(Parcel source)179     public OverlayInfo(Parcel source) {
180         packageName = source.readString();
181         targetPackageName = source.readString();
182         category = source.readString();
183         baseCodePath = source.readString();
184         state = source.readInt();
185         userId = source.readInt();
186         priority = source.readInt();
187         isStatic = source.readBoolean();
188         ensureValidState();
189     }
190 
ensureValidState()191     private void ensureValidState() {
192         if (packageName == null) {
193             throw new IllegalArgumentException("packageName must not be null");
194         }
195         if (targetPackageName == null) {
196             throw new IllegalArgumentException("targetPackageName must not be null");
197         }
198         if (baseCodePath == null) {
199             throw new IllegalArgumentException("baseCodePath must not be null");
200         }
201         switch (state) {
202             case STATE_UNKNOWN:
203             case STATE_MISSING_TARGET:
204             case STATE_NO_IDMAP:
205             case STATE_DISABLED:
206             case STATE_ENABLED:
207             case STATE_ENABLED_STATIC:
208             case STATE_TARGET_UPGRADING:
209             case STATE_OVERLAY_UPGRADING:
210                 break;
211             default:
212                 throw new IllegalArgumentException("State " + state + " is not a valid state");
213         }
214     }
215 
216     @Override
describeContents()217     public int describeContents() {
218         return 0;
219     }
220 
221     @Override
writeToParcel(Parcel dest, int flags)222     public void writeToParcel(Parcel dest, int flags) {
223         dest.writeString(packageName);
224         dest.writeString(targetPackageName);
225         dest.writeString(category);
226         dest.writeString(baseCodePath);
227         dest.writeInt(state);
228         dest.writeInt(userId);
229         dest.writeInt(priority);
230         dest.writeBoolean(isStatic);
231     }
232 
233     public static final Parcelable.Creator<OverlayInfo> CREATOR =
234             new Parcelable.Creator<OverlayInfo>() {
235         @Override
236         public OverlayInfo createFromParcel(Parcel source) {
237             return new OverlayInfo(source);
238         }
239 
240         @Override
241         public OverlayInfo[] newArray(int size) {
242             return new OverlayInfo[size];
243         }
244     };
245 
246     /**
247      * Return true if this overlay is enabled, i.e. should be used to overlay
248      * the resources in the target package.
249      *
250      * Disabled overlay packages are installed but are currently not in use.
251      *
252      * @return true if the overlay is enabled, else false.
253      */
isEnabled()254     public boolean isEnabled() {
255         switch (state) {
256             case STATE_ENABLED:
257             case STATE_ENABLED_STATIC:
258                 return true;
259             default:
260                 return false;
261         }
262     }
263 
264     /**
265      * Translate a state to a human readable string. Only intended for
266      * debugging purposes.
267      *
268      * @return a human readable String representing the state.
269      */
stateToString(@tate int state)270     public static String stateToString(@State int state) {
271         switch (state) {
272             case STATE_UNKNOWN:
273                 return "STATE_UNKNOWN";
274             case STATE_MISSING_TARGET:
275                 return "STATE_MISSING_TARGET";
276             case STATE_NO_IDMAP:
277                 return "STATE_NO_IDMAP";
278             case STATE_DISABLED:
279                 return "STATE_DISABLED";
280             case STATE_ENABLED:
281                 return "STATE_ENABLED";
282             case STATE_ENABLED_STATIC:
283                 return "STATE_ENABLED_STATIC";
284             case STATE_TARGET_UPGRADING:
285                 return "STATE_TARGET_UPGRADING";
286             case STATE_OVERLAY_UPGRADING:
287                 return "STATE_OVERLAY_UPGRADING";
288             default:
289                 return "<unknown state>";
290         }
291     }
292 
293     @Override
hashCode()294     public int hashCode() {
295         final int prime = 31;
296         int result = 1;
297         result = prime * result + userId;
298         result = prime * result + state;
299         result = prime * result + ((packageName == null) ? 0 : packageName.hashCode());
300         result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode());
301         result = prime * result + ((category == null) ? 0 : category.hashCode());
302         result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode());
303         return result;
304     }
305 
306     @Override
equals(Object obj)307     public boolean equals(Object obj) {
308         if (this == obj) {
309             return true;
310         }
311         if (obj == null) {
312             return false;
313         }
314         if (getClass() != obj.getClass()) {
315             return false;
316         }
317         OverlayInfo other = (OverlayInfo) obj;
318         if (userId != other.userId) {
319             return false;
320         }
321         if (state != other.state) {
322             return false;
323         }
324         if (!packageName.equals(other.packageName)) {
325             return false;
326         }
327         if (!targetPackageName.equals(other.targetPackageName)) {
328             return false;
329         }
330         if (!category.equals(other.category)) {
331             return false;
332         }
333         if (!baseCodePath.equals(other.baseCodePath)) {
334             return false;
335         }
336         return true;
337     }
338 
339     @Override
toString()340     public String toString() {
341         return "OverlayInfo { overlay=" + packageName + ", target=" + targetPackageName + ", state="
342                 + state + " (" + stateToString(state) + "), userId=" + userId + " }";
343     }
344 }
345