Loading core/java/com/android/internal/widget/LocalImageResolver.java +61 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.internal.widget; import android.annotation.DrawableRes; 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.Bitmap; import android.graphics.ImageDecoder; Loading Loading @@ -109,13 +111,13 @@ public class LocalImageResolver { } break; case Icon.TYPE_RESOURCE: if (!(TextUtils.isEmpty(icon.getResPackage()) || context.getPackageName().equals(icon.getResPackage()))) { // We can't properly resolve icons from other packages here, so fall back. Resources res = resolveResourcesForIcon(context, icon); if (res == null) { // We couldn't resolve resources properly, fall back to icon loading. return icon.loadDrawable(context); } Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight); Drawable result = resolveImage(res, icon.getResId(), maxWidth, maxHeight); if (result != null) { return tintDrawable(icon, result); } Loading Loading @@ -158,6 +160,13 @@ public class LocalImageResolver { return resolveImage(source, maxWidth, maxHeight); } @Nullable private static Drawable resolveImage(Resources res, @DrawableRes int resId, int maxWidth, int maxHeight) { final ImageDecoder.Source source = ImageDecoder.createSource(res, resId); return resolveImage(source, maxWidth, maxHeight); } @Nullable private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth, int maxHeight) { Loading Loading @@ -259,4 +268,52 @@ public class LocalImageResolver { } return icon.getUri(); } /** * Resolves the correct resources package for a given Icon - it may come from another * package. * * @see Icon#loadDrawableInner(Context) * @hide * * @return resources instance if the operation succeeded, null otherwise */ @Nullable @VisibleForTesting public static Resources resolveResourcesForIcon(Context context, Icon icon) { if (icon.getType() != Icon.TYPE_RESOURCE) { return null; } // Icons cache resolved resources, use cache if available. Resources res = icon.getResources(); if (res != null) { return res; } String resPackage = icon.getResPackage(); // No package means we try to use current context. if (TextUtils.isEmpty(resPackage) || context.getPackageName().equals(resPackage)) { return context.getResources(); } if ("android".equals(resPackage)) { return Resources.getSystem(); } final PackageManager pm = context.getPackageManager(); try { ApplicationInfo ai = pm.getApplicationInfo(resPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_SHARED_LIBRARY_FILES); if (ai != null) { return pm.getResourcesForApplication(ai); } } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, String.format("Unable to resolve package %s for icon %s", resPackage, icon)); return null; } return null; } } core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java +47 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.internal.widget; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.BitmapFactory; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; Loading Loading @@ -279,4 +281,49 @@ public class LocalImageResolverTest { // This drawable must not be loaded - if it was, the code ignored the package specification. assertThat(d).isNull(); } @Test public void resolveResourcesForIcon_notAResourceIcon_returnsNull() { Icon icon = Icon.createWithContentUri(Uri.parse("some_uri")); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull(); } @Test public void resolveResourcesForIcon_localPackageIcon_returnsPackageResources() { Icon icon = Icon.createWithResource(mContext, R.drawable.test32x24); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)) .isSameInstanceAs(mContext.getResources()); } @Test public void resolveResourcesForIcon_iconWithoutPackageSpecificed_returnsPackageResources() { Icon icon = Icon.createWithResource("", R.drawable.test32x24); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)) .isSameInstanceAs(mContext.getResources()); } @Test public void resolveResourcesForIcon_systemPackageSpecified_returnsSystemPackage() { Icon icon = Icon.createWithResource("android", R.drawable.test32x24); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isSameInstanceAs( Resources.getSystem()); } @Test public void resolveResourcesForIcon_differentPackageSpecified_returnsPackageResources() throws PackageManager.NameNotFoundException { String pkg = "com.android.settings"; Resources res = mContext.getPackageManager().getResourcesForApplication(pkg); int resId = res.getIdentifier("ic_android", "drawable", pkg); Icon icon = Icon.createWithResource(pkg, resId); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon).getDrawable(resId, mContext.getTheme())).isNotNull(); } @Test public void resolveResourcesForIcon_invalidPackageSpecified_returnsNull() { Icon icon = Icon.createWithResource("invalid.package", R.drawable.test32x24); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull(); } } Loading
core/java/com/android/internal/widget/LocalImageResolver.java +61 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.internal.widget; import android.annotation.DrawableRes; 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.Bitmap; import android.graphics.ImageDecoder; Loading Loading @@ -109,13 +111,13 @@ public class LocalImageResolver { } break; case Icon.TYPE_RESOURCE: if (!(TextUtils.isEmpty(icon.getResPackage()) || context.getPackageName().equals(icon.getResPackage()))) { // We can't properly resolve icons from other packages here, so fall back. Resources res = resolveResourcesForIcon(context, icon); if (res == null) { // We couldn't resolve resources properly, fall back to icon loading. return icon.loadDrawable(context); } Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight); Drawable result = resolveImage(res, icon.getResId(), maxWidth, maxHeight); if (result != null) { return tintDrawable(icon, result); } Loading Loading @@ -158,6 +160,13 @@ public class LocalImageResolver { return resolveImage(source, maxWidth, maxHeight); } @Nullable private static Drawable resolveImage(Resources res, @DrawableRes int resId, int maxWidth, int maxHeight) { final ImageDecoder.Source source = ImageDecoder.createSource(res, resId); return resolveImage(source, maxWidth, maxHeight); } @Nullable private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth, int maxHeight) { Loading Loading @@ -259,4 +268,52 @@ public class LocalImageResolver { } return icon.getUri(); } /** * Resolves the correct resources package for a given Icon - it may come from another * package. * * @see Icon#loadDrawableInner(Context) * @hide * * @return resources instance if the operation succeeded, null otherwise */ @Nullable @VisibleForTesting public static Resources resolveResourcesForIcon(Context context, Icon icon) { if (icon.getType() != Icon.TYPE_RESOURCE) { return null; } // Icons cache resolved resources, use cache if available. Resources res = icon.getResources(); if (res != null) { return res; } String resPackage = icon.getResPackage(); // No package means we try to use current context. if (TextUtils.isEmpty(resPackage) || context.getPackageName().equals(resPackage)) { return context.getResources(); } if ("android".equals(resPackage)) { return Resources.getSystem(); } final PackageManager pm = context.getPackageManager(); try { ApplicationInfo ai = pm.getApplicationInfo(resPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_SHARED_LIBRARY_FILES); if (ai != null) { return pm.getResourcesForApplication(ai); } } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, String.format("Unable to resolve package %s for icon %s", resPackage, icon)); return null; } return null; } }
core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java +47 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.internal.widget; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.BitmapFactory; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; Loading Loading @@ -279,4 +281,49 @@ public class LocalImageResolverTest { // This drawable must not be loaded - if it was, the code ignored the package specification. assertThat(d).isNull(); } @Test public void resolveResourcesForIcon_notAResourceIcon_returnsNull() { Icon icon = Icon.createWithContentUri(Uri.parse("some_uri")); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull(); } @Test public void resolveResourcesForIcon_localPackageIcon_returnsPackageResources() { Icon icon = Icon.createWithResource(mContext, R.drawable.test32x24); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)) .isSameInstanceAs(mContext.getResources()); } @Test public void resolveResourcesForIcon_iconWithoutPackageSpecificed_returnsPackageResources() { Icon icon = Icon.createWithResource("", R.drawable.test32x24); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)) .isSameInstanceAs(mContext.getResources()); } @Test public void resolveResourcesForIcon_systemPackageSpecified_returnsSystemPackage() { Icon icon = Icon.createWithResource("android", R.drawable.test32x24); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isSameInstanceAs( Resources.getSystem()); } @Test public void resolveResourcesForIcon_differentPackageSpecified_returnsPackageResources() throws PackageManager.NameNotFoundException { String pkg = "com.android.settings"; Resources res = mContext.getPackageManager().getResourcesForApplication(pkg); int resId = res.getIdentifier("ic_android", "drawable", pkg); Icon icon = Icon.createWithResource(pkg, resId); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon).getDrawable(resId, mContext.getTheme())).isNotNull(); } @Test public void resolveResourcesForIcon_invalidPackageSpecified_returnsNull() { Icon icon = Icon.createWithResource("invalid.package", R.drawable.test32x24); assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull(); } }