Loading core/java/android/content/om/FabricatedOverlay.java +310 −96 Original line number Diff line number Diff line Loading @@ -35,29 +35,84 @@ import java.util.ArrayList; import java.util.Objects; /** * Fabricated Runtime Resource Overlays (FRROs) are overlays generated ar runtime. * FabricatedOverlay describes the content of Fabricated Runtime Resource Overlay (FRRO) that is * used to overlay the app's resources. The app should register the {@link FabricatedOverlay} * instance in an {@link OverlayManagerTransaction} by calling {@link * OverlayManagerTransaction#registerFabricatedOverlay(FabricatedOverlay)}. The FRRO is * created once the transaction is committed successfully. * * Fabricated overlays are enabled, disabled, and reordered just like normal overlays. The * overlayable policies a fabricated overlay fulfills are the same policies the creator of the * overlay fulfill. For example, a fabricated overlay created by a platform signed package on the * system partition would fulfil the {@code system} and {@code signature} policies. * <p>The app creates a FabricatedOverlay to describe the how to overlay string, integer, and file * type resources. Before creating any frro, please define a target overlayable in {@code * res/values/overlayable.xml} that describes what kind of resources can be overlaid, what kind of * roles or applications can overlay the resources. Here is an example. * * The owner of a fabricated overlay is the UID that created it. Overlays commit to the overlay * manager persist across reboots. When the UID is uninstalled, its fabricated overlays are wiped. * <pre>{@code * <overlayable name="SignatureOverlayable" actor="overlay://theme"> * <!-- The app with the same signature can overlay the below resources --> * <policy type="signature"> * <item type="color" name="mycolor" /> * <item type="string" name="mystring" /> * </policy> * </overlayable> * }</pre> * * Processes with {@link Android.Manifest.permission.CHANGE_OVERLAY_PACKAGES} can manage normal * overlays and fabricated overlays. * <p>The overlay must assign the target overlayable name just like the above example by calling * {@link #setTargetOverlayable(String)}. Here is an example: * * <pre>{@code * FabricatedOverlay fabricatedOverlay = new FabricatedOverlay("overlay_name", * context.getPackageName()); * fabricatedOverlay.setTargetOverlayable("SignatureOverlayable") * fabricatedOverlay.setResourceValue("mycolor", TypedValue.TYPE_INT_COLOR_ARGB8, Color.White) * fabricatedOverlay.setResourceValue("mystring", TypedValue.TYPE_STRING, "Hello") * }</pre> * * <p>The app can create any {@link FabricatedOverlay} instance by calling the following APIs. * * <ul> * <li>{@link #setTargetOverlayable(String)} * <li>{@link #setResourceValue(String, int, int, String)} * <li>{@link #setResourceValue(String, int, String, String)} * <li>{@link #setResourceValue(String, ParcelFileDescriptor, String)} * </ul> * * @see OverlayManager * @see OverlayManagerTransaction * @hide */ public class FabricatedOverlay { /** Retrieves the identifier for this fabricated overlay. */ /** * Retrieves the identifier for this fabricated overlay. * @return the overlay identifier * * @hide */ public OverlayIdentifier getIdentifier() { return new OverlayIdentifier( mOverlay.packageName, TextUtils.nullIfEmpty(mOverlay.overlayName)); } public static class Builder { /** * The builder of Fabricated Runtime Resource Overlays(FRROs). * * Fabricated overlays are enabled, disabled, and reordered just like normal overlays. The * overlayable policies a fabricated overlay fulfills are the same policies the creator of the * overlay fulfill. For example, a fabricated overlay created by a platform signed package on * the system partition would fulfil the {@code system} and {@code signature} policies. * * The owner of a fabricated overlay is the UID that created it. Overlays commit to the overlay * manager persist across reboots. When the UID is uninstalled, its fabricated overlays are * wiped. * * Processes with {@code android.Manifest.permission#CHANGE_OVERLAY_PACKAGES} can manage normal * overlays and fabricated overlays. * * @see FabricatedOverlay * @see OverlayManagerTransaction.Builder#registerFabricatedOverlay(FabricatedOverlay) * @hide */ public static final class Builder { private final String mOwningPackage; private final String mName; private final String mTargetPackage; Loading Loading @@ -88,22 +143,16 @@ public class FabricatedOverlay { } /** * Constructs a builder for building a fabricated overlay. * Sets the name of the target overlayable to be overlaid. * * @param name a name used to uniquely identify the fabricated overlay owned by the caller * itself. * @param targetPackage the name of the package to overlay */ public Builder(@NonNull String name, @NonNull String targetPackage) { mName = OverlayManagerImpl.checkOverlayNameValid(name); mTargetPackage = Preconditions.checkStringNotEmpty( targetPackage, "'targetPackage' must not be empty nor null"); mOwningPackage = ""; // The package name is filled in OverlayManager.commit } /** * Sets the name of the overlayable resources to overlay (can be null). * <p>The target package defines may define several overlayables. The * {@link FabricatedOverlay} should specify which overlayable to be overlaid. * * <p>The target overlayable should be defined in {@code <overlayable>} and pass the value * of its {@code name} attribute as the parameter. * * @param targetOverlayable is a name of the overlayable resources set * @hide */ @NonNull public Builder setTargetOverlayable(@Nullable String targetOverlayable) { Loading @@ -111,27 +160,6 @@ public class FabricatedOverlay { return this; } /** * Ensure the resource name is in the form [package]:type/entry. * * @param name name of the target resource to overlay (in the form [package]:type/entry) * @return the valid name */ private static String ensureValidResourceName(@NonNull String name) { Objects.requireNonNull(name); final int slashIndex = name.indexOf('/'); /* must contain '/' */ final int colonIndex = name.indexOf(':'); /* ':' should before '/' if ':' exist */ // The minimum length of resource type is "id". Preconditions.checkArgument( slashIndex >= 0 /* It must contain the type name */ && colonIndex != 0 /* 0 means the package name is empty */ && (slashIndex - colonIndex) > 2 /* The shortest length of type is "id" */, "\"%s\" is invalid resource name", name); return name; } /** * Sets the value of the fabricated overlay for the integer-like types. * Loading @@ -141,8 +169,12 @@ public class FabricatedOverlay { * @param value the unsigned 32 bit integer representing the new value * @return the builder itself * @see #setResourceValue(String, int, int, String) * @see android.util.TypedValue#type * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, int, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, Loading @@ -161,8 +193,13 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the unsigned 32 bit integer representing the new value * @param configuration The string representation of the config this overlay is enabled for * @see android.util.TypedValue#type * @return the builder itself * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, int, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, Loading @@ -171,30 +208,11 @@ public class FabricatedOverlay { int value, @Nullable String configuration) { ensureValidResourceName(resourceName); final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.dataType = Preconditions.checkArgumentInRange( dataType, TypedValue.TYPE_FIRST_INT, TypedValue.TYPE_LAST_INT, "dataType"); entry.data = value; entry.configuration = configuration; mEntries.add(entry); mEntries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, configuration)); return this; } /** @hide */ @IntDef( prefix = {"OVERLAY_TYPE"}, value = { TypedValue.TYPE_STRING, }) @Retention(RetentionPolicy.SOURCE) public @interface StringTypeOverlayResource {} /** * Sets the value of the fabricated overlay for the string-like type. * Loading @@ -203,8 +221,12 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the string representing the new value * @return the builder itself * @see android.util.TypedValue#type * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, String, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, Loading @@ -221,8 +243,13 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the string representing the new value * @param configuration The string representation of the config this overlay is enabled for * @see android.util.TypedValue#type * @return the builder itself * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, String, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, Loading @@ -230,39 +257,32 @@ public class FabricatedOverlay { @NonNull String value, @Nullable String configuration) { ensureValidResourceName(resourceName); final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.dataType = Preconditions.checkArgumentInRange( dataType, TypedValue.TYPE_STRING, TypedValue.TYPE_FRACTION, "dataType"); entry.stringData = Objects.requireNonNull(value); entry.configuration = configuration; mEntries.add(entry); mEntries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, configuration)); return this; } /** * Sets the value of the fabricated overlay * Sets the value of the fabricated overlay for the file descriptor type. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param value the file descriptor whose contents are the value of the frro * @param configuration The string representation of the config this overlay is enabled for * @return the builder itself * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, ParcelFileDescriptor, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, @NonNull ParcelFileDescriptor value, @Nullable String configuration) { ensureValidResourceName(resourceName); final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.binaryData = Objects.requireNonNull(value); entry.configuration = configuration; mEntries.add(entry); mEntries.add( generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); return this; } Loading @@ -270,22 +290,216 @@ public class FabricatedOverlay { * Builds an immutable fabricated overlay. * * @return the fabricated overlay * @hide */ @NonNull public FabricatedOverlay build() { return new FabricatedOverlay( generateFabricatedOverlayInternal(mOwningPackage, mName, mTargetPackage, mTargetOverlayable, mEntries)); } } private static FabricatedOverlayInternal generateFabricatedOverlayInternal( @NonNull String owningPackage, @NonNull String overlayName, @NonNull String targetPackageName, @Nullable String targetOverlayable, @NonNull ArrayList<FabricatedOverlayInternalEntry> entries) { final FabricatedOverlayInternal overlay = new FabricatedOverlayInternal(); overlay.packageName = mOwningPackage; overlay.overlayName = mName; overlay.targetPackageName = mTargetPackage; overlay.targetOverlayable = mTargetOverlayable; overlay.packageName = owningPackage; overlay.overlayName = overlayName; overlay.targetPackageName = targetPackageName; overlay.targetOverlayable = TextUtils.emptyIfNull(targetOverlayable); overlay.entries = new ArrayList<>(); overlay.entries.addAll(mEntries); return new FabricatedOverlay(overlay); } overlay.entries.addAll(entries); return overlay; } final FabricatedOverlayInternal mOverlay; private FabricatedOverlay(FabricatedOverlayInternal overlay) { mOverlay = overlay; } /** * Create a fabricated overlay to overlay on the specified package. * * @param overlayName a name used to uniquely identify the fabricated overlay owned by the * caller itself. * @param targetPackage the name of the package to be overlaid * @hide */ public FabricatedOverlay(@NonNull String overlayName, @NonNull String targetPackage) { this(generateFabricatedOverlayInternal( "" /* owningPackage, The package name is filled commitment */, OverlayManagerImpl.checkOverlayNameValid(overlayName), Preconditions.checkStringNotEmpty(targetPackage, "'targetPackage' must not be empty nor null"), null /* targetOverlayable */, new ArrayList<>())); } /** * Set the target overlayable name of the overlay * * The target package defines may define several overlayables. The {@link FabricatedOverlay} * should specify which overlayable to be overlaid. * * @param targetOverlayable the overlayable name defined in target package. * @hide */ public void setTargetOverlayable(@Nullable String targetOverlayable) { mOverlay.targetOverlayable = TextUtils.emptyIfNull(targetOverlayable); } /** * Return the target overlayable name of the overlay * * The target package defines may define several overlayables. The {@link FabricatedOverlay} * should specify which overlayable to be overlaid. * * @return the target overlayable name. * @hide */ @Nullable public String getTargetOverlayable() { return mOverlay.targetOverlayable; } /** * Ensure the resource name is in the form [package]:type/entry. * * @param name name of the target resource to overlay (in the form [package]:type/entry) * @return the valid name */ private static String ensureValidResourceName(@NonNull String name) { Objects.requireNonNull(name); final int slashIndex = name.indexOf('/'); /* must contain '/' */ final int colonIndex = name.indexOf(':'); /* ':' should before '/' if ':' exist */ // The minimum length of resource type is "id". Preconditions.checkArgument( slashIndex >= 0 /* It must contain the type name */ && colonIndex != 0 /* 0 means the package name is empty */ && (slashIndex - colonIndex) > 2 /* The shortest length of type is "id" */, "\"%s\" is invalid resource name", name); return name; } @NonNull private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( @NonNull String resourceName, @IntRange(from = TypedValue.TYPE_FIRST_INT, to = TypedValue.TYPE_LAST_INT) int dataType, int value, @Nullable String configuration) { final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.dataType = Preconditions.checkArgumentInRange( dataType, TypedValue.TYPE_FIRST_INT, TypedValue.TYPE_LAST_INT, "dataType"); entry.data = value; entry.configuration = configuration; return entry; } @NonNull private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( @NonNull String resourceName, @StringTypeOverlayResource int dataType, @NonNull String value, @Nullable String configuration) { final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.dataType = Preconditions.checkArgumentInRange( dataType, TypedValue.TYPE_STRING, TypedValue.TYPE_FRACTION, "dataType"); entry.stringData = Objects.requireNonNull(value); entry.configuration = configuration; return entry; } @NonNull private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( @NonNull String resourceName, @NonNull ParcelFileDescriptor parcelFileDescriptor, @Nullable String configuration) { final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.binaryData = Objects.requireNonNull(parcelFileDescriptor); entry.configuration = configuration; return entry; } /** * Sets the resource value in the fabricated overlay for the integer-like types with the * configuration. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param dataType the data type of the new value * @param value the integer representing the new value * @param configuration The string representation of the config this overlay is enabled for * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type * @hide */ @NonNull public void setResourceValue( @NonNull String resourceName, @IntRange(from = TypedValue.TYPE_FIRST_INT, to = TypedValue.TYPE_LAST_INT) int dataType, int value, @Nullable String configuration) { ensureValidResourceName(resourceName); mOverlay.entries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, configuration)); } /** @hide */ @IntDef( prefix = {"OVERLAY_TYPE"}, value = { TypedValue.TYPE_STRING, }) @Retention(RetentionPolicy.SOURCE) public @interface StringTypeOverlayResource {} /** * Sets the resource value in the fabricated overlay for the string-like type with the * configuration. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param dataType the data type of the new value * @param value the string representing the new value * @param configuration The string representation of the config this overlay is enabled for * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type * @hide */ @NonNull public void setResourceValue( @NonNull String resourceName, @StringTypeOverlayResource int dataType, @NonNull String value, @Nullable String configuration) { ensureValidResourceName(resourceName); mOverlay.entries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, configuration)); } /** * Sets the resource value in the fabricated overlay for the file descriptor type with the * configuration. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param value the file descriptor whose contents are the value of the frro * @param configuration The string representation of the config this overlay is enabled for * @hide */ @NonNull public void setResourceValue( @NonNull String resourceName, @NonNull ParcelFileDescriptor value, @Nullable String configuration) { ensureValidResourceName(resourceName); mOverlay.entries.add( generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); } } Loading
core/java/android/content/om/FabricatedOverlay.java +310 −96 Original line number Diff line number Diff line Loading @@ -35,29 +35,84 @@ import java.util.ArrayList; import java.util.Objects; /** * Fabricated Runtime Resource Overlays (FRROs) are overlays generated ar runtime. * FabricatedOverlay describes the content of Fabricated Runtime Resource Overlay (FRRO) that is * used to overlay the app's resources. The app should register the {@link FabricatedOverlay} * instance in an {@link OverlayManagerTransaction} by calling {@link * OverlayManagerTransaction#registerFabricatedOverlay(FabricatedOverlay)}. The FRRO is * created once the transaction is committed successfully. * * Fabricated overlays are enabled, disabled, and reordered just like normal overlays. The * overlayable policies a fabricated overlay fulfills are the same policies the creator of the * overlay fulfill. For example, a fabricated overlay created by a platform signed package on the * system partition would fulfil the {@code system} and {@code signature} policies. * <p>The app creates a FabricatedOverlay to describe the how to overlay string, integer, and file * type resources. Before creating any frro, please define a target overlayable in {@code * res/values/overlayable.xml} that describes what kind of resources can be overlaid, what kind of * roles or applications can overlay the resources. Here is an example. * * The owner of a fabricated overlay is the UID that created it. Overlays commit to the overlay * manager persist across reboots. When the UID is uninstalled, its fabricated overlays are wiped. * <pre>{@code * <overlayable name="SignatureOverlayable" actor="overlay://theme"> * <!-- The app with the same signature can overlay the below resources --> * <policy type="signature"> * <item type="color" name="mycolor" /> * <item type="string" name="mystring" /> * </policy> * </overlayable> * }</pre> * * Processes with {@link Android.Manifest.permission.CHANGE_OVERLAY_PACKAGES} can manage normal * overlays and fabricated overlays. * <p>The overlay must assign the target overlayable name just like the above example by calling * {@link #setTargetOverlayable(String)}. Here is an example: * * <pre>{@code * FabricatedOverlay fabricatedOverlay = new FabricatedOverlay("overlay_name", * context.getPackageName()); * fabricatedOverlay.setTargetOverlayable("SignatureOverlayable") * fabricatedOverlay.setResourceValue("mycolor", TypedValue.TYPE_INT_COLOR_ARGB8, Color.White) * fabricatedOverlay.setResourceValue("mystring", TypedValue.TYPE_STRING, "Hello") * }</pre> * * <p>The app can create any {@link FabricatedOverlay} instance by calling the following APIs. * * <ul> * <li>{@link #setTargetOverlayable(String)} * <li>{@link #setResourceValue(String, int, int, String)} * <li>{@link #setResourceValue(String, int, String, String)} * <li>{@link #setResourceValue(String, ParcelFileDescriptor, String)} * </ul> * * @see OverlayManager * @see OverlayManagerTransaction * @hide */ public class FabricatedOverlay { /** Retrieves the identifier for this fabricated overlay. */ /** * Retrieves the identifier for this fabricated overlay. * @return the overlay identifier * * @hide */ public OverlayIdentifier getIdentifier() { return new OverlayIdentifier( mOverlay.packageName, TextUtils.nullIfEmpty(mOverlay.overlayName)); } public static class Builder { /** * The builder of Fabricated Runtime Resource Overlays(FRROs). * * Fabricated overlays are enabled, disabled, and reordered just like normal overlays. The * overlayable policies a fabricated overlay fulfills are the same policies the creator of the * overlay fulfill. For example, a fabricated overlay created by a platform signed package on * the system partition would fulfil the {@code system} and {@code signature} policies. * * The owner of a fabricated overlay is the UID that created it. Overlays commit to the overlay * manager persist across reboots. When the UID is uninstalled, its fabricated overlays are * wiped. * * Processes with {@code android.Manifest.permission#CHANGE_OVERLAY_PACKAGES} can manage normal * overlays and fabricated overlays. * * @see FabricatedOverlay * @see OverlayManagerTransaction.Builder#registerFabricatedOverlay(FabricatedOverlay) * @hide */ public static final class Builder { private final String mOwningPackage; private final String mName; private final String mTargetPackage; Loading Loading @@ -88,22 +143,16 @@ public class FabricatedOverlay { } /** * Constructs a builder for building a fabricated overlay. * Sets the name of the target overlayable to be overlaid. * * @param name a name used to uniquely identify the fabricated overlay owned by the caller * itself. * @param targetPackage the name of the package to overlay */ public Builder(@NonNull String name, @NonNull String targetPackage) { mName = OverlayManagerImpl.checkOverlayNameValid(name); mTargetPackage = Preconditions.checkStringNotEmpty( targetPackage, "'targetPackage' must not be empty nor null"); mOwningPackage = ""; // The package name is filled in OverlayManager.commit } /** * Sets the name of the overlayable resources to overlay (can be null). * <p>The target package defines may define several overlayables. The * {@link FabricatedOverlay} should specify which overlayable to be overlaid. * * <p>The target overlayable should be defined in {@code <overlayable>} and pass the value * of its {@code name} attribute as the parameter. * * @param targetOverlayable is a name of the overlayable resources set * @hide */ @NonNull public Builder setTargetOverlayable(@Nullable String targetOverlayable) { Loading @@ -111,27 +160,6 @@ public class FabricatedOverlay { return this; } /** * Ensure the resource name is in the form [package]:type/entry. * * @param name name of the target resource to overlay (in the form [package]:type/entry) * @return the valid name */ private static String ensureValidResourceName(@NonNull String name) { Objects.requireNonNull(name); final int slashIndex = name.indexOf('/'); /* must contain '/' */ final int colonIndex = name.indexOf(':'); /* ':' should before '/' if ':' exist */ // The minimum length of resource type is "id". Preconditions.checkArgument( slashIndex >= 0 /* It must contain the type name */ && colonIndex != 0 /* 0 means the package name is empty */ && (slashIndex - colonIndex) > 2 /* The shortest length of type is "id" */, "\"%s\" is invalid resource name", name); return name; } /** * Sets the value of the fabricated overlay for the integer-like types. * Loading @@ -141,8 +169,12 @@ public class FabricatedOverlay { * @param value the unsigned 32 bit integer representing the new value * @return the builder itself * @see #setResourceValue(String, int, int, String) * @see android.util.TypedValue#type * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, int, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, Loading @@ -161,8 +193,13 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the unsigned 32 bit integer representing the new value * @param configuration The string representation of the config this overlay is enabled for * @see android.util.TypedValue#type * @return the builder itself * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, int, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, Loading @@ -171,30 +208,11 @@ public class FabricatedOverlay { int value, @Nullable String configuration) { ensureValidResourceName(resourceName); final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.dataType = Preconditions.checkArgumentInRange( dataType, TypedValue.TYPE_FIRST_INT, TypedValue.TYPE_LAST_INT, "dataType"); entry.data = value; entry.configuration = configuration; mEntries.add(entry); mEntries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, configuration)); return this; } /** @hide */ @IntDef( prefix = {"OVERLAY_TYPE"}, value = { TypedValue.TYPE_STRING, }) @Retention(RetentionPolicy.SOURCE) public @interface StringTypeOverlayResource {} /** * Sets the value of the fabricated overlay for the string-like type. * Loading @@ -203,8 +221,12 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the string representing the new value * @return the builder itself * @see android.util.TypedValue#type * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, String, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, Loading @@ -221,8 +243,13 @@ public class FabricatedOverlay { * @param dataType the data type of the new value * @param value the string representing the new value * @param configuration The string representation of the config this overlay is enabled for * @see android.util.TypedValue#type * @return the builder itself * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, int, String, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, Loading @@ -230,39 +257,32 @@ public class FabricatedOverlay { @NonNull String value, @Nullable String configuration) { ensureValidResourceName(resourceName); final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.dataType = Preconditions.checkArgumentInRange( dataType, TypedValue.TYPE_STRING, TypedValue.TYPE_FRACTION, "dataType"); entry.stringData = Objects.requireNonNull(value); entry.configuration = configuration; mEntries.add(entry); mEntries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, configuration)); return this; } /** * Sets the value of the fabricated overlay * Sets the value of the fabricated overlay for the file descriptor type. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param value the file descriptor whose contents are the value of the frro * @param configuration The string representation of the config this overlay is enabled for * @return the builder itself * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String, ParcelFileDescriptor, String)} instead. * @hide */ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead") @NonNull public Builder setResourceValue( @NonNull String resourceName, @NonNull ParcelFileDescriptor value, @Nullable String configuration) { ensureValidResourceName(resourceName); final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.binaryData = Objects.requireNonNull(value); entry.configuration = configuration; mEntries.add(entry); mEntries.add( generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); return this; } Loading @@ -270,22 +290,216 @@ public class FabricatedOverlay { * Builds an immutable fabricated overlay. * * @return the fabricated overlay * @hide */ @NonNull public FabricatedOverlay build() { return new FabricatedOverlay( generateFabricatedOverlayInternal(mOwningPackage, mName, mTargetPackage, mTargetOverlayable, mEntries)); } } private static FabricatedOverlayInternal generateFabricatedOverlayInternal( @NonNull String owningPackage, @NonNull String overlayName, @NonNull String targetPackageName, @Nullable String targetOverlayable, @NonNull ArrayList<FabricatedOverlayInternalEntry> entries) { final FabricatedOverlayInternal overlay = new FabricatedOverlayInternal(); overlay.packageName = mOwningPackage; overlay.overlayName = mName; overlay.targetPackageName = mTargetPackage; overlay.targetOverlayable = mTargetOverlayable; overlay.packageName = owningPackage; overlay.overlayName = overlayName; overlay.targetPackageName = targetPackageName; overlay.targetOverlayable = TextUtils.emptyIfNull(targetOverlayable); overlay.entries = new ArrayList<>(); overlay.entries.addAll(mEntries); return new FabricatedOverlay(overlay); } overlay.entries.addAll(entries); return overlay; } final FabricatedOverlayInternal mOverlay; private FabricatedOverlay(FabricatedOverlayInternal overlay) { mOverlay = overlay; } /** * Create a fabricated overlay to overlay on the specified package. * * @param overlayName a name used to uniquely identify the fabricated overlay owned by the * caller itself. * @param targetPackage the name of the package to be overlaid * @hide */ public FabricatedOverlay(@NonNull String overlayName, @NonNull String targetPackage) { this(generateFabricatedOverlayInternal( "" /* owningPackage, The package name is filled commitment */, OverlayManagerImpl.checkOverlayNameValid(overlayName), Preconditions.checkStringNotEmpty(targetPackage, "'targetPackage' must not be empty nor null"), null /* targetOverlayable */, new ArrayList<>())); } /** * Set the target overlayable name of the overlay * * The target package defines may define several overlayables. The {@link FabricatedOverlay} * should specify which overlayable to be overlaid. * * @param targetOverlayable the overlayable name defined in target package. * @hide */ public void setTargetOverlayable(@Nullable String targetOverlayable) { mOverlay.targetOverlayable = TextUtils.emptyIfNull(targetOverlayable); } /** * Return the target overlayable name of the overlay * * The target package defines may define several overlayables. The {@link FabricatedOverlay} * should specify which overlayable to be overlaid. * * @return the target overlayable name. * @hide */ @Nullable public String getTargetOverlayable() { return mOverlay.targetOverlayable; } /** * Ensure the resource name is in the form [package]:type/entry. * * @param name name of the target resource to overlay (in the form [package]:type/entry) * @return the valid name */ private static String ensureValidResourceName(@NonNull String name) { Objects.requireNonNull(name); final int slashIndex = name.indexOf('/'); /* must contain '/' */ final int colonIndex = name.indexOf(':'); /* ':' should before '/' if ':' exist */ // The minimum length of resource type is "id". Preconditions.checkArgument( slashIndex >= 0 /* It must contain the type name */ && colonIndex != 0 /* 0 means the package name is empty */ && (slashIndex - colonIndex) > 2 /* The shortest length of type is "id" */, "\"%s\" is invalid resource name", name); return name; } @NonNull private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( @NonNull String resourceName, @IntRange(from = TypedValue.TYPE_FIRST_INT, to = TypedValue.TYPE_LAST_INT) int dataType, int value, @Nullable String configuration) { final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.dataType = Preconditions.checkArgumentInRange( dataType, TypedValue.TYPE_FIRST_INT, TypedValue.TYPE_LAST_INT, "dataType"); entry.data = value; entry.configuration = configuration; return entry; } @NonNull private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( @NonNull String resourceName, @StringTypeOverlayResource int dataType, @NonNull String value, @Nullable String configuration) { final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.dataType = Preconditions.checkArgumentInRange( dataType, TypedValue.TYPE_STRING, TypedValue.TYPE_FRACTION, "dataType"); entry.stringData = Objects.requireNonNull(value); entry.configuration = configuration; return entry; } @NonNull private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry( @NonNull String resourceName, @NonNull ParcelFileDescriptor parcelFileDescriptor, @Nullable String configuration) { final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry(); entry.resourceName = resourceName; entry.binaryData = Objects.requireNonNull(parcelFileDescriptor); entry.configuration = configuration; return entry; } /** * Sets the resource value in the fabricated overlay for the integer-like types with the * configuration. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param dataType the data type of the new value * @param value the integer representing the new value * @param configuration The string representation of the config this overlay is enabled for * @see android.util.TypedValue#TYPE_INT_COLOR_ARGB8 android.util.TypedValue#type * @hide */ @NonNull public void setResourceValue( @NonNull String resourceName, @IntRange(from = TypedValue.TYPE_FIRST_INT, to = TypedValue.TYPE_LAST_INT) int dataType, int value, @Nullable String configuration) { ensureValidResourceName(resourceName); mOverlay.entries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, configuration)); } /** @hide */ @IntDef( prefix = {"OVERLAY_TYPE"}, value = { TypedValue.TYPE_STRING, }) @Retention(RetentionPolicy.SOURCE) public @interface StringTypeOverlayResource {} /** * Sets the resource value in the fabricated overlay for the string-like type with the * configuration. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param dataType the data type of the new value * @param value the string representing the new value * @param configuration The string representation of the config this overlay is enabled for * @see android.util.TypedValue#TYPE_STRING android.util.TypedValue#type * @hide */ @NonNull public void setResourceValue( @NonNull String resourceName, @StringTypeOverlayResource int dataType, @NonNull String value, @Nullable String configuration) { ensureValidResourceName(resourceName); mOverlay.entries.add(generateFabricatedOverlayInternalEntry(resourceName, dataType, value, configuration)); } /** * Sets the resource value in the fabricated overlay for the file descriptor type with the * configuration. * * @param resourceName name of the target resource to overlay (in the form * [package]:type/entry) * @param value the file descriptor whose contents are the value of the frro * @param configuration The string representation of the config this overlay is enabled for * @hide */ @NonNull public void setResourceValue( @NonNull String resourceName, @NonNull ParcelFileDescriptor value, @Nullable String configuration) { ensureValidResourceName(resourceName); mOverlay.entries.add( generateFabricatedOverlayInternalEntry(resourceName, value, configuration)); } }