Merge "Prevent loading of Icon resources from the wrong package" into tm-qpr-dev
This commit is contained in:
@@ -19,6 +19,8 @@ package com.android.internal.widget;
|
|||||||
import android.annotation.DrawableRes;
|
import android.annotation.DrawableRes;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.ImageDecoder;
|
import android.graphics.ImageDecoder;
|
||||||
@@ -109,13 +111,13 @@ public class LocalImageResolver {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Icon.TYPE_RESOURCE:
|
case Icon.TYPE_RESOURCE:
|
||||||
if (!(TextUtils.isEmpty(icon.getResPackage())
|
Resources res = resolveResourcesForIcon(context, icon);
|
||||||
|| context.getPackageName().equals(icon.getResPackage()))) {
|
if (res == null) {
|
||||||
// We can't properly resolve icons from other packages here, so fall back.
|
// We couldn't resolve resources properly, fall back to icon loading.
|
||||||
return icon.loadDrawable(context);
|
return icon.loadDrawable(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight);
|
Drawable result = resolveImage(res, icon.getResId(), maxWidth, maxHeight);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return tintDrawable(icon, result);
|
return tintDrawable(icon, result);
|
||||||
}
|
}
|
||||||
@@ -158,6 +160,13 @@ public class LocalImageResolver {
|
|||||||
return resolveImage(source, maxWidth, maxHeight);
|
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
|
@Nullable
|
||||||
private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth,
|
private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth,
|
||||||
int maxHeight) {
|
int maxHeight) {
|
||||||
@@ -259,4 +268,52 @@ public class LocalImageResolver {
|
|||||||
}
|
}
|
||||||
return icon.getUri();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package com.android.internal.widget;
|
package com.android.internal.widget;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
@@ -279,4 +281,49 @@ public class LocalImageResolverTest {
|
|||||||
// This drawable must not be loaded - if it was, the code ignored the package specification.
|
// This drawable must not be loaded - if it was, the code ignored the package specification.
|
||||||
assertThat(d).isNull();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user