From b3c56086d802ae28888dd97ba1f49bd6cee0b673 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Sat, 14 Jun 2014 12:57:55 -0700 Subject: [PATCH] Add support for setTint in all Drawables, clean up lint warnings Change-Id: I962089ca59684cef28cb4a648d4a91e542bdf5d4 --- .../android/graphics/drawable/Animatable.java | 2 +- .../drawable/AnimatedRotateDrawable.java | 52 ++++++++++---- .../graphics/drawable/AnimationDrawable.java | 43 ++++++------ .../graphics/drawable/BitmapDrawable.java | 40 +++-------- .../graphics/drawable/ClipDrawable.java | 14 +++- .../graphics/drawable/ColorDrawable.java | 70 ++++++++++++++++--- .../android/graphics/drawable/Drawable.java | 36 +++++++--- .../graphics/drawable/DrawableContainer.java | 29 +++++++- .../graphics/drawable/InsetDrawable.java | 33 ++++++--- .../graphics/drawable/LayerDrawable.java | 11 +++ .../drawable/MaterialProgressDrawable.java | 34 ++++++++- .../graphics/drawable/NinePatchDrawable.java | 38 +++------- .../graphics/drawable/PaintDrawable.java | 8 +-- .../graphics/drawable/PictureDrawable.java | 16 ++--- .../graphics/drawable/RotateDrawable.java | 7 ++ .../graphics/drawable/ScaleDrawable.java | 7 ++ .../graphics/drawable/ShapeDrawable.java | 5 +- .../graphics/drawable/StateListDrawable.java | 6 +- .../graphics/drawable/TransitionDrawable.java | 18 ++--- .../graphics/drawable/VectorDrawable.java | 49 ++++++++++++- 20 files changed, 362 insertions(+), 156 deletions(-) diff --git a/graphics/java/android/graphics/drawable/Animatable.java b/graphics/java/android/graphics/drawable/Animatable.java index 9dc62c36d6180..4edfad4fd7dd3 100644 --- a/graphics/java/android/graphics/drawable/Animatable.java +++ b/graphics/java/android/graphics/drawable/Animatable.java @@ -32,7 +32,7 @@ public interface Animatable { /** * Indicates whether the animation is running. - * + * * @return True if the animation is running, false otherwise. */ boolean isRunning(); diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java index e8024f7864f0e..0fd442382dd64 100644 --- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java @@ -19,6 +19,8 @@ package android.graphics.drawable; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.ColorFilter; +import android.graphics.PorterDuff.Mode; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; @@ -88,6 +90,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac canvas.restoreToCount(saveCount); } + @Override public void start() { if (!mRunning) { mRunning = true; @@ -95,11 +98,13 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } } + @Override public void stop() { mRunning = false; unscheduleSelf(this); } + @Override public boolean isRunning() { return mRunning; } @@ -108,10 +113,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac unscheduleSelf(this); scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration); } - + + @Override public void run() { // TODO: This should be computed in draw(Canvas), based on the amount - // of time since the last frame drawn + // of time since the last frame drawn mCurrentDegrees += mIncrement; if (mCurrentDegrees > (360.0f - mIncrement)) { mCurrentDegrees = 0.0f; @@ -119,7 +125,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac invalidateSelf(); nextFrame(); } - + @Override public boolean setVisible(boolean visible, boolean restart) { mState.mDrawable.setVisible(visible, restart); @@ -133,8 +139,8 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac unscheduleSelf(this); } return changed; - } - + } + /** * Returns the drawable rotated by this RotateDrawable. */ @@ -148,7 +154,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac | mState.mChangingConfigurations | mState.mDrawable.getChangingConfigurations(); } - + @Override public void setAlpha(int alpha) { mState.mDrawable.setAlpha(alpha); @@ -164,11 +170,17 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac mState.mDrawable.setColorFilter(cf); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mState.mDrawable.setTint(tint, tintMode); + } + @Override public int getOpacity() { return mState.mDrawable.getOpacity(); } + @Override public void invalidateDrawable(Drawable who) { final Callback callback = getCallback(); if (callback != null) { @@ -176,6 +188,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } } + @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { final Callback callback = getCallback(); if (callback != null) { @@ -183,6 +196,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } } + @Override public void unscheduleDrawable(Drawable who, Runnable what) { final Callback callback = getCallback(); if (callback != null) { @@ -194,7 +208,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac public boolean getPadding(Rect padding) { return mState.mDrawable.getPadding(padding); } - + @Override public boolean isStateful() { return mState.mDrawable.isStateful(); @@ -205,6 +219,16 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac mState.mDrawable.setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom); } + @Override + protected boolean onLevelChange(int level) { + return mState.mDrawable.setLevel(level); + } + + @Override + protected boolean onStateChange(int[] state) { + return mState.mDrawable.setState(state); + } + @Override public int getIntrinsicWidth() { return mState.mDrawable.getIntrinsicWidth(); @@ -231,11 +255,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedRotateDrawable); super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible); - + TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX); final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION; final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); - + tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY); final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION; final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); @@ -250,7 +274,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } a.recycle(); - + int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && @@ -306,7 +330,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac Drawable mDrawable; int mChangingConfigurations; - + boolean mPivotXRel; float mPivotX; boolean mPivotYRel; @@ -315,7 +339,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac int mFramesCount; private boolean mCanConstantState; - private boolean mCheckedConstantState; + private boolean mCheckedConstantState; public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner, Resources res) { @@ -341,12 +365,12 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac public Drawable newDrawable() { return new AnimatedRotateDrawable(this, null); } - + @Override public Drawable newDrawable(Resources res) { return new AnimatedRotateDrawable(this, res); } - + @Override public int getChangingConfigurations() { return mChangingConfigurations; diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index 1ee022490e7bf..074076151d564 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -28,7 +28,6 @@ import android.os.SystemClock; import android.util.AttributeSet; /** - * * An object used to create frame-by-frame animations, defined by a series of Drawable objects, * which can be used as a View object's background. *

@@ -114,6 +113,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An * @see #isRunning() * @see #stop() */ + @Override public void start() { if (!isRunning()) { run(); @@ -127,6 +127,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An * @see #isRunning() * @see #start() */ + @Override public void stop() { if (isRunning()) { unscheduleSelf(this); @@ -138,6 +139,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An * * @return true if the animation is running, false otherwise */ + @Override public boolean isRunning() { return mAnimating; } @@ -148,6 +150,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An * * @see #start() */ + @Override public void run() { nextFrame(false); } @@ -165,41 +168,41 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An public int getNumberOfFrames() { return mAnimationState.getChildCount(); } - + /** * @return The Drawable at the specified frame index */ public Drawable getFrame(int index) { return mAnimationState.getChild(index); } - + /** - * @return The duration in milliseconds of the frame at the + * @return The duration in milliseconds of the frame at the * specified index */ public int getDuration(int i) { return mAnimationState.mDurations[i]; } - + /** * @return True of the animation will play once, false otherwise */ public boolean isOneShot() { return mAnimationState.mOneShot; } - + /** * Sets whether the animation should play once or repeat. - * + * * @param oneShot Pass true if the animation should only play once */ public void setOneShot(boolean oneShot) { mAnimationState.mOneShot = oneShot; } - + /** * Add a frame to the animation - * + * * @param frame The frame to add * @param duration How long in milliseconds the frame should appear */ @@ -209,7 +212,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An setFrame(0, true, false); } } - + private void nextFrame(boolean unschedule) { int next = mCurFrame+1; final int N = mAnimationState.getChildCount(); @@ -239,21 +242,21 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { - + TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawable); super.inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.AnimationDrawable_visible); - + mAnimationState.setVariablePadding(a.getBoolean( com.android.internal.R.styleable.AnimationDrawable_variablePadding, false)); - + mAnimationState.mOneShot = a.getBoolean( com.android.internal.R.styleable.AnimationDrawable_oneshot, false); - + a.recycle(); - + int type; final int innerDepth = parser.getDepth()+1; @@ -267,7 +270,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An if (depth > innerDepth || !parser.getName().equals("item")) { continue; } - + a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawableItem); int duration = a.getInt( com.android.internal.R.styleable.AnimationDrawableItem_duration, -1); @@ -278,9 +281,9 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An } int drawableRes = a.getResourceId( com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0); - + a.recycle(); - + Drawable dr; if (drawableRes != 0) { dr = r.getDrawable(drawableRes); @@ -295,7 +298,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An } dr = Drawable.createFromXmlInner(r, parser, attrs, theme); } - + mAnimationState.addFrame(dr, duration); if (dr != null) { dr.setCallback(this); @@ -342,7 +345,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An } public void addFrame(Drawable dr, int dur) { - // Do not combine the following. The array index must be evaluated before + // Do not combine the following. The array index must be evaluated before // the array is accessed because super.addChild(dr) has a side effect on mDurations. int pos = super.addChild(dr); mDurations[pos] = dur; diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index ef6c0859f6663..be940df215e78 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -31,6 +31,7 @@ import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuff.Mode; +import android.graphics.drawable.ColorDrawable.ColorState; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.Shader; @@ -618,9 +619,11 @@ public class BitmapDrawable extends Drawable { @Override public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) { - mBitmapState.mTint = tint; - mBitmapState.mTintMode = tintMode; - computeTintFilter(); + final BitmapState state = mBitmapState; + state.mTint = tint; + state.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); invalidateSelf(); } @@ -638,21 +641,6 @@ public class BitmapDrawable extends Drawable { return mBitmapState.mTintMode; } - private void computeTintFilter() { - final BitmapState state = mBitmapState; - if (state.mTint != null && state.mTintMode != null) { - final int color = state.mTint.getColorForState(getState(), 0); - if (mTintFilter != null) { - mTintFilter.setColor(color); - mTintFilter.setMode(state.mTintMode); - } else { - mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); - } - } else { - mTintFilter = null; - } - } - /** * @hide Candidate for future API inclusion */ @@ -679,17 +667,11 @@ public class BitmapDrawable extends Drawable { @Override protected boolean onStateChange(int[] stateSet) { - final ColorStateList tint = mBitmapState.mTint; - if (tint != null) { - final int newColor = tint.getColorForState(stateSet, 0); - final int oldColor = mTintFilter.getColor(); - if (oldColor != newColor) { - mTintFilter.setColor(newColor); - invalidateSelf(); - return true; - } + final BitmapState state = mBitmapState; + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + return true; } - return false; } @@ -946,7 +928,7 @@ public class BitmapDrawable extends Drawable { mTargetDensity = state.mTargetDensity; } - computeTintFilter(); + updateTintFilter(mTintFilter, state.mTint, state.mTintMode); computeBitmapSize(); } } diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index 3ac99727b53ee..174de3ae7c548 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -19,10 +19,12 @@ package android.graphics.drawable; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; import android.graphics.*; +import android.graphics.PorterDuff.Mode; import android.view.Gravity; import android.util.AttributeSet; @@ -52,7 +54,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { public static final int HORIZONTAL = 1; public static final int VERTICAL = 2; - + ClipDrawable() { this(null, null); } @@ -111,6 +113,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { // overrides from Drawable.Callback + @Override public void invalidateDrawable(Drawable who) { final Callback callback = getCallback(); if (callback != null) { @@ -118,6 +121,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { } } + @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { final Callback callback = getCallback(); if (callback != null) { @@ -125,6 +129,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { } } + @Override public void unscheduleDrawable(Drawable who, Runnable what) { final Callback callback = getCallback(); if (callback != null) { @@ -168,6 +173,11 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { mClipState.mDrawable.setColorFilter(cf); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mClipState.mDrawable.setTint(tint, tintMode); + } + @Override public int getOpacity() { return mClipState.mDrawable.getOpacity(); @@ -197,7 +207,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { @Override public void draw(Canvas canvas) { - + if (mClipState.mDrawable.getLevel() == 0) { return; } diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index df5ca33b91114..37161826e0edb 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -17,6 +17,8 @@ package android.graphics.drawable; import android.graphics.*; +import android.graphics.PorterDuff.Mode; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; @@ -39,9 +41,13 @@ import java.io.IOException; * @attr ref android.R.styleable#ColorDrawable_color */ public class ColorDrawable extends Drawable { + private final Paint mPaint = new Paint(); + @ViewDebug.ExportedProperty(deepExport = true, prefix = "state_") private ColorState mColorState; - private final Paint mPaint = new Paint(); + private ColorStateList mTint; + private PorterDuffColorFilter mTintFilter; + private boolean mMutated; /** @@ -84,9 +90,17 @@ public class ColorDrawable extends Drawable { @Override public void draw(Canvas canvas) { - if ((mColorState.mUseColor >>> 24) != 0) { + final ColorFilter colorFilter = mPaint.getColorFilter(); + if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) { + if (colorFilter == null) { + mPaint.setColorFilter(mTintFilter); + } + mPaint.setColor(mColorState.mUseColor); canvas.drawRect(getBounds(), mPaint); + + // Restore original color filter. + mPaint.setColorFilter(colorFilter); } } @@ -141,16 +155,51 @@ public class ColorDrawable extends Drawable { } /** - * Setting a color filter on a ColorDrawable has no effect. + * Sets the color filter applied to this color. + *

+ * Only supported on version {@link android.os.Build.VERSION_CODES#L} and + * above. Calling this method has no effect on earlier versions. * - * @param colorFilter Ignore. + * @see android.graphics.drawable.Drawable#setColorFilter(ColorFilter) */ @Override public void setColorFilter(ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + } + + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + final ColorState state = mColorState; + if (state.mTint != tint || state.mTintMode != tintMode) { + state.mTint = tint; + state.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); + invalidateSelf(); + } + } + + @Override + protected boolean onStateChange(int[] stateSet) { + final ColorState state = mColorState; + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + return true; + } + return false; + } + + @Override + public boolean isStateful() { + return mTint != null && mTint.isStateful(); } @Override public int getOpacity() { + if (mTintFilter != null || mPaint.getColorFilter() != null) { + return PixelFormat.TRANSLUCENT; + } + switch (mColorState.mUseColor >>> 24) { case 255: return PixelFormat.OPAQUE; @@ -165,8 +214,7 @@ public class ColorDrawable extends Drawable { throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); - final TypedArray a = obtainAttributes( - r, theme, attrs, R.styleable.ColorDrawable); + final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable); inflateStateFromTypedArray(a); a.recycle(); } @@ -225,21 +273,25 @@ public class ColorDrawable extends Drawable { } final static class ColorState extends ConstantState { + int[] mThemeAttrs; int mBaseColor; // base color, independent of setAlpha() @ViewDebug.ExportedProperty int mUseColor; // basecolor modulated by setAlpha() int mChangingConfigurations; - int[] mThemeAttrs; + ColorStateList mTint; + Mode mTintMode; ColorState() { // Empty constructor. } ColorState(ColorState state) { + mThemeAttrs = state.mThemeAttrs; mBaseColor = state.mBaseColor; mUseColor = state.mUseColor; mChangingConfigurations = state.mChangingConfigurations; - mThemeAttrs = state.mThemeAttrs; + mTint = state.mTint; + mTintMode = state.mTintMode; } @Override @@ -276,6 +328,6 @@ public class ColorDrawable extends Drawable { mColorState = state; } - // No local properties to initialize. + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 6a7757b912e79..cb88e3da28ad5 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -17,13 +17,6 @@ package android.graphics.drawable; import android.annotation.NonNull; -import android.graphics.Insets; -import android.graphics.Xfermode; -import android.os.Trace; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; @@ -31,15 +24,19 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; +import android.graphics.Insets; import android.graphics.NinePatch; import android.graphics.Outline; import android.graphics.PixelFormat; import android.graphics.PorterDuff; +import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.Region; -import android.graphics.PorterDuff.Mode; +import android.graphics.Xfermode; +import android.os.Trace; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.StateSet; @@ -47,6 +44,9 @@ import android.util.TypedValue; import android.util.Xml; import android.view.View; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; @@ -1225,6 +1225,26 @@ public abstract class Drawable { return new BitmapDrawable(res, bm); } + /** + * Ensures the tint filter is consistent with the current tint color and + * mode. + */ + PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint, + PorterDuff.Mode tintMode) { + if (tint == null || tintMode == null) { + return null; + } + + final int color = tint.getColorForState(getState(), Color.TRANSPARENT); + if (tintFilter == null) { + return new PorterDuffColorFilter(color, tintMode); + } + + tintFilter.setColor(color); + tintFilter.setMode(tintMode); + return tintFilter; + } + /** * Obtains styled attributes from the theme, if available, or unstyled * resources if the theme is null. diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 2aef39fc3e525..8be6eb745c09f 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -16,6 +16,7 @@ package android.graphics.drawable; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.graphics.Canvas; @@ -23,6 +24,7 @@ import android.graphics.ColorFilter; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.PorterDuff.Mode; import android.os.SystemClock; import android.util.LayoutDirection; import android.util.SparseArray; @@ -151,7 +153,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public void setColorFilter(ColorFilter cf) { - mDrawableContainerState.mHasColorFilter = true; + mDrawableContainerState.mHasColorFilter = (cf != null); if (mDrawableContainerState.mColorFilter != cf) { mDrawableContainerState.mColorFilter = cf; @@ -162,6 +164,20 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mDrawableContainerState.mHasTint = (tint != null && tintMode != null); + + if (mDrawableContainerState.mTint != tint || mDrawableContainerState.mTintMode != tintMode) { + mDrawableContainerState.mTint = tint; + mDrawableContainerState.mTintMode = tintMode; + + if (mCurrDrawable != null) { + mCurrDrawable.mutate().setTint(tint, tintMode); + } + } + } + /** * Change the global fade duration when a new drawable is entering * the scene. @@ -396,6 +412,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } if (mDrawableContainerState.mHasColorFilter) { d.setColorFilter(mDrawableContainerState.mColorFilter); + } else if (mDrawableContainerState.mHasTint) { + d.setTint(mDrawableContainerState.mTint, mDrawableContainerState.mTintMode); } d.setVisible(isVisible(), true); d.setDither(mDrawableContainerState.mDither); @@ -566,6 +584,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { ColorFilter mColorFilter; boolean mHasColorFilter; + ColorStateList mTint; + Mode mTintMode; + boolean mHasTint; + DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; @@ -588,6 +610,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mAutoMirrored = orig.mAutoMirrored; mColorFilter = orig.mColorFilter; mHasColorFilter = orig.mHasColorFilter; + mTint = orig.mTint; + mTintMode = orig.mTintMode; + mHasTint = orig.mHasTint; // Cloning the following values may require creating futures. mConstantPadding = orig.getConstantPadding(); @@ -741,7 +766,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { final int N = mNumChildren; final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { - final Drawable d = drawables[i]; + final Drawable d = drawables[i]; if (d != null) { if (d.canApplyTheme()) { return true; diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 9e0ab86e18c5c..220e81c5c7d1b 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -19,10 +19,12 @@ package android.graphics.drawable; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; import android.graphics.*; +import android.graphics.PorterDuff.Mode; import android.util.AttributeSet; import android.util.Log; @@ -44,8 +46,7 @@ import java.io.IOException; * @attr ref android.R.styleable#InsetDrawable_insetTop * @attr ref android.R.styleable#InsetDrawable_insetBottom */ -public class InsetDrawable extends Drawable implements Drawable.Callback -{ +public class InsetDrawable extends Drawable implements Drawable.Callback { // Most of this is copied from ScaleDrawable. private InsetState mInsetState; private final Rect mTmpRect = new Rect(); @@ -62,13 +63,13 @@ public class InsetDrawable extends Drawable implements Drawable.Callback public InsetDrawable(Drawable drawable, int insetLeft, int insetTop, int insetRight, int insetBottom) { this(null, null); - + mInsetState.mDrawable = drawable; mInsetState.mInsetLeft = insetLeft; mInsetState.mInsetTop = insetTop; mInsetState.mInsetRight = insetRight; mInsetState.mInsetBottom = insetBottom; - + if (drawable != null) { drawable.setCallback(this); } @@ -78,7 +79,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { int type; - + TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.InsetDrawable); @@ -168,7 +169,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback | mInsetState.mChangingConfigurations | mInsetState.mDrawable.getChangingConfigurations(); } - + @Override public boolean getPadding(Rect padding) { boolean pad = mInsetState.mDrawable.getPadding(padding); @@ -178,7 +179,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback padding.top += mInsetState.mInsetTop; padding.bottom += mInsetState.mInsetBottom; - if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight | + if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight | mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) { return true; } else { @@ -217,6 +218,11 @@ public class InsetDrawable extends Drawable implements Drawable.Callback mInsetState.mDrawable.setColorFilter(cf); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mInsetState.mDrawable.setTint(tint, tintMode); + } + /** {@hide} */ @Override public void setLayoutDirection(int layoutDirection) { @@ -227,7 +233,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback public int getOpacity() { return mInsetState.mDrawable.getOpacity(); } - + @Override public boolean isStateful() { return mInsetState.mDrawable.isStateful(); @@ -239,7 +245,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback onBoundsChange(getBounds()); return changed; } - + + @Override + protected boolean onLevelChange(int level) { + return mInsetState.mDrawable.setLevel(level); + } + @Override protected void onBoundsChange(Rect bounds) { final Rect r = mTmpRect; @@ -321,12 +332,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback public Drawable newDrawable() { return new InsetDrawable(this, null); } - + @Override public Drawable newDrawable(Resources res) { return new InsetDrawable(this, res); } - + @Override public int getChangingConfigurations() { return mChangingConfigurations; diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 27f0a9d7c80c2..5cea7c9263041 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -16,12 +16,14 @@ package android.graphics.drawable; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; +import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; @@ -630,6 +632,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + final ChildDrawable[] array = mLayerState.mChildren; + final int N = mLayerState.mNum; + for (int i = 0; i < N; i++) { + array[i].mDrawable.setTint(tint, tintMode); + } + } + /** * Sets the opacity of this drawable directly, instead of collecting the * states from the layers diff --git a/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java index 9e56f67f4b23f..c484094f0ff57 100644 --- a/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java +++ b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java @@ -27,8 +27,10 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; +import android.graphics.PorterDuffColorFilter; import android.graphics.Paint.Cap; import android.graphics.Paint.Style; +import android.graphics.PorterDuff.Mode; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; @@ -67,6 +69,7 @@ class MaterialProgressDrawable extends Drawable implements Animatable { private final Ring mRing; private MaterialProgressState mState; + private PorterDuffColorFilter mTintFilter; /** Canvas rotation in degrees. */ private float mRotation; @@ -106,6 +109,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable { float insets = minEdge / 2.0f - state.mInnerRadius; ring.setInsets(insets); } + + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } @Override @@ -118,15 +123,21 @@ class MaterialProgressDrawable extends Drawable implements Animatable { } @Override - protected boolean onStateChange(int[] state) { - boolean changed = super.onStateChange(state); + protected boolean onStateChange(int[] stateSet) { + boolean changed = super.onStateChange(stateSet); - final int color = mState.mColor.getColorForState(state, Color.TRANSPARENT); + final MaterialProgressState state = mState; + final int color = state.mColor.getColorForState(stateSet, Color.TRANSPARENT); if (color != mRing.getColor()) { mRing.setColor(color); changed = true; } + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + changed = true; + } + return changed; } @@ -223,11 +234,24 @@ class MaterialProgressDrawable extends Drawable implements Animatable { return mRing.getColorFilter(); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + if (mState.mTint != tint || mState.mTintMode != tintMode) { + mState.mTint = tint; + mState.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); + invalidateSelf(); + } + } + + @SuppressWarnings("unused") private void setRotation(float rotation) { mRotation = rotation; invalidateSelf(); } + @SuppressWarnings("unused") private float getRotation() { return mRotation; } @@ -331,6 +355,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable { private int mWidth = -1; private int mHeight = -1; private ColorStateList mColor = ColorStateList.valueOf(Color.TRANSPARENT); + private ColorStateList mTint = null; + private Mode mTintMode = null; public MaterialProgressState(MaterialProgressState orig) { if (orig != null) { @@ -340,6 +366,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable { mWidth = orig.mWidth; mHeight = orig.mHeight; mColor = orig.mColor; + mTint = orig.mTint; + mTintMode = orig.mTintMode; } } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index fea68ee1a4db8..36ffdddf5bdc1 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -327,25 +327,12 @@ public class NinePatchDrawable extends Drawable { @Override public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) { - mNinePatchState.mTint = tint; - mNinePatchState.mTintMode = tintMode; - computeTintFilter(); - invalidateSelf(); - } - - private void computeTintFilter() { final NinePatchState state = mNinePatchState; - if (state.mTint != null && state.mTintMode != null) { - final int color = state.mTint.getColorForState(getState(), 0); - if (mTintFilter != null) { - mTintFilter.setColor(color); - mTintFilter.setMode(state.mTintMode); - } else { - mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); - } - } else { - mTintFilter = null; - } + state.mTint = tint; + state.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); + invalidateSelf(); } @Override @@ -549,15 +536,10 @@ public class NinePatchDrawable extends Drawable { @Override protected boolean onStateChange(int[] stateSet) { - final ColorStateList tint = mNinePatchState.mTint; - if (tint != null) { - final int newColor = tint.getColorForState(stateSet, 0); - final int oldColor = mTintFilter.getColor(); - if (oldColor != newColor) { - mTintFilter.setColor(newColor); - invalidateSelf(); - return true; - } + final NinePatchState state = mNinePatchState; + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + return true; } return false; @@ -689,7 +671,7 @@ public class NinePatchDrawable extends Drawable { mPadding = new Rect(state.mPadding); } - computeTintFilter(); + updateTintFilter(mTintFilter, state.mTint, state.mTintMode); setNinePatch(state.mNinePatch); } } diff --git a/graphics/java/android/graphics/drawable/PaintDrawable.java b/graphics/java/android/graphics/drawable/PaintDrawable.java index c71cda1697372..a82e7b950edf2 100644 --- a/graphics/java/android/graphics/drawable/PaintDrawable.java +++ b/graphics/java/android/graphics/drawable/PaintDrawable.java @@ -35,7 +35,7 @@ public class PaintDrawable extends ShapeDrawable { public PaintDrawable(int color) { getPaint().setColor(color); } - + /** * Specify radius for the corners of the rectangle. If this is > 0, then the * drawable is drawn in a round-rectangle, rather than a rectangle. @@ -51,7 +51,7 @@ public class PaintDrawable extends ShapeDrawable { } setCornerRadii(radii); } - + /** * Specify radii for each of the 4 corners. For each corner, the array * contains 2 values, [X_radius, Y_radius]. The corners are ordered @@ -78,9 +78,9 @@ public class PaintDrawable extends ShapeDrawable { int radius = a.getDimensionPixelSize( com.android.internal.R.styleable.DrawableCorners_radius, 0); setCornerRadius(radius); - + // now check of they have any per-corner radii - + int topLeftRadius = a.getDimensionPixelSize( com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius); int topRightRadius = a.getDimensionPixelSize( diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java index cb2d8f67a4baa..6dcda1f565908 100644 --- a/graphics/java/android/graphics/drawable/PictureDrawable.java +++ b/graphics/java/android/graphics/drawable/PictureDrawable.java @@ -25,7 +25,7 @@ import android.graphics.Rect; /** * Drawable subclass that wraps a Picture, allowing the picture to be used - * whereever a Drawable is supported. + * wherever a Drawable is supported. */ public class PictureDrawable extends Drawable { @@ -40,7 +40,7 @@ public class PictureDrawable extends Drawable { public PictureDrawable(Picture picture) { mPicture = picture; } - + /** * Return the picture associated with the drawable. May be null. * @@ -49,7 +49,7 @@ public class PictureDrawable extends Drawable { public Picture getPicture() { return mPicture; } - + /** * Associate a picture with this drawable. The picture may be null. * @@ -58,7 +58,7 @@ public class PictureDrawable extends Drawable { public void setPicture(Picture picture) { mPicture = picture; } - + @Override public void draw(Canvas canvas) { if (mPicture != null) { @@ -86,16 +86,16 @@ public class PictureDrawable extends Drawable { // not sure, so be safe return PixelFormat.TRANSLUCENT; } - + @Override public void setFilterBitmap(boolean filter) {} - + @Override public void setDither(boolean dither) {} - + @Override public void setColorFilter(ColorFilter colorFilter) {} - + @Override public void setAlpha(int alpha) {} } diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index 06aeb983b2e31..8f8fa98c8acda 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -22,6 +22,8 @@ import org.xmlpull.v1.XmlPullParserException; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Rect; +import android.graphics.PorterDuff.Mode; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; @@ -136,6 +138,11 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { mState.mDrawable.setColorFilter(cf); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mState.mDrawable.setTint(tint, tintMode); + } + @Override public int getOpacity() { return mState.mDrawable.getOpacity(); diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index f090c11bd13e2..46c92fe82dfb0 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -19,10 +19,12 @@ package android.graphics.drawable; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; import android.graphics.*; +import android.graphics.PorterDuff.Mode; import android.view.Gravity; import android.util.AttributeSet; @@ -187,6 +189,11 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { mScaleState.mDrawable.setColorFilter(cf); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mScaleState.mDrawable.setTint(tint, tintMode); + } + @Override public int getOpacity() { return mScaleState.mDrawable.getOpacity(); diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index 024f77cf2e7fc..a2aef215c2a38 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -91,10 +91,7 @@ public class ShapeDrawable extends Drawable { private ShapeDrawable(ShapeState state) { mShapeState = new ShapeState(state); - if (state != null && state.mTint != null) { - final int color = state.mTint.getColorForState(getState(), 0); - mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); - } + updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } /** diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index b2fac9bef74c5..f359fdd0b475b 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -235,10 +235,10 @@ public class StateListDrawable extends DrawableContainer { public Drawable getStateDrawable(int index) { return mStateListState.getChild(index); } - + /** * Gets the index of the drawable with the provided state set. - * + * * @param stateSet the state set to look up * @return the index of the provided state set, or -1 if not found * @hide pending API council @@ -248,7 +248,7 @@ public class StateListDrawable extends DrawableContainer { public int getStateDrawableIndex(int[] stateSet) { return mStateListState.indexOfStateSet(stateSet); } - + @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java index 622e90ba4c04b..4380ca4e8145f 100644 --- a/graphics/java/android/graphics/drawable/TransitionDrawable.java +++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java @@ -42,20 +42,20 @@ import android.os.SystemClock; public class TransitionDrawable extends LayerDrawable implements Drawable.Callback { /** - * A transition is about to start. + * A transition is about to start. */ private static final int TRANSITION_STARTING = 0; - + /** * The transition has started and the animation is in progress */ private static final int TRANSITION_RUNNING = 1; - + /** * No transition will be applied */ private static final int TRANSITION_NONE = 2; - + /** * The current state of the transition. One of {@link #TRANSITION_STARTING}, * {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE} @@ -101,10 +101,10 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba LayerState createConstantState(LayerState state, Resources res) { return new TransitionState((TransitionState) state, this, res); } - + /** * Begin the second layer on top of the first layer. - * + * * @param durationMillis The length of the transition in milliseconds */ public void startTransition(int durationMillis) { @@ -116,7 +116,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba mTransitionState = TRANSITION_STARTING; invalidateSelf(); } - + /** * Show only the first layer. */ @@ -184,7 +184,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba } break; } - + final int alpha = mAlpha; final boolean crossFade = mCrossFade; final ChildDrawable[] array = mLayerState.mChildren; @@ -217,7 +217,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba d.draw(canvas); d.setAlpha(0xFF); } - + if (!done) { invalidateSelf(); } diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index c531c224e2e68..c3c1bcabad4e1 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -14,6 +14,7 @@ package android.graphics.drawable; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; @@ -25,8 +26,10 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.PixelFormat; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.Region; +import android.graphics.PorterDuff.Mode; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.Log; @@ -137,6 +140,8 @@ public class VectorDrawable extends Drawable { private final ArrayMap mVGTargetsMap = new ArrayMap(); + private PorterDuffColorFilter mTintFilter; + public VectorDrawable() { mVectorState = new VectorDrawableState(null); } @@ -147,6 +152,9 @@ public class VectorDrawable extends Drawable { if (theme != null && canApplyTheme()) { applyTheme(theme); } + + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + mVectorState.mVPathRenderer.setColorFilter(mTintFilter); } Object getTargetByName(String name) { @@ -182,10 +190,45 @@ public class VectorDrawable extends Drawable { @Override public void setColorFilter(ColorFilter colorFilter) { - mVectorState.mVPathRenderer.setColorFilter(colorFilter); + final VectorDrawableState state = mVectorState; + if (colorFilter != null) { + // Color filter overrides tint. + mTintFilter = null; + } else if (state.mTint != null && state.mTintMode != null) { + // Restore the tint filter, if we need one. + final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT); + mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); + colorFilter = mTintFilter; + } + + state.mVPathRenderer.setColorFilter(colorFilter); invalidateSelf(); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + final VectorDrawableState state = mVectorState; + if (state.mTint != tint || state.mTintMode != tintMode) { + state.mTint = tint; + state.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); + mVectorState.mVPathRenderer.setColorFilter(mTintFilter); + invalidateSelf(); + } + } + + @Override + protected boolean onStateChange(int[] stateSet) { + final VectorDrawableState state = mVectorState; + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + mVectorState.mVPathRenderer.setColorFilter(mTintFilter); + return true; + } + return false; + } + @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; @@ -397,6 +440,8 @@ public class VectorDrawable extends Drawable { int mChangingConfigurations; VPathRenderer mVPathRenderer; Rect mPadding; + ColorStateList mTint; + Mode mTintMode; public VectorDrawableState(VectorDrawableState copy) { if (copy != null) { @@ -404,6 +449,8 @@ public class VectorDrawable extends Drawable { // TODO: Make sure the constant state are handled correctly. mVPathRenderer = new VPathRenderer(copy.mVPathRenderer); mPadding = new Rect(copy.mPadding); + mTint = copy.mTint; + mTintMode = copy.mTintMode; } }