From 24f11b1871f9def5d802d107897658c4b2b66ab5 Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Wed, 3 Jun 2015 12:05:37 -0400 Subject: Allow an icon to carry a tint with it, wherever it goes. Bug: 21031774 Change-Id: I2d06c7288e0c0a06bf6ff147dfbfdea5a46fd288 --- graphics/java/android/graphics/PorterDuff.java | 34 ++++++++++ graphics/java/android/graphics/drawable/Icon.java | 77 +++++++++++++++++++++-- 2 files changed, 107 insertions(+), 4 deletions(-) (limited to 'graphics') diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java index dcccf35..2bbbff3 100644 --- a/graphics/java/android/graphics/PorterDuff.java +++ b/graphics/java/android/graphics/PorterDuff.java @@ -67,4 +67,38 @@ public class PorterDuff { */ public final int nativeInt; } + + /** + * @hide + */ + public static final int modeToInt(Mode mode) { + return mode.nativeInt; + } + + /** + * @hide + */ + public static final Mode intToMode(int val) { + switch (val) { + default: + case 0: return Mode.CLEAR; + case 1: return Mode.SRC; + case 2: return Mode.DST; + case 3: return Mode.SRC_OVER; + case 4: return Mode.DST_OVER; + case 5: return Mode.SRC_IN; + case 6: return Mode.DST_IN; + case 7: return Mode.SRC_OUT; + case 8: return Mode.DST_OUT; + case 9: return Mode.SRC_ATOP; + case 10: return Mode.DST_ATOP; + case 11: return Mode.XOR; + case 16: return Mode.DARKEN; + case 17: return Mode.LIGHTEN; + case 13: return Mode.MULTIPLY; + case 14: return Mode.SCREEN; + case 12: return Mode.ADD; + case 15: return Mode.OVERLAY; + } + } } diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index 85db6a1..425225c 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -16,13 +16,16 @@ package android.graphics.drawable; +import android.annotation.ColorInt; import android.annotation.DrawableRes; +import android.content.res.ColorStateList; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.PorterDuff; import android.net.Uri; import android.os.AsyncTask; import android.os.Handler; @@ -67,6 +70,10 @@ public final class Icon implements Parcelable { private final int mType; + private ColorStateList mTintList; + static final PorterDuff.Mode DEFAULT_TINT_MODE = Drawable.DEFAULT_TINT_MODE; // SRC_IN + private PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE; + // To avoid adding unnecessary overhead, we have a few basic objects that get repurposed // based on the value of mType. @@ -254,6 +261,19 @@ public final class Icon implements Parcelable { * @return A fresh instance of a drawable for this image, yours to keep. */ public Drawable loadDrawable(Context context) { + final Drawable result = loadDrawableInner(context); + if (result != null && (mTintList != null || mTintMode != DEFAULT_TINT_MODE)) { + result.mutate(); + result.setTintList(mTintList); + result.setTintMode(mTintMode); + } + return result; + } + + /** + * Do the heavy lifting of loading the drawable, but stop short of applying any tint. + */ + private Drawable loadDrawableInner(Context context) { switch (mType) { case TYPE_BITMAP: return new BitmapDrawable(context.getResources(), getBitmap()); @@ -518,6 +538,38 @@ public final class Icon implements Parcelable { } /** + * Store a color to use whenever this Icon is drawn. + * + * @param tint a color, as in {@link Drawable#setTint(int)} + * @return this same object, for use in chained construction + */ + public Icon setTint(@ColorInt int tint) { + return setTintList(ColorStateList.valueOf(tint)); + } + + /** + * Store a color to use whenever this Icon is drawn. + * + * @param tintList as in {@link Drawable#setTintList(ColorStateList)}, null to remove tint + * @return this same object, for use in chained construction + */ + public Icon setTintList(ColorStateList tintList) { + mTintList = tintList; + return this; + } + + /** + * Store a blending mode to use whenever this Icon is drawn. + * + * @param mode a blending mode, as in {@link Drawable#setTintMode(PorterDuff.Mode)}, may be null + * @return this same object, for use in chained construction + */ + public Icon setTintMode(PorterDuff.Mode mode) { + mTintMode = mode; + return this; + } + + /** * Create an Icon pointing to an image file specified by path. * * @param path A path to a file that contains compressed bitmap data of @@ -558,6 +610,15 @@ public final class Icon implements Parcelable { sb.append(" uri=").append(getUriString()); break; } + if (mTintList != null) { + sb.append(" tint="); + String sep = ""; + for (int c : mTintList.getColors()) { + sb.append(String.format("%s0x%08x", sep, c)); + sep = "|"; + } + } + if (mTintMode != DEFAULT_TINT_MODE) sb.append(" mode=").append(mTintMode); sb.append(")"); return sb.toString(); } @@ -603,31 +664,39 @@ public final class Icon implements Parcelable { throw new RuntimeException("invalid " + this.getClass().getSimpleName() + " type in parcel: " + mType); } + if (in.readInt() == 1) { + mTintList = ColorStateList.CREATOR.createFromParcel(in); + } + mTintMode = PorterDuff.intToMode(in.readInt()); } @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mType); switch (mType) { case TYPE_BITMAP: final Bitmap bits = getBitmap(); - dest.writeInt(TYPE_BITMAP); getBitmap().writeToParcel(dest, flags); break; case TYPE_RESOURCE: - dest.writeInt(TYPE_RESOURCE); dest.writeString(getResPackage()); dest.writeInt(getResId()); break; case TYPE_DATA: - dest.writeInt(TYPE_DATA); dest.writeInt(getDataLength()); dest.writeBlob(getDataBytes(), getDataOffset(), getDataLength()); break; case TYPE_URI: - dest.writeInt(TYPE_URI); dest.writeString(getUriString()); break; } + if (mTintList == null) { + dest.writeInt(0); + } else { + dest.writeInt(1); + mTintList.writeToParcel(dest, flags); + } + dest.writeInt(PorterDuff.modeToInt(mTintMode)); } public static final Parcelable.Creator CREATOR -- cgit v1.1