/* * Copyright (C) 2015 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.content.om; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** * Immutable overlay information about a package. All PackageInfos that * represent an overlay package will have a corresponding OverlayInfo. * * @hide */ @SystemApi public final class OverlayInfo implements CriticalOverlayInfo, Parcelable { /** @hide */ @IntDef(prefix = "STATE_", value = { STATE_UNKNOWN, STATE_MISSING_TARGET, STATE_NO_IDMAP, STATE_DISABLED, STATE_ENABLED, STATE_ENABLED_IMMUTABLE, // @Deprecated STATE_TARGET_IS_BEING_REPLACED, STATE_OVERLAY_IS_BEING_REPLACED, }) /** @hide */ @Retention(RetentionPolicy.SOURCE) public @interface State {} /** * An internal state used as the initial state of an overlay. OverlayInfo * objects exposed outside the {@link * com.android.server.om.OverlayManagerService} should never have this * state. * * @hide */ public static final int STATE_UNKNOWN = -1; /** * The target package of the overlay is not installed. The overlay cannot be enabled. * * @hide */ public static final int STATE_MISSING_TARGET = 0; /** * Creation of idmap file failed (e.g. no matching resources). The overlay * cannot be enabled. * * @hide */ public static final int STATE_NO_IDMAP = 1; /** * The overlay is currently disabled. It can be enabled. * * @see IOverlayManager#setEnabled * @hide */ public static final int STATE_DISABLED = 2; /** * The overlay is currently enabled. It can be disabled. * * @see IOverlayManager#setEnabled * @hide */ public static final int STATE_ENABLED = 3; /** * The target package is currently being upgraded or downgraded; the state * will change once the package installation has finished. * @hide * * @deprecated No longer used. Caused invalid transitions from enabled -> upgrading -> enabled, * where an update is propagated when nothing has changed. Can occur during --dont-kill * installs when code and resources are hot swapped and the Activity should not be relaunched. * In all other cases, the process and therefore Activity is killed, so the state loop is * irrelevant. */ @Deprecated public static final int STATE_TARGET_IS_BEING_REPLACED = 4; /** * The overlay package is currently being upgraded or downgraded; the state * will change once the package installation has finished. * @hide */ public static final int STATE_OVERLAY_IS_BEING_REPLACED = 5; /** * The overlay package is currently enabled because it is marked as * 'immutable'. It cannot be disabled but will change state if for instance * its target is uninstalled. * @hide */ @Deprecated public static final int STATE_ENABLED_IMMUTABLE = 6; /** * Overlay category: theme. *
* Change how Android (including the status bar, dialogs, ...) looks.
*
* @hide
*/
public static final String CATEGORY_THEME = "android.theme";
/**
* Package name of the overlay package
*
* @hide
*/
@NonNull
public final String packageName;
/**
* The unique name within the package of the overlay.
*
* @hide
*/
@Nullable
public final String overlayName;
/**
* Package name of the target package
*
* @hide
*/
@NonNull
public final String targetPackageName;
/**
* Name of the target overlayable declaration.
*
* @hide
*/
public final String targetOverlayableName;
/**
* Category of the overlay package
*
* @hide
*/
public final String category;
/**
* Full path to the base APK for this overlay package
* @hide
*/
@NonNull
public final String baseCodePath;
/**
* The state of this OverlayInfo as defined by the STATE_* constants in this class.
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public final @State int state;
/**
* User handle for which this overlay applies
* @hide
*/
public final int userId;
/**
* Priority as configured by {@link com.android.internal.content.om.OverlayConfig}.
* Not intended to be exposed to 3rd party.
*
* @hide
*/
public final int priority;
/**
* isMutable as configured by {@link com.android.internal.content.om.OverlayConfig}.
* If false, the overlay is unconditionally loaded and cannot be unloaded. Not intended to be
* exposed to 3rd party.
*
* @hide
*/
public final boolean isMutable;
private OverlayIdentifier mIdentifierCached;
/**
*
* @hide
*/
public final boolean isFabricated;
/**
* Create a new OverlayInfo based on source with an updated state.
*
* @param source the source OverlayInfo to base the new instance on
* @param state the new state for the source OverlayInfo
*
* @hide
*/
public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
this(source.packageName, source.overlayName, source.targetPackageName,
source.targetOverlayableName, source.category, source.baseCodePath, state,
source.userId, source.priority, source.isMutable, source.isFabricated);
}
/** @hide */
@VisibleForTesting
public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
@Nullable String targetOverlayableName, @Nullable String category,
@NonNull String baseCodePath, int state, int userId, int priority, boolean isMutable) {
this(packageName, null /* overlayName */, targetPackageName, targetOverlayableName,
category, baseCodePath, state, userId, priority, isMutable,
false /* isFabricated */);
}
/** @hide */
public OverlayInfo(@NonNull String packageName, @Nullable String overlayName,
@NonNull String targetPackageName, @Nullable String targetOverlayableName,
@Nullable String category, @NonNull String baseCodePath, int state, int userId,
int priority, boolean isMutable, boolean isFabricated) {
this.packageName = packageName;
this.overlayName = overlayName;
this.targetPackageName = targetPackageName;
this.targetOverlayableName = targetOverlayableName;
this.category = category;
this.baseCodePath = baseCodePath;
this.state = state;
this.userId = userId;
this.priority = priority;
this.isMutable = isMutable;
this.isFabricated = isFabricated;
ensureValidState();
}
/** @hide */
public OverlayInfo(Parcel source) {
packageName = source.readString();
overlayName = source.readString();
targetPackageName = source.readString();
targetOverlayableName = source.readString();
category = source.readString();
baseCodePath = source.readString();
state = source.readInt();
userId = source.readInt();
priority = source.readInt();
isMutable = source.readBoolean();
isFabricated = source.readBoolean();
ensureValidState();
}
/**
* {@inheritDoc}
* @hide
*/
@Override
@SystemApi
@NonNull
public String getPackageName() {
return packageName;
}
/**
* {@inheritDoc}
* @hide
*/
@Override
@Nullable
public String getOverlayName() {
return overlayName;
}
/**
* {@inheritDoc}
* @hide
*/
@Override
@SystemApi
@NonNull
public String getTargetPackageName() {
return targetPackageName;
}
/**
* Returns the category of the current overlay.
*
* @hide
*/
@SystemApi
@Nullable
public String getCategory() {
return category;
}
/**
* Returns user handle for which this overlay applies to.
*
* @hide
*/
@SystemApi
@UserIdInt
public int getUserId() {
return userId;
}
/**
* {@inheritDoc}
* @hide
*/
@Override
@SystemApi
@Nullable
public String getTargetOverlayableName() {
return targetOverlayableName;
}
/**
* {@inheritDoc}
* @hide
*/
@Override
public boolean isFabricated() {
return isFabricated;
}
/**
* Full path to the base APK or fabricated overlay for this overlay package.
*
* @hide
*/
public String getBaseCodePath() {
return baseCodePath;
}
/**
* {@inheritDoc}
* @hide
*/
@Override
@NonNull
public OverlayIdentifier getOverlayIdentifier() {
if (mIdentifierCached == null) {
mIdentifierCached = new OverlayIdentifier(packageName, overlayName);
}
return mIdentifierCached;
}
@SuppressWarnings("ConstantConditions")
private void ensureValidState() {
if (packageName == null) {
throw new IllegalArgumentException("packageName must not be null");
}
if (targetPackageName == null) {
throw new IllegalArgumentException("targetPackageName must not be null");
}
if (baseCodePath == null) {
throw new IllegalArgumentException("baseCodePath must not be null");
}
switch (state) {
case STATE_UNKNOWN:
case STATE_MISSING_TARGET:
case STATE_NO_IDMAP:
case STATE_DISABLED:
case STATE_ENABLED:
case STATE_ENABLED_IMMUTABLE:
case STATE_TARGET_IS_BEING_REPLACED:
case STATE_OVERLAY_IS_BEING_REPLACED:
break;
default:
throw new IllegalArgumentException("State " + state + " is not a valid state");
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(packageName);
dest.writeString(overlayName);
dest.writeString(targetPackageName);
dest.writeString(targetOverlayableName);
dest.writeString(category);
dest.writeString(baseCodePath);
dest.writeInt(state);
dest.writeInt(userId);
dest.writeInt(priority);
dest.writeBoolean(isMutable);
dest.writeBoolean(isFabricated);
}
public static final @android.annotation.NonNull Parcelable.Creator