package com.bumptech.glide.load.resource.drawable; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import com.bumptech.glide.load.Options; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import java.io.IOException; import java.util.List; /** * Decodes {@link Drawable}s given resource {@link Uri}s. * *

This is typically used as a fallback for resource types that either aren't Bitmaps (see #350) * or for resource types that we can't obtain an {@link java.io.InputStream} for using a standard * {@link ContentResolver}, including some types of application icons and resources loaded from * other packages. */ public class ResourceDrawableDecoder implements ResourceDecoder { // android.resource:////. private static final int NAME_URI_PATH_SEGMENTS = 2; private static final int TYPE_PATH_SEGMENT_INDEX = 0; private static final int NAME_PATH_SEGMENT_INDEX = 1; // android.resource:/// private static final int ID_PATH_SEGMENTS = 1; private static final int RESOURCE_ID_SEGMENT_INDEX = 0; private final Context context; private final BitmapPool bitmapPool; public ResourceDrawableDecoder(Context context, BitmapPool bitmapPool) { this.context = context.getApplicationContext(); this.bitmapPool = bitmapPool; } @Override public boolean handles(Uri source, Options options) throws IOException { return source.getScheme().equals(ContentResolver.SCHEME_ANDROID_RESOURCE); } @NonNull @Override public Resource decode(Uri source, int width, int height, Options options) throws IOException { @DrawableRes int resId = loadResourceIdFromUri(source); String packageName = source.getAuthority(); Context toUse = packageName.equals(context.getPackageName()) ? context : getContextForPackage(source, packageName); // We can't get a theme from another application. Drawable drawable = DrawableDecoderCompat.getDrawable(toUse, resId); return DrawableResourceImpl.newInstance(drawable, bitmapPool); } @NonNull private Context getContextForPackage(Uri source, String packageName) { try { return context.createPackageContext(packageName, /*flags=*/ 0); } catch (NameNotFoundException e) { throw new IllegalArgumentException( "Failed to obtain context or unrecognized Uri format for: " + source, e); } } @DrawableRes private int loadResourceIdFromUri(Uri source) { List segments = source.getPathSegments(); @DrawableRes Integer result = null; if (segments.size() == NAME_URI_PATH_SEGMENTS) { String packageName = source.getAuthority(); String typeName = segments.get(TYPE_PATH_SEGMENT_INDEX); String resourceName = segments.get(NAME_PATH_SEGMENT_INDEX); result = context.getResources().getIdentifier(resourceName, typeName, packageName); } else if (segments.size() == ID_PATH_SEGMENTS) { try { result = Integer.valueOf(segments.get(RESOURCE_ID_SEGMENT_INDEX)); } catch (NumberFormatException e) { // Ignored. } } if (result == null) { throw new IllegalArgumentException("Unrecognized Uri format: " + source); } else if (result == 0) { throw new IllegalArgumentException("Failed to obtain resource id for: " + source); } return result; } }