From b68458f6cc6da9fabca6d63e367f0de30592fc90 Mon Sep 17 00:00:00 2001 From: Jared Duke Date: Tue, 15 Mar 2022 17:44:58 +0000 Subject: [PATCH] Revert "Support downscaling of Drawable icons in LocalImageResolver" Revert submission 17083643-large-icons-tm Reason for revert: Speculative revert for android.app.cts.NotificationManagerTest breakage. Reverted Changes: Ib66933a8f:Size restrict right notification icon size If3d871e78:Downscale large bitmaps in CachingIconView I504694cb2:Support downscaling of Drawable icons in LocalImag... Bug: 224768026 Change-Id: Icae8dfdfb89544f76a43a141b5f93271a03db360 --- .../internal/widget/LocalImageResolver.java | 137 ++------------ core/tests/coretests/res/drawable/big_a.png | Bin 11905 -> 0 bytes .../widget/LocalImageResolverTest.java | 169 ------------------ 3 files changed, 18 insertions(+), 288 deletions(-) delete mode 100644 core/tests/coretests/res/drawable/big_a.png delete mode 100644 core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java index 66a3ff950577b..616b69961b799 100644 --- a/core/java/com/android/internal/widget/LocalImageResolver.java +++ b/core/java/com/android/internal/widget/LocalImageResolver.java @@ -16,25 +16,21 @@ package com.android.internal.widget; -import android.annotation.DrawableRes; import android.annotation.Nullable; import android.content.Context; -import android.graphics.Bitmap; import android.graphics.ImageDecoder; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.net.Uri; import android.util.Size; -import com.android.internal.annotations.VisibleForTesting; - import java.io.IOException; /** A class to extract Drawables from a MessagingStyle/ConversationStyle message. */ public class LocalImageResolver { + private static final String TAG = LocalImageResolver.class.getSimpleName(); - @VisibleForTesting - static final int DEFAULT_MAX_SAFE_ICON_SIZE_PX = 480; + private static final int MAX_SAFE_ICON_SIZE_PX = 480; /** * Resolve an image from the given Uri using {@link ImageDecoder} @@ -42,9 +38,9 @@ public class LocalImageResolver { public static Drawable resolveImage(Uri uri, Context context) throws IOException { final ImageDecoder.Source source = ImageDecoder.createSource(context.getContentResolver(), uri); - return ImageDecoder.decodeDrawable(source, - (decoder, info, s) -> LocalImageResolver.onHeaderDecoded(decoder, info, - DEFAULT_MAX_SAFE_ICON_SIZE_PX, DEFAULT_MAX_SAFE_ICON_SIZE_PX)); + final Drawable drawable = + ImageDecoder.decodeDrawable(source, LocalImageResolver::onHeaderDecoded); + return drawable; } /** @@ -52,49 +48,17 @@ public class LocalImageResolver { * using {@link Icon#loadDrawable(Context)} otherwise. This will correctly apply the Icon's, * tint, if present, to the drawable. */ - public static Drawable resolveImage(@Nullable Icon icon, Context context) - throws IOException { - return resolveImage(icon, context, DEFAULT_MAX_SAFE_ICON_SIZE_PX, - DEFAULT_MAX_SAFE_ICON_SIZE_PX); - } - - /** - * Get the drawable from Icon using {@link ImageDecoder} if it contains a Uri, or - * using {@link Icon#loadDrawable(Context)} otherwise. This will correctly apply the Icon's, - * tint, if present, to the drawable. - */ - @Nullable - public static Drawable resolveImage(@Nullable Icon icon, Context context, int maxWidth, - int maxHeight) - throws IOException { - if (icon == null) { - return null; + public static Drawable resolveImage(Icon icon, Context context) throws IOException { + Uri uri = getResolvableUri(icon); + if (uri != null) { + Drawable result = resolveImage(uri, context); + if (icon.hasTint()) { + result.mutate(); + result.setTintList(icon.getTintList()); + result.setTintBlendMode(icon.getTintBlendMode()); + } + return result; } - - switch (icon.getType()) { - case Icon.TYPE_URI: - case Icon.TYPE_URI_ADAPTIVE_BITMAP: - Uri uri = getResolvableUri(icon); - if (uri != null) { - Drawable result = resolveImage(uri, context, maxWidth, maxHeight); - return tintDrawable(icon, result); - } - break; - case Icon.TYPE_RESOURCE: - Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight); - if (result != null) { - return tintDrawable(icon, result); - } - break; - case Icon.TYPE_BITMAP: - case Icon.TYPE_ADAPTIVE_BITMAP: - return resolveBitmapImage(icon, context, maxWidth, maxHeight); - case Icon.TYPE_DATA: // We can't really improve on raw data images. - default: - break; - } - - // Fallback to straight drawable load if we fail with more efficient approach. return icon.loadDrawable(context); } @@ -102,71 +66,7 @@ public class LocalImageResolver { throws IOException { final ImageDecoder.Source source = ImageDecoder.createSource(context.getContentResolver(), uri); - return resolveImage(source, maxWidth, maxHeight); - } - - /** - * Attempts to resolve the resource as a bitmap drawable constrained within max sizes. - * - * @return decoded drawable or null if the passed resource is not a straight bitmap - */ - @Nullable - public static Drawable resolveImage(@DrawableRes int resId, Context context, int maxWidth, - int maxHeight) - throws IOException { - final ImageDecoder.Source source = ImageDecoder.createSource(context.getResources(), resId); - // It's possible that the resource isn't an actual bitmap drawable so this decode can fail. - // Return null in that case. - try { - return resolveImage(source, maxWidth, maxHeight); - } catch (ImageDecoder.DecodeException e) { - return null; - } - } - - @Nullable - private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth, - int maxHeight) { - Bitmap bitmap = icon.getBitmap(); - if (bitmap == null) { - return null; - } - - if (bitmap.getWidth() > maxWidth || bitmap.getHeight() > maxHeight) { - Icon smallerIcon = icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP - ? Icon.createWithAdaptiveBitmap(bitmap) : Icon.createWithBitmap(bitmap); - // We don't want to modify the source icon, create a copy. - smallerIcon.setTintList(icon.getTintList()) - .setTintBlendMode(icon.getTintBlendMode()) - .scaleDownIfNecessary(maxWidth, maxHeight); - return smallerIcon.loadDrawable(context); - } - - return icon.loadDrawable(context); - } - - @Nullable - private static Drawable tintDrawable(Icon icon, @Nullable Drawable drawable) { - if (drawable == null) { - return null; - } - - if (icon.hasTint()) { - drawable.mutate(); - drawable.setTintList(icon.getTintList()); - drawable.setTintBlendMode(icon.getTintBlendMode()); - } - - return drawable; - } - - private static Drawable resolveImage(ImageDecoder.Source source, int maxWidth, int maxHeight) - throws IOException { return ImageDecoder.decodeDrawable(source, (decoder, info, unused) -> { - if (maxWidth <= 0 || maxHeight <= 0) { - return; - } - final Size size = info.getSize(); if (size.getWidth() > size.getHeight()) { if (size.getWidth() > maxWidth) { @@ -188,12 +88,11 @@ public class LocalImageResolver { } private static void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, - int maxWidth, int maxHeight) { + ImageDecoder.Source source) { final Size size = info.getSize(); final int originalSize = Math.max(size.getHeight(), size.getWidth()); - final int maxSize = Math.max(maxWidth, maxHeight); - final double ratio = (originalSize > maxSize) - ? originalSize * 1f / maxSize + final double ratio = (originalSize > MAX_SAFE_ICON_SIZE_PX) + ? originalSize * 1f / MAX_SAFE_ICON_SIZE_PX : 1.0; decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio)); } diff --git a/core/tests/coretests/res/drawable/big_a.png b/core/tests/coretests/res/drawable/big_a.png deleted file mode 100644 index dc059a3557a8becdb07680d8c366d6db8baaf3c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11905 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 a27prgbG6