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

Commit 6587430d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "AdaptiveIconDrawable should handle all usage cases of setBounds Test:...

Merge "AdaptiveIconDrawable should handle all usage cases of setBounds Test: runtest --path=frameworks/base/core/tests/coretests/src/android/graphics/drawable/AdaptiveIconDrawableTest.java"
parents 3744d8ba 0bbf4f59
Loading
Loading
Loading
Loading
+193 −0
Original line number Diff line number Diff line
package android.graphics.drawable;

import static org.junit.Assert.assertTrue;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Rect;
import android.graphics.Region;
import android.test.AndroidTestCase;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Arrays;
import org.junit.Test;

public class AdaptiveIconDrawableTest extends AndroidTestCase {

    public static final String TAG = AdaptiveIconDrawableTest.class.getSimpleName();
    public static void L(String s, Object... parts) {
        Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
    }
    private Drawable mBackgroundDrawable;
    private Drawable mForegroundDrawable;
    private AdaptiveIconDrawable mIconDrawable;
    private File mDir;

    /**
     * When setBound isn't called before draw method is called.
     * Nothing is drawn.
     */
    @Test
    public void testDrawWithoutSetBounds() throws Exception {
        mBackgroundDrawable = new ColorDrawable(Color.BLUE);
        mForegroundDrawable = new ColorDrawable(Color.RED);
        mIconDrawable = new AdaptiveIconDrawable(mBackgroundDrawable, mForegroundDrawable);
        mDir = getContext().getExternalFilesDir(null);
        L("writing temp bitmaps to %s...", mDir);

        final Bitmap bm_test = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
        final Bitmap bm_org = bm_test.copy(Config.ARGB_8888, false);
        final Canvas can1 = new Canvas(bm_test);

        // Even when setBounds is not called, should not crash
        mIconDrawable.draw(can1);
        // Draws nothing! Hence same as original.
        if (!equalBitmaps(bm_test, bm_org)) {
            findBitmapDifferences(bm_test, bm_org);
            fail("bm differs, check " + mDir);
        }
    }

    /**
     * When setBound is called, translate accordingly.
     */
    @Test
    public void testDrawSetBounds() throws Exception {
        int dpi = 4 ;
        int top = 18 * dpi;
        int left = 18 * dpi;
        int right = 90 * dpi;
        int bottom = 90 * dpi;
        int width = right - left;
        int height = bottom - top;

        mIconDrawable = (AdaptiveIconDrawable) getContext().getResources().getDrawable(android.R.drawable.sym_def_app_icon);
        mDir = getContext().getExternalFilesDir(null);
        L("writing temp bitmaps to %s...", mDir);
        final Bitmap bm_org = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        final Canvas can_org = new Canvas(bm_org);
        mIconDrawable.setBounds(0, 0, width, height);
        mIconDrawable.draw(can_org);

        // Tested bitmap is drawn from the adaptive icon drawable.
        final Bitmap bm_test = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        final Canvas can_test = new Canvas(bm_test);

        mIconDrawable.setBounds(left, top, right, bottom);
        can_test.translate(-left, -top);
        mIconDrawable.draw(can_test);
        can_test.translate(left, top);


        bm_org.compress(Bitmap.CompressFormat.PNG, 100,
            new FileOutputStream(new File(mDir, "adaptive-bm-original.png")));
        bm_test.compress(Bitmap.CompressFormat.PNG, 100,
            new FileOutputStream(new File(mDir, "adaptive-bm-test.png")));
        Region region = new Region(new Rect(0, 0, width, height));

        Path circle = new Path();
        circle.addCircle(width / 2, height / 2,  (right - left)/2 -10 /* room for anti-alias */, Direction.CW);

        region.setPath(circle, region);
        if (!equalBitmaps(bm_test, bm_org, region)) {
            findBitmapDifferences(bm_test, bm_org);
            fail("bm differs, check " + mDir);
        }
    }

    //
    // Utils
    //

    boolean equalBitmaps(Bitmap a, Bitmap b) {
      return equalBitmaps(a, b, null);
    }

    boolean equalBitmaps(Bitmap a, Bitmap b, Region region) {
        if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false;

        final int w = a.getWidth();
        final int h = a.getHeight();
        int[] aPix = new int[w * h];
        int[] bPix = new int[w * h];

        if (region != null) {
            for (int i = 0; i < w; i++) {
                for (int j = 0; j < h; j++) {
                    int ra = (a.getPixel(i, j) >> 16) & 0xff;
                    int ga = (a.getPixel(i, j) >> 8) & 0xff;
                    int ba = a.getPixel(i, j) & 0xff;
                    int rb = (b.getPixel(i, j) >> 16) & 0xff;
                    int gb = (b.getPixel(i, j) >> 8) & 0xff;
                    int bb = b.getPixel(i, j) & 0xff;
                    if (region.contains(i, j) && a.getPixel(i, j) != b.getPixel(i, j) ) {
                        return false;
                    }
                }
            }
            return true;
        } else {
            a.getPixels(aPix, 0, w, 0, 0, w, h);
            b.getPixels(bPix, 0, w, 0, 0, w, h);
            return Arrays.equals(aPix, bPix);
        }
    }

    void findBitmapDifferences(Bitmap a, Bitmap b) {
        if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
            L("different sizes: %dx%d vs %dx%d",
                a.getWidth(), a.getHeight(), b.getWidth(), b.getHeight());
            return;
        }

        final int w = a.getWidth();
        final int h = a.getHeight();
        int[] aPix = new int[w * h];
        int[] bPix = new int[w * h];

        a.getPixels(aPix, 0, w, 0, 0, w, h);
        b.getPixels(bPix, 0, w, 0, 0, w, h);

        L("bitmap a (%dx%d)", w, h);
        printBits(aPix, w, h);
        L("bitmap b (%dx%d)", w, h);
        printBits(bPix, w, h);

        StringBuffer sb = new StringBuffer("Different pixels: ");
        for (int i=0; i<w; i++) {
            for (int j=0; j<h; j++) {
                if (aPix[i+w*j] != bPix[i+w*j]) {
                    sb.append(" ").append(i).append(",").append(j).append("<")
                        .append(aPix[i+w*j]).append(",").append(bPix[i+w*j]).append(">");
                }
            }
        }
        L(sb.toString());
    }

    static void printBits(int[] a, int w, int h) {
        final StringBuilder sb = new StringBuilder();
        for (int i=0; i<w; i++) {
            for (int j=0; j<h; j++) {
                sb.append(colorToChar(a[i+w*j]));
            }
            sb.append('\n');
        }
        L(sb.toString());
    }

    static char colorToChar(int color) {
        int sum = ((color >> 16) & 0xff)
            + ((color >> 8)  & 0xff)
            + ((color)       & 0xff);
        return GRADIENT[sum * (GRADIENT.length-1) / (3*0xff)];
    }
    static final char[] GRADIENT = " .:;+=xX$#".toCharArray();
}
+14 −5
Original line number Diff line number Diff line
@@ -256,9 +256,12 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
        }
    }

    /**
     * Set the child layer bounds bigger than the view port size by {@link #DEFAULT_VIEW_PORT_SCALE}
     */
    private void updateLayerBoundsInternal(Rect bounds) {
        int cX = bounds.centerX();
        int cY = bounds.centerY();
        int cX = bounds.width() / 2;
        int cY = bounds.height() / 2;

        for (int i = 0, count = mLayerState.N_CHILDREN; i < count; i++) {
            final ChildDrawable r = mLayerState.mChildren[i];
@@ -283,7 +286,11 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
        mMaskMatrix.setScale(b.width() / MASK_SIZE, b.height() / MASK_SIZE);
        sMask.transform(mMaskMatrix, mMask);

        if (mMaskBitmap == null || mMaskBitmap.getWidth() != b.width() ||
            mMaskBitmap.getHeight() != b.height()) {
            mMaskBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ALPHA_8);
            mLayersBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ARGB_8888);
        }
        mCanvas.setBitmap(mMaskBitmap);
        mPaint.setShader(null);
        mCanvas.drawPath(mMask, mPaint);
@@ -291,7 +298,6 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
        // reset everything that depends on the view bounds
        mTransparentRegion.setEmpty();
        mLayersShader = null;
        mLayersBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ARGB_8888);
    }

    @Override
@@ -310,7 +316,10 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
            mLayersShader = new BitmapShader(mLayersBitmap, TileMode.CLAMP, TileMode.CLAMP);
            mPaint.setShader(mLayersShader);
        }
        canvas.drawBitmap(mMaskBitmap, 0.0f, 0.0f, mPaint);
        if (mMaskBitmap != null) {
            Rect bounds = getBounds();
            canvas.drawBitmap(mMaskBitmap, bounds.left, bounds.top, mPaint);
        }
    }

    @Override