Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26e492cc authored by Jernej Virag's avatar Jernej Virag
Browse files

Fix handling of negative size request for Bitmaps in LocalImageResolver

Requesting negative sized bitmap should mean "no restrictions" and not "please resize to -1x-1". This fixes the corner case for pure bitmaps.
Also reduce severity of logging when we're falling back to non-ImageDecoder load since that's not a catastrophic failure.

Bug:227103943
Bug:227008805

Test: tested on device with Notify1.apk while reproducing the issue
      atest LocalImageResolver with new tests
Change-Id: I581d3e637fcafaba68856738f90cc72c42442d60
parent 0d8aaf4b
Loading
Loading
Loading
Loading
+28 −15
Original line number Original line Diff line number Diff line
@@ -37,12 +37,18 @@ public class LocalImageResolver {


    private static final String TAG = "LocalImageResolver";
    private static final String TAG = "LocalImageResolver";


    /** There's no max size specified, load at original size. */
    public static final int NO_MAX_SIZE = -1;

    @VisibleForTesting
    @VisibleForTesting
    static final int DEFAULT_MAX_SAFE_ICON_SIZE_PX = 480;
    static final int DEFAULT_MAX_SAFE_ICON_SIZE_PX = 480;


    /**
    /**
     * Resolve an image from the given Uri using {@link ImageDecoder} if it contains a
     * Resolve an image from the given Uri using {@link ImageDecoder} if it contains a
     * bitmap reference.
     * bitmap reference.
     * Negative or zero dimensions will result in icon loaded in its original size.
     *
     * @throws IOException if the icon could not be loaded.
     */
     */
    @Nullable
    @Nullable
    public static Drawable resolveImage(Uri uri, Context context) throws IOException {
    public static Drawable resolveImage(Uri uri, Context context) throws IOException {
@@ -63,8 +69,10 @@ public class LocalImageResolver {
     * Get the drawable from Icon using {@link ImageDecoder} if it contains a bitmap reference, or
     * Get the drawable from Icon using {@link ImageDecoder} if it contains a bitmap reference, or
     * using {@link Icon#loadDrawable(Context)} otherwise.  This will correctly apply the Icon's,
     * using {@link Icon#loadDrawable(Context)} otherwise.  This will correctly apply the Icon's,
     * tint, if present, to the drawable.
     * tint, if present, to the drawable.
     * Negative or zero dimensions will result in icon loaded in its original size.
     *
     *
     * @return drawable or null if loading failed.
     * @return drawable or null if the passed icon parameter was null.
     * @throws IOException if the icon could not be loaded.
     */
     */
    @Nullable
    @Nullable
    public static Drawable resolveImage(@Nullable Icon icon, Context context) throws IOException {
    public static Drawable resolveImage(@Nullable Icon icon, Context context) throws IOException {
@@ -76,8 +84,10 @@ public class LocalImageResolver {
     * Get the drawable from Icon using {@link ImageDecoder} if it contains a bitmap reference, or
     * Get the drawable from Icon using {@link ImageDecoder} if it contains a bitmap reference, or
     * using {@link Icon#loadDrawable(Context)} otherwise.  This will correctly apply the Icon's,
     * using {@link Icon#loadDrawable(Context)} otherwise.  This will correctly apply the Icon's,
     * tint, if present, to the drawable.
     * tint, if present, to the drawable.
     * Negative or zero dimensions will result in icon loaded in its original size.
     *
     *
     * @throws IOException if the icon could not be loaded for whichever reason
     * @return loaded icon or null if a null icon was passed as a parameter.
     * @throws IOException if the icon could not be loaded.
     */
     */
    @Nullable
    @Nullable
    public static Drawable resolveImage(@Nullable Icon icon, Context context, int maxWidth,
    public static Drawable resolveImage(@Nullable Icon icon, Context context, int maxWidth,
@@ -144,6 +154,8 @@ public class LocalImageResolver {
    @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) {

        if (maxWidth > 0 && maxHeight > 0) {
            Bitmap bitmap = icon.getBitmap();
            Bitmap bitmap = icon.getBitmap();
            if (bitmap == null) {
            if (bitmap == null) {
                return null;
                return null;
@@ -158,6 +170,7 @@ public class LocalImageResolver {
                        .scaleDownIfNecessary(maxWidth, maxHeight);
                        .scaleDownIfNecessary(maxWidth, maxHeight);
                return smallerIcon.loadDrawable(context);
                return smallerIcon.loadDrawable(context);
            }
            }
        }


        return icon.loadDrawable(context);
        return icon.loadDrawable(context);
    }
    }
@@ -202,7 +215,7 @@ public class LocalImageResolver {
        // in some cases despite it not saying so. Rethrow it as an IOException to keep
        // in some cases despite it not saying so. Rethrow it as an IOException to keep
        // our API contract.
        // our API contract.
        } catch (IOException | Resources.NotFoundException e) {
        } catch (IOException | Resources.NotFoundException e) {
            Log.e(TAG, "Failed to load image drawable", e);
            Log.d(TAG, "Couldn't use ImageDecoder for drawable, falling back to non-resized load.");
            return null;
            return null;
        }
        }
    }
    }
+50 −0
Original line number Original line Diff line number Diff line
@@ -144,6 +144,56 @@ public class LocalImageResolverTest {
        assertThat(bd.getBitmap().getHeight()).isLessThan(51);
        assertThat(bd.getBitmap().getHeight()).isLessThan(51);
    }
    }


    @Test
    public void resolveImage_largeResourceIcon_negativeWidth_dontResize() {
        Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
        Drawable d = LocalImageResolver.resolveImage(icon, mContext, LocalImageResolver.NO_MAX_SIZE,
                50);

        assertThat(d).isInstanceOf(BitmapDrawable.class);
        BitmapDrawable bd = (BitmapDrawable) d;
        assertThat(bd.getBitmap().getWidth()).isGreaterThan(101);
        assertThat(bd.getBitmap().getHeight()).isGreaterThan(51);
    }

    @Test
    public void resolveImage_largeResourceIcon_negativeHeight_dontResize() {
        Icon icon = Icon.createWithResource(mContext, R.drawable.big_a);
        Drawable d = LocalImageResolver.resolveImage(icon, mContext, 100,
                LocalImageResolver.NO_MAX_SIZE);

        assertThat(d).isInstanceOf(BitmapDrawable.class);
        BitmapDrawable bd = (BitmapDrawable) d;
        assertThat(bd.getBitmap().getWidth()).isGreaterThan(101);
        assertThat(bd.getBitmap().getHeight()).isGreaterThan(51);
    }

    @Test
    public void resolveImage_largeBitmapIcon_passedNegativeWidth_dontResize() {
        Icon icon = Icon.createWithBitmap(
                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
        Drawable d = LocalImageResolver.resolveImage(icon, mContext, LocalImageResolver.NO_MAX_SIZE,
                50);

        assertThat(d).isInstanceOf(BitmapDrawable.class);
        BitmapDrawable bd = (BitmapDrawable) d;
        assertThat(bd.getBitmap().getWidth()).isGreaterThan(101);
        assertThat(bd.getBitmap().getHeight()).isGreaterThan(51);
    }

    @Test
    public void resolveImage_largeBitmapIcon_passedNegativeHeight_dontResize() {
        Icon icon = Icon.createWithBitmap(
                BitmapFactory.decodeResource(mContext.getResources(), R.drawable.big_a));
        Drawable d = LocalImageResolver.resolveImage(icon, mContext, LocalImageResolver.NO_MAX_SIZE,
                50);

        assertThat(d).isInstanceOf(BitmapDrawable.class);
        BitmapDrawable bd = (BitmapDrawable) d;
        assertThat(bd.getBitmap().getWidth()).isGreaterThan(101);
        assertThat(bd.getBitmap().getHeight()).isGreaterThan(51);
    }

    @Test
    @Test
    public void resolveImage_largeBitmapIcon_passedSize_resizeToDefinedSize() {
    public void resolveImage_largeBitmapIcon_passedSize_resizeToDefinedSize() {
        Icon icon = Icon.createWithBitmap(
        Icon icon = Icon.createWithBitmap(