/* * Copyright (C) 2022 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.app.admin; import static java.util.Objects.requireNonNull; import android.annotation.AnyRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.util.Slog; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; import java.util.function.Supplier; /** * Used to store the required information to load a resource that was updated using * {@link DevicePolicyResourcesManager#setDrawables} and * {@link DevicePolicyResourcesManager#setStrings}. * * @hide */ public final class ParcelableResource implements Parcelable { private static String TAG = "DevicePolicyManager"; private static final String ATTR_RESOURCE_ID = "resource-id"; private static final String ATTR_PACKAGE_NAME = "package-name"; private static final String ATTR_RESOURCE_NAME = "resource-name"; private static final String ATTR_RESOURCE_TYPE = "resource-type"; public static final int RESOURCE_TYPE_DRAWABLE = 1; public static final int RESOURCE_TYPE_STRING = 2; @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "RESOURCE_TYPE_" }, value = { RESOURCE_TYPE_DRAWABLE, RESOURCE_TYPE_STRING }) public @interface ResourceType {} private final int mResourceId; @NonNull private final String mPackageName; @NonNull private final String mResourceName; private final int mResourceType; /** * * Creates a {@code ParcelableDevicePolicyResource} for the given {@code resourceId} and * verifies that it exists in the package of the given {@code context}. * * @param context for the package containing the {@code resourceId} to use as the updated * resource * @param resourceId of the resource to use as an updated resource * @param resourceType see {@link ResourceType} */ public ParcelableResource( @NonNull Context context, @AnyRes int resourceId, @ResourceType int resourceType) throws IllegalStateException, IllegalArgumentException { Objects.requireNonNull(context, "context must be provided"); verifyResourceExistsInCallingPackage(context, resourceId, resourceType); this.mResourceId = resourceId; this.mPackageName = context.getResources().getResourcePackageName(resourceId); this.mResourceName = context.getResources().getResourceName(resourceId); this.mResourceType = resourceType; } /** * Creates a {@code ParcelableDevicePolicyResource} with the given params, this DOES NOT make * any verifications on whether the given {@code resourceId} actually exists. */ private ParcelableResource( @AnyRes int resourceId, @NonNull String packageName, @NonNull String resourceName, @ResourceType int resourceType) { this.mResourceId = resourceId; this.mPackageName = requireNonNull(packageName); this.mResourceName = requireNonNull(resourceName); this.mResourceType = resourceType; } private static void verifyResourceExistsInCallingPackage( Context context, @AnyRes int resourceId, @ResourceType int resourceType) throws IllegalStateException, IllegalArgumentException { switch (resourceType) { case RESOURCE_TYPE_DRAWABLE: if (!hasDrawableInCallingPackage(context, resourceId)) { throw new IllegalStateException(String.format( "Drawable with id %d doesn't exist in the calling package %s", resourceId, context.getPackageName())); } break; case RESOURCE_TYPE_STRING: if (!hasStringInCallingPackage(context, resourceId)) { throw new IllegalStateException(String.format( "String with id %d doesn't exist in the calling package %s", resourceId, context.getPackageName())); } break; default: throw new IllegalArgumentException( "Unknown ResourceType: " + resourceType); } } private static boolean hasDrawableInCallingPackage(Context context, @AnyRes int resourceId) { try { return "drawable".equals(context.getResources().getResourceTypeName(resourceId)); } catch (Resources.NotFoundException e) { return false; } } private static boolean hasStringInCallingPackage(Context context, @AnyRes int resourceId) { try { return "string".equals(context.getResources().getResourceTypeName(resourceId)); } catch (Resources.NotFoundException e) { return false; } } public @AnyRes int getResourceId() { return mResourceId; } @NonNull public String getPackageName() { return mPackageName; } @NonNull public String getResourceName() { return mResourceName; } public int getResourceType() { return mResourceType; } /** * Loads the drawable with id {@code mResourceId} from {@code mPackageName} using the provided * {@code density} and {@link Resources.Theme} and {@link Resources#getConfiguration} of the * provided {@code context}. * *
Returns the default drawable by calling the {@code defaultDrawableLoader} if the updated * drawable was not found or could not be loaded.
*/ @Nullable public Drawable getDrawable( Context context, int density, @NonNull SupplierReturns the default string by calling {@code defaultStringLoader} if the updated * string was not found or could not be loaded.
*/ @Nullable public String getString( Context context, @NonNull SupplierReturns the default string by calling {@code defaultStringLoader} if the updated * string was not found or could not be loaded.
*/ @Nullable public String getString( Context context, @NonNull Supplier