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

Commit 9ee90a42 authored by Hyunyoung Song's avatar Hyunyoung Song
Browse files

Icon class should support Maskable bitmap type

Test: Unit test on IconTest
$ runtest --path=frameworks/base/graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java

b/34196580

Change-Id: I321c4b02f17ad9426c053216c4c88616a605aacf
parent 620f7284
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -13766,6 +13766,7 @@ package android.graphics.drawable {
    method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
    method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
    method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
    method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
    method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
    method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
    method public int describeContents();
@@ -13849,9 +13850,9 @@ package android.graphics.drawable {
  }
  public class MaskableIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
    ctor public MaskableIconDrawable(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
    method public void draw(android.graphics.Canvas);
    method public android.graphics.drawable.Drawable getBackground();
    method public static float getExtraInsetPercentage();
    method public android.graphics.drawable.Drawable getForeground();
    method public android.graphics.Path getIconMask();
    method public int getOpacity();
@@ -13861,8 +13862,6 @@ package android.graphics.drawable {
    method public void setColorFilter(android.graphics.ColorFilter);
    method public void setOpacity(int);
    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
    field public static final float DEFAULT_VIEW_PORT_SCALE = 0.6666667f;
    field public static final float MASK_SIZE = 100.0f;
  }
  public class NinePatchDrawable extends android.graphics.drawable.Drawable {
+2 −3
Original line number Diff line number Diff line
@@ -14334,6 +14334,7 @@ package android.graphics.drawable {
    method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
    method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
    method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
    method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
    method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
    method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
    method public int describeContents();
@@ -14417,9 +14418,9 @@ package android.graphics.drawable {
  }
  public class MaskableIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
    ctor public MaskableIconDrawable(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
    method public void draw(android.graphics.Canvas);
    method public android.graphics.drawable.Drawable getBackground();
    method public static float getExtraInsetPercentage();
    method public android.graphics.drawable.Drawable getForeground();
    method public android.graphics.Path getIconMask();
    method public int getOpacity();
@@ -14429,8 +14430,6 @@ package android.graphics.drawable {
    method public void setColorFilter(android.graphics.ColorFilter);
    method public void setOpacity(int);
    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
    field public static final float DEFAULT_VIEW_PORT_SCALE = 0.6666667f;
    field public static final float MASK_SIZE = 100.0f;
  }
  public class NinePatchDrawable extends android.graphics.drawable.Drawable {
+3 −3
Original line number Diff line number Diff line
@@ -13800,6 +13800,7 @@ package android.graphics.drawable {
    method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
    method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
    method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
    method public static android.graphics.drawable.Icon createWithMaskableBitmap(android.graphics.Bitmap);
    method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int);
    method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int);
    method public int describeContents();
@@ -13883,20 +13884,19 @@ package android.graphics.drawable {
  }
  public class MaskableIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
    ctor public MaskableIconDrawable(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
    method public void draw(android.graphics.Canvas);
    method public android.graphics.drawable.Drawable getBackground();
    method public static float getExtraInsetPercentage();
    method public android.graphics.drawable.Drawable getForeground();
    method public android.graphics.Path getIconMask();
    method public int getOpacity();
    method public android.graphics.Region getSafeZone();
    method public void invalidateDrawable(android.graphics.drawable.Drawable);
    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
    method public void setAlpha(int);
    method public void setColorFilter(android.graphics.ColorFilter);
    method public void setOpacity(int);
    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
    field public static final float DEFAULT_VIEW_PORT_SCALE = 0.6666667f;
    field public static final float MASK_SIZE = 100.0f;
  }
  public class NinePatchDrawable extends android.graphics.drawable.Drawable {
+31 −3
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@ public final class Icon implements Parcelable {
    public static final int TYPE_DATA     = 3;
    /** @hide */
    public static final int TYPE_URI      = 4;
    /** @hide */
    public static final int TYPE_BITMAP_MASKABLE      = 5;

    private static final int VERSION_STREAM_SERIALIZER = 1;

@@ -101,6 +103,7 @@ public final class Icon implements Parcelable {
     * {@link #TYPE_RESOURCE},
     * {@link #TYPE_DATA}, or
     * {@link #TYPE_URI}.
     * {@link #TYPE_BITMAP_MASKABLE}
     * @hide
     */
    public int getType() {
@@ -112,7 +115,7 @@ public final class Icon implements Parcelable {
     * @hide
     */
    public Bitmap getBitmap() {
        if (mType != TYPE_BITMAP) {
        if (mType != TYPE_BITMAP && mType != TYPE_BITMAP_MASKABLE) {
            throw new IllegalStateException("called getBitmap() on " + this);
        }
        return (Bitmap) mObj1;
@@ -218,6 +221,7 @@ public final class Icon implements Parcelable {
    private static final String typeToString(int x) {
        switch (x) {
            case TYPE_BITMAP: return "BITMAP";
            case TYPE_BITMAP_MASKABLE: return "BITMAP_MASKABLE";
            case TYPE_DATA: return "DATA";
            case TYPE_RESOURCE: return "RESOURCE";
            case TYPE_URI: return "URI";
@@ -285,6 +289,9 @@ public final class Icon implements Parcelable {
        switch (mType) {
            case TYPE_BITMAP:
                return new BitmapDrawable(context.getResources(), getBitmap());
            case TYPE_BITMAP_MASKABLE:
                return new MaskableIconDrawable(null,
                    new BitmapDrawable(context.getResources(), getBitmap()));
            case TYPE_RESOURCE:
                if (getResources() == null) {
                    // figure out where to load resources from
@@ -388,7 +395,7 @@ public final class Icon implements Parcelable {
     * @hide
     */
    public void convertToAshmem() {
        if (mType == TYPE_BITMAP &&
        if ((mType == TYPE_BITMAP || mType == TYPE_BITMAP_MASKABLE) &&
            getBitmap().isMutable() &&
            getBitmap().getAllocationByteCount() >= MIN_ASHMEM_ICON_SIZE) {
            setBitmap(getBitmap().createAshmemBitmap());
@@ -409,6 +416,7 @@ public final class Icon implements Parcelable {

        switch (mType) {
            case TYPE_BITMAP:
            case TYPE_BITMAP_MASKABLE:
                getBitmap().compress(Bitmap.CompressFormat.PNG, 100, dataStream);
                break;
            case TYPE_DATA:
@@ -444,6 +452,8 @@ public final class Icon implements Parcelable {
            switch (type) {
                case TYPE_BITMAP:
                    return createWithBitmap(BitmapFactory.decodeStream(inputStream));
                case TYPE_BITMAP_MASKABLE:
                    return createWithMaskableBitmap(BitmapFactory.decodeStream(inputStream));
                case TYPE_DATA:
                    final int length = inputStream.readInt();
                    final byte[] data = new byte[length];
@@ -478,6 +488,7 @@ public final class Icon implements Parcelable {
        }
        switch (mType) {
            case TYPE_BITMAP:
            case TYPE_BITMAP_MASKABLE:
                return getBitmap() == otherIcon.getBitmap();
            case TYPE_DATA:
                return getDataLength() == otherIcon.getDataLength()
@@ -550,6 +561,20 @@ public final class Icon implements Parcelable {
        return rep;
    }

    /**
     * Create an Icon pointing to a bitmap in memory that follows the icon design guideline defined
     * by {@link MaskableIconDrawable}.
     * @param bits A valid {@link android.graphics.Bitmap} object
     */
    public static Icon createWithMaskableBitmap(Bitmap bits) {
        if (bits == null) {
            throw new IllegalArgumentException("Bitmap must not be null.");
        }
        final Icon rep = new Icon(TYPE_BITMAP_MASKABLE);
        rep.setBitmap(bits);
        return rep;
    }

    /**
     * Create an Icon pointing to a compressed bitmap stored in a byte array.
     * @param data Byte array storing compressed bitmap data of a type that
@@ -654,6 +679,7 @@ public final class Icon implements Parcelable {
        final StringBuilder sb = new StringBuilder("Icon(typ=").append(typeToString(mType));
        switch (mType) {
            case TYPE_BITMAP:
            case TYPE_BITMAP_MASKABLE:
                sb.append(" size=")
                        .append(getBitmap().getWidth())
                        .append("x")
@@ -692,7 +718,7 @@ public final class Icon implements Parcelable {
     * Parcelable interface
     */
    public int describeContents() {
        return (mType == TYPE_BITMAP || mType == TYPE_DATA)
        return (mType == TYPE_BITMAP || mType == TYPE_BITMAP_MASKABLE || mType == TYPE_DATA)
                ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
    }

@@ -702,6 +728,7 @@ public final class Icon implements Parcelable {
        this(in.readInt());
        switch (mType) {
            case TYPE_BITMAP:
            case TYPE_BITMAP_MASKABLE:
                final Bitmap bits = Bitmap.CREATOR.createFromParcel(in);
                mObj1 = bits;
                break;
@@ -740,6 +767,7 @@ public final class Icon implements Parcelable {
        dest.writeInt(mType);
        switch (mType) {
            case TYPE_BITMAP:
            case TYPE_BITMAP_MASKABLE:
                final Bitmap bits = getBitmap();
                getBitmap().writeToParcel(dest, flags);
                break;
+50 −8
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.graphics.drawable.Drawable.obtainAttributes;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -62,17 +63,22 @@ public class MaskableIconDrawable extends Drawable implements Drawable.Callback

    /**
     * Mask path is defined inside device configuration in following dimension: [100 x 100]
     * @hide
     */
    public static final float MASK_SIZE = 100f;
    private static final float SAFEZONE_SCALE = .9f;

    /**
     * The view port of the layers is smaller than their intrinsic width and height by this factor.
     *
     * It is part of the API contract that all four sides of the layers are padded so as to provide
     * All four sides of the layers are padded with extra inset so as to provide
     * extra content to reveal within the clip path when performing affine transformations on the
     * layers.
     *
     * Each layers will reserve 25% of it's width and height.
     *
     * As a result, the view port of the layers is smaller than their intrinsic width and height.
     */
    public static final float DEFAULT_VIEW_PORT_SCALE = 2f / 3f;
    private static final float EXTRA_INSET_PERCENTAGE = 1 / 4f;
    private static final float DEFAULT_VIEW_PORT_SCALE = 1f / (1 + 2 * EXTRA_INSET_PERCENTAGE);

    /**
     * Clip path defined in {@link com.android.internal.R.string.config_icon_mask}.
@@ -155,13 +161,18 @@ public class MaskableIconDrawable extends Drawable implements Drawable.Callback
     *
     * @param backgroundDrawable drawable that should be rendered in the background
     * @param foregroundDrawable drawable that should be rendered in the foreground
     * @hide
     */
    public MaskableIconDrawable(Drawable backgroundDrawable,
            Drawable foregroundDrawable) {
        this((LayerState)null, null);
        if (backgroundDrawable != null) {
            addLayer(BACKGROUND_ID, createChildDrawable(backgroundDrawable));
        }
        if (foregroundDrawable != null) {
            addLayer(FOREGROUND_ID, createChildDrawable(foregroundDrawable));
        }
    }

    /**
     * Sets the layer to the {@param index} and invalidates cache.
@@ -198,6 +209,15 @@ public class MaskableIconDrawable extends Drawable implements Drawable.Callback
        inflateLayers(r, parser, attrs, theme);
    }

    /**
     * All four sides of the layers are padded with extra inset so as to provide
     * extra content to reveal within the clip path when performing affine transformations on the
     * layers.
     */
    public static float getExtraInsetPercentage() {
        return EXTRA_INSET_PERCENTAGE;
    }

    /**
     * @return the mask path object used to clip the drawable
     */
@@ -242,13 +262,20 @@ public class MaskableIconDrawable extends Drawable implements Drawable.Callback
        int cY = bounds.centerY();

        for (int i = 0, count = mLayerState.N_CHILDREN; i < count; i++) {
            final ChildDrawable r = mLayerState.mChildren[i];
            if (r == null) {
                continue;
            }
            final Drawable d = r.mDrawable;
            if (d == null) {
                continue;
            }

            int insetWidth = (int) (bounds.width() / (DEFAULT_VIEW_PORT_SCALE * 2));
            int insetHeight = (int) (bounds.height() / (DEFAULT_VIEW_PORT_SCALE * 2));
            final Rect outRect = mTmpOutRect;
            outRect.set(cX - insetWidth, cY - insetHeight, cX + insetWidth, cY + insetHeight);

            final ChildDrawable r = mLayerState.mChildren[i];
            final Drawable d = r.mDrawable;
            d.setBounds(outRect);
        }
    }
@@ -273,6 +300,9 @@ public class MaskableIconDrawable extends Drawable implements Drawable.Callback
        if (mLayersShader == null) {
            mCanvas.setBitmap(mLayersBitmap);
            for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
                if (mLayerState.mChildren[i] == null) {
                    continue;
                }
                final Drawable dr = mLayerState.mChildren[i].mDrawable;
                if (dr != null) {
                    dr.draw(mCanvas);
@@ -295,6 +325,18 @@ public class MaskableIconDrawable extends Drawable implements Drawable.Callback
        outline.setConvexPath(mMask);
    }

    /** @hide */
    @TestApi
    public Region getSafeZone() {
        mMaskMatrix.reset();
        mMaskMatrix.setScale(SAFEZONE_SCALE, SAFEZONE_SCALE, getBounds().centerX(), getBounds().centerY());
        Path p = new Path();
        mMask.transform(mMaskMatrix, p);
        Region safezoneRegion = new Region(getBounds());
        safezoneRegion.setPath(p, safezoneRegion);
        return safezoneRegion;
    }

    @Override
    public @Nullable Region getTransparentRegion() {
        if (mTransparentRegion.isEmpty()) {
Loading