• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.annotation.UnsupportedAppUsage;
24 import android.annotation.UserIdInt;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.util.Objects;
31 
32 /**
33  * Immutable overlay information about a package. All PackageInfos that
34  * represent an overlay package will have a corresponding OverlayInfo.
35  *
36  * @hide
37  */
38 @SystemApi
39 public final class OverlayInfo implements Parcelable {
40 
41     /** @hide */
42     @IntDef(prefix = "STATE_", value = {
43             STATE_UNKNOWN,
44             STATE_MISSING_TARGET,
45             STATE_NO_IDMAP,
46             STATE_DISABLED,
47             STATE_ENABLED,
48             STATE_ENABLED_STATIC,
49             // @Deprecated STATE_TARGET_IS_BEING_REPLACED,
50             STATE_OVERLAY_IS_BEING_REPLACED,
51     })
52     /** @hide */
53     @Retention(RetentionPolicy.SOURCE)
54     public @interface State {}
55 
56     /**
57      * An internal state used as the initial state of an overlay. OverlayInfo
58      * objects exposed outside the {@link
59      * com.android.server.om.OverlayManagerService} should never have this
60      * state.
61      *
62      * @hide
63      */
64     public static final int STATE_UNKNOWN = -1;
65 
66     /**
67      * The target package of the overlay is not installed. The overlay cannot be enabled.
68      *
69      * @hide
70      */
71     public static final int STATE_MISSING_TARGET = 0;
72 
73     /**
74      * Creation of idmap file failed (e.g. no matching resources). The overlay
75      * cannot be enabled.
76      *
77      * @hide
78      */
79     public static final int STATE_NO_IDMAP = 1;
80 
81     /**
82      * The overlay is currently disabled. It can be enabled.
83      *
84      * @see IOverlayManager#setEnabled
85      * @hide
86      */
87     public static final int STATE_DISABLED = 2;
88 
89     /**
90      * The overlay is currently enabled. It can be disabled.
91      *
92      * @see IOverlayManager#setEnabled
93      * @hide
94      */
95     public static final int STATE_ENABLED = 3;
96 
97     /**
98      * The target package is currently being upgraded or downgraded; the state
99      * will change once the package installation has finished.
100      * @hide
101      *
102      * @deprecated No longer used. Caused invalid transitions from enabled -> upgrading -> enabled,
103      * where an update is propagated when nothing has changed. Can occur during --dont-kill
104      * installs when code and resources are hot swapped and the Activity should not be relaunched.
105      * In all other cases, the process and therefore Activity is killed, so the state loop is
106      * irrelevant.
107      */
108     @Deprecated
109     public static final int STATE_TARGET_IS_BEING_REPLACED = 4;
110 
111     /**
112      * The overlay package is currently being upgraded or downgraded; the state
113      * will change once the package installation has finished.
114      * @hide
115      */
116     public static final int STATE_OVERLAY_IS_BEING_REPLACED = 5;
117 
118     /**
119      * The overlay package is currently enabled because it is marked as
120      * 'static'. It cannot be disabled but will change state if for instance
121      * its target is uninstalled.
122      * @hide
123      */
124     public static final int STATE_ENABLED_STATIC = 6;
125 
126     /**
127      * Overlay category: theme.
128      * <p>
129      * Change how Android (including the status bar, dialogs, ...) looks.
130      *
131      * @hide
132      */
133     public static final String CATEGORY_THEME = "android.theme";
134 
135     /**
136      * Package name of the overlay package
137      *
138      * @hide
139      */
140     public final String packageName;
141 
142     /**
143      * Package name of the target package
144      *
145      * @hide
146      */
147     public final String targetPackageName;
148 
149     /**
150      * Name of the target overlayable declaration.
151      *
152      * @hide
153      */
154     public final String targetOverlayableName;
155 
156     /**
157      * Category of the overlay package
158      *
159      * @hide
160      */
161     public final String category;
162 
163     /**
164      * Full path to the base APK for this overlay package
165      * @hide
166      */
167     public final String baseCodePath;
168 
169     /**
170      * The state of this OverlayInfo as defined by the STATE_* constants in this class.
171      * @hide
172      */
173     @UnsupportedAppUsage
174     public final @State int state;
175 
176     /**
177      * User handle for which this overlay applies
178      * @hide
179      */
180     public final int userId;
181 
182     /**
183      * Priority as read from the manifest. Used if isStatic is true. Not
184      * intended to be exposed to 3rd party.
185      *
186      * @hide
187      */
188     public final int priority;
189 
190     /**
191      * isStatic as read from the manifest. If true, the overlay is
192      * unconditionally loaded and cannot be unloaded. Not intended to be
193      * exposed to 3rd party.
194      *
195      * @hide
196      */
197     public final boolean isStatic;
198 
199     /**
200      * Create a new OverlayInfo based on source with an updated state.
201      *
202      * @param source the source OverlayInfo to base the new instance on
203      * @param state the new state for the source OverlayInfo
204      *
205      * @hide
206      */
OverlayInfo(@onNull OverlayInfo source, @State int state)207     public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
208         this(source.packageName, source.targetPackageName, source.targetOverlayableName,
209                 source.category, source.baseCodePath, state, source.userId, source.priority,
210                 source.isStatic);
211     }
212 
213     /** @hide */
OverlayInfo(@onNull String packageName, @NonNull String targetPackageName, @Nullable String targetOverlayableName, @Nullable String category, @NonNull String baseCodePath, int state, int userId, int priority, boolean isStatic)214     public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
215             @Nullable String targetOverlayableName, @Nullable String category,
216             @NonNull String baseCodePath, int state, int userId,
217             int priority, boolean isStatic) {
218         this.packageName = packageName;
219         this.targetPackageName = targetPackageName;
220         this.targetOverlayableName = targetOverlayableName;
221         this.category = category;
222         this.baseCodePath = baseCodePath;
223         this.state = state;
224         this.userId = userId;
225         this.priority = priority;
226         this.isStatic = isStatic;
227         ensureValidState();
228     }
229 
230     /** @hide */
OverlayInfo(Parcel source)231     public OverlayInfo(Parcel source) {
232         packageName = source.readString();
233         targetPackageName = source.readString();
234         targetOverlayableName = source.readString();
235         category = source.readString();
236         baseCodePath = source.readString();
237         state = source.readInt();
238         userId = source.readInt();
239         priority = source.readInt();
240         isStatic = source.readBoolean();
241         ensureValidState();
242     }
243 
244     /**
245      * Returns package name of the current overlay.
246      * @hide
247      */
248     @SystemApi
249     @NonNull
getPackageName()250     public String getPackageName() {
251         return packageName;
252     }
253 
254     /**
255      * Returns the target package name of the current overlay.
256      * @hide
257      */
258     @SystemApi
259     @NonNull
getTargetPackageName()260     public String getTargetPackageName() {
261         return targetPackageName;
262     }
263 
264     /**
265      * Returns the category of the current overlay.
266      * @hide\
267      */
268     @SystemApi
269     @Nullable
getCategory()270     public String getCategory() {
271         return category;
272     }
273 
274     /**
275      * Returns user handle for which this overlay applies to.
276      * @hide
277      */
278     @SystemApi
279     @UserIdInt
getUserId()280     public int getUserId() {
281         return userId;
282     }
283 
284     /**
285      * Returns name of the target overlayable declaration.
286      * @hide
287      */
288     @SystemApi
289     @Nullable
getTargetOverlayableName()290     public String getTargetOverlayableName() {
291         return targetOverlayableName;
292     }
293 
ensureValidState()294     private void ensureValidState() {
295         if (packageName == null) {
296             throw new IllegalArgumentException("packageName must not be null");
297         }
298         if (targetPackageName == null) {
299             throw new IllegalArgumentException("targetPackageName must not be null");
300         }
301         if (baseCodePath == null) {
302             throw new IllegalArgumentException("baseCodePath must not be null");
303         }
304         switch (state) {
305             case STATE_UNKNOWN:
306             case STATE_MISSING_TARGET:
307             case STATE_NO_IDMAP:
308             case STATE_DISABLED:
309             case STATE_ENABLED:
310             case STATE_ENABLED_STATIC:
311             case STATE_TARGET_IS_BEING_REPLACED:
312             case STATE_OVERLAY_IS_BEING_REPLACED:
313                 break;
314             default:
315                 throw new IllegalArgumentException("State " + state + " is not a valid state");
316         }
317     }
318 
319     @Override
describeContents()320     public int describeContents() {
321         return 0;
322     }
323 
324     @Override
writeToParcel(Parcel dest, int flags)325     public void writeToParcel(Parcel dest, int flags) {
326         dest.writeString(packageName);
327         dest.writeString(targetPackageName);
328         dest.writeString(targetOverlayableName);
329         dest.writeString(category);
330         dest.writeString(baseCodePath);
331         dest.writeInt(state);
332         dest.writeInt(userId);
333         dest.writeInt(priority);
334         dest.writeBoolean(isStatic);
335     }
336 
337     public static final @android.annotation.NonNull Parcelable.Creator<OverlayInfo> CREATOR =
338             new Parcelable.Creator<OverlayInfo>() {
339         @Override
340         public OverlayInfo createFromParcel(Parcel source) {
341             return new OverlayInfo(source);
342         }
343 
344         @Override
345         public OverlayInfo[] newArray(int size) {
346             return new OverlayInfo[size];
347         }
348     };
349 
350     /**
351      * Return true if this overlay is enabled, i.e. should be used to overlay
352      * the resources in the target package.
353      *
354      * Disabled overlay packages are installed but are currently not in use.
355      *
356      * @return true if the overlay is enabled, else false.
357      * @hide
358      */
359     @SystemApi
isEnabled()360     public boolean isEnabled() {
361         switch (state) {
362             case STATE_ENABLED:
363             case STATE_ENABLED_STATIC:
364                 return true;
365             default:
366                 return false;
367         }
368     }
369 
370     /**
371      * Translate a state to a human readable string. Only intended for
372      * debugging purposes.
373      *
374      * @return a human readable String representing the state.
375      * @hide
376      */
stateToString(@tate int state)377     public static String stateToString(@State int state) {
378         switch (state) {
379             case STATE_UNKNOWN:
380                 return "STATE_UNKNOWN";
381             case STATE_MISSING_TARGET:
382                 return "STATE_MISSING_TARGET";
383             case STATE_NO_IDMAP:
384                 return "STATE_NO_IDMAP";
385             case STATE_DISABLED:
386                 return "STATE_DISABLED";
387             case STATE_ENABLED:
388                 return "STATE_ENABLED";
389             case STATE_ENABLED_STATIC:
390                 return "STATE_ENABLED_STATIC";
391             case STATE_TARGET_IS_BEING_REPLACED:
392                 return "STATE_TARGET_IS_BEING_REPLACED";
393             case STATE_OVERLAY_IS_BEING_REPLACED:
394                 return "STATE_OVERLAY_IS_BEING_REPLACED";
395             default:
396                 return "<unknown state>";
397         }
398     }
399 
400     @Override
hashCode()401     public int hashCode() {
402         final int prime = 31;
403         int result = 1;
404         result = prime * result + userId;
405         result = prime * result + state;
406         result = prime * result + ((packageName == null) ? 0 : packageName.hashCode());
407         result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode());
408         result = prime * result + ((targetOverlayableName == null) ? 0
409                 : targetOverlayableName.hashCode());
410         result = prime * result + ((category == null) ? 0 : category.hashCode());
411         result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode());
412         return result;
413     }
414 
415     @Override
equals(Object obj)416     public boolean equals(Object obj) {
417         if (this == obj) {
418             return true;
419         }
420         if (obj == null) {
421             return false;
422         }
423         if (getClass() != obj.getClass()) {
424             return false;
425         }
426         OverlayInfo other = (OverlayInfo) obj;
427         if (userId != other.userId) {
428             return false;
429         }
430         if (state != other.state) {
431             return false;
432         }
433         if (!packageName.equals(other.packageName)) {
434             return false;
435         }
436         if (!targetPackageName.equals(other.targetPackageName)) {
437             return false;
438         }
439         if (!Objects.equals(targetOverlayableName, other.targetOverlayableName)) {
440             return false;
441         }
442         if (!Objects.equals(category, other.category)) {
443             return false;
444         }
445         if (!baseCodePath.equals(other.baseCodePath)) {
446             return false;
447         }
448         return true;
449     }
450 
451     @Override
toString()452     public String toString() {
453         return "OverlayInfo { overlay=" + packageName + ", targetPackage=" + targetPackageName
454                 + ((targetOverlayableName == null) ? ""
455                 : ", targetOverlayable=" + targetOverlayableName)
456                 + ", state=" + state + " (" + stateToString(state) + "), userId=" + userId + " }";
457     }
458 }
459