summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/widget/LocalImageResolver.java137
-rw-r--r--core/tests/coretests/res/drawable/big_a.pngbin11905 -> 0 bytes
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java169
3 files changed, 18 insertions, 288 deletions
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index 66a3ff950577..616b69961b79 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,20 +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));
- }
-
- /**
- * 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.
- */
- 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);
+ final Drawable drawable =
+ ImageDecoder.decodeDrawable(source, LocalImageResolver::onHeaderDecoded);
+ return drawable;
}
/**
@@ -63,38 +48,17 @@ public class LocalImageResolver {
* 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;
- }
-
- 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;
+ 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;
}
-
- // 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 dc059a3557a8..000000000000
--- a/core/tests/coretests/res/drawable/big_a.png
+++ /dev/null
Binary files differ
diff --git a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
deleted file mode 100644
index 8dcb4a27b24d..000000000000
--- a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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 com.android.internal.widget;
-
-import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-
-import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.frameworks.coretests.R;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-
-@RunWith(AndroidJUnit4ClassRunner.class)
-public class LocalImageResolverTest {
-
- private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
-
- @Test
- public void resolveImage_largeBitmapIcon_defaultSize_resizeToDefaultSize() throws
- IOException {
- Icon icon = Icon.createWithBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- // No isLessOrEqualThan sadly.
- assertThat(bd.getBitmap().getWidth()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- assertThat(bd.getBitmap().getHeight()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- }
-
- @Test
- public void resolveImage_largeAdaptiveBitmapIcon_defaultSize_resizeToDefaultSize() throws
- IOException {
- Icon icon = Icon.createWithAdaptiveBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
- // No isLessOrEqualThan sadly.
- assertThat(bd.getBitmap().getWidth()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- assertThat(bd.getBitmap().getHeight()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- }
-
- @Test
- public void resolveImage_largeResourceIcon_defaultSize_resizeToDefaultSize() throws
- IOException {
- Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- // No isLessOrEqualThan sadly.
- assertThat(bd.getBitmap().getWidth()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- assertThat(bd.getBitmap().getHeight()).isLessThan(
- LocalImageResolver.DEFAULT_MAX_SAFE_ICON_SIZE_PX + 1);
- }
-
- @Test
- public void resolveImage_largeResourceIcon_passedSize_resizeToDefinedSize() throws
- IOException {
- Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
- Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- assertThat(bd.getBitmap().getWidth()).isLessThan(101);
- assertThat(bd.getBitmap().getHeight()).isLessThan(51);
- }
-
- @Test
- public void resolveImage_largeBitmapIcon_passedSize_resizeToDefinedSize() throws
- IOException {
- Icon icon = Icon.createWithBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
- Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- assertThat(bd.getBitmap().getWidth()).isLessThan(101);
- assertThat(bd.getBitmap().getHeight()).isLessThan(51);
- }
-
- @Test
- public void resolveImage_largeAdaptiveBitmapIcon_passedSize_resizeToDefinedSize() throws
- IOException {
- Icon icon = Icon.createWithAdaptiveBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
- Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100, 50);
-
- assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
- assertThat(bd.getBitmap().getWidth()).isLessThan(101);
- assertThat(bd.getBitmap().getHeight()).isLessThan(51);
- }
-
-
- @Test
- public void resolveImage_smallResourceIcon_defaultSize_untouched() throws IOException {
- Icon icon = Icon.createWithResource(mContext, R.drawable.test32x24);
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- assertThat(bd.getBitmap().getWidth()).isEqualTo(32);
- assertThat(bd.getBitmap().getHeight()).isEqualTo(24);
- }
-
- @Test
- public void resolveImage_smallBitmapIcon_defaultSize_untouched() throws IOException {
- Icon icon = Icon.createWithBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test32x24));
- final int originalWidth = icon.getBitmap().getWidth();
- final int originalHeight = icon.getBitmap().getHeight();
-
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
-
- assertThat(d).isInstanceOf(BitmapDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) d;
- assertThat(bd.getBitmap().getWidth()).isEqualTo(originalWidth);
- assertThat(bd.getBitmap().getHeight()).isEqualTo(originalHeight);
- }
-
- @Test
- public void resolveImage_smallAdaptiveBitmapIcon_defaultSize_untouched() throws IOException {
- Icon icon = Icon.createWithAdaptiveBitmap(
- BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test32x24));
- final int originalWidth = icon.getBitmap().getWidth();
- final int originalHeight = icon.getBitmap().getHeight();
-
- Drawable d = LocalImageResolver.resolveImage(icon, mContext);
- assertThat(d).isInstanceOf(AdaptiveIconDrawable.class);
- BitmapDrawable bd = (BitmapDrawable) ((AdaptiveIconDrawable) d).getForeground();
- assertThat(bd.getBitmap().getWidth()).isEqualTo(originalWidth);
- assertThat(bd.getBitmap().getHeight()).isEqualTo(originalHeight);
-
- }
-}