summaryrefslogtreecommitdiffstats
path: root/core/java/android/widget
diff options
context:
space:
mode:
authorAlan Viverette <alanv@google.com>2014-06-17 14:51:45 -0700
committerAlan Viverette <alanv@google.com>2014-06-17 14:51:45 -0700
commit911743652b597057a1bd7ef8a921e9ff8dce0f4a (patch)
tree8657a361d0a6c309dcab5c71a548a7f7c4443c4f /core/java/android/widget
parent96401d99959afc2034a6b43580a93dae94da684a (diff)
downloadframeworks_base-911743652b597057a1bd7ef8a921e9ff8dce0f4a.zip
frameworks_base-911743652b597057a1bd7ef8a921e9ff8dce0f4a.tar.gz
frameworks_base-911743652b597057a1bd7ef8a921e9ff8dce0f4a.tar.bz2
Add attributes and accessors for tinting View drawables
Also cleans up handling in setters for managed drawables. BUG: 15391544 Change-Id: Idc08f7eaea0050feb6403566985a6d58185b81f8
Diffstat (limited to 'core/java/android/widget')
-rw-r--r--core/java/android/widget/AbsSeekBar.java108
-rw-r--r--core/java/android/widget/CompoundButton.java135
-rw-r--r--core/java/android/widget/FrameLayout.java121
-rw-r--r--core/java/android/widget/ImageView.java122
-rw-r--r--core/java/android/widget/ProgressBar.java553
5 files changed, 970 insertions, 69 deletions
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 08931fe..eb3f882 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -16,11 +16,15 @@
package android.widget;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Insets;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -31,10 +35,16 @@ import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
public abstract class AbsSeekBar extends ProgressBar {
private final Rect mTempRect = new Rect();
private Drawable mThumb;
+ private ColorStateList mThumbTint = null;
+ private PorterDuff.Mode mThumbTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasThumbTint = false;
+
private int mThumbOffset;
private boolean mSplitTrack;
@@ -83,6 +93,15 @@ public abstract class AbsSeekBar extends ProgressBar {
final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
setThumb(thumb);
+ if (a.hasValue(R.styleable.SeekBar_thumbTint)) {
+ mThumbTint = a.getColorStateList(R.styleable.SeekBar_thumbTint);
+ mThumbTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.SeekBar_thumbTintMode, -1), mThumbTintMode);
+ mHasThumbTint = true;
+
+ applyThumbTint();
+ }
+
// Guess thumb offset if thumb != null, but allow layout to override.
final int thumbOffset = a.getDimensionPixelOffset(
com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
@@ -108,7 +127,7 @@ public abstract class AbsSeekBar extends ProgressBar {
* @param thumb Drawable representing the thumb
*/
public void setThumb(Drawable thumb) {
- boolean needUpdate;
+ final boolean needUpdate;
// This way, calling setThumb again with the same bitmap will result in
// it recalcuating mThumbOffset (if for example it the bounds of the
// drawable changed)
@@ -118,6 +137,7 @@ public abstract class AbsSeekBar extends ProgressBar {
} else {
needUpdate = false;
}
+
if (thumb != null) {
thumb.setCallback(this);
if (canResolveLayoutDirection()) {
@@ -136,8 +156,12 @@ public abstract class AbsSeekBar extends ProgressBar {
requestLayout();
}
}
+
mThumb = thumb;
+
+ applyThumbTint();
invalidate();
+
if (needUpdate) {
updateThumbAndTrackPos(getWidth(), getHeight());
if (thumb != null && thumb.isStateful()) {
@@ -160,6 +184,88 @@ public abstract class AbsSeekBar extends ProgressBar {
}
/**
+ * Applies a tint to the thumb drawable.
+ * <p>
+ * Subsequent calls to {@link #setThumb(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setThumbTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mThumbTint = tint;
+ mThumbTintMode = tintMode;
+ mHasThumbTint = true;
+
+ applyThumbTint();
+ }
+
+ /**
+ * Applies a tint to the thumb drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setThumb(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setThumbTint(@Nullable ColorStateList tint) {
+ setThumbTint(tint, mThumbTintMode);
+ }
+
+ /**
+ * @return the tint applied to the thumb drawable
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getThumbTint() {
+ return mThumbTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setThumbTint(ColorStateList)}} to the thumb drawable. The
+ * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see #setThumbTint(ColorStateList)
+ */
+ public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setThumbTint(mThumbTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the thumb drawable
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getThumbTintMode() {
+ return mThumbTintMode;
+ }
+
+ private void applyThumbTint() {
+ if (mThumb != null && mHasThumbTint) {
+ mThumb = mThumb.mutate();
+ mThumb.setTint(mThumbTint, mThumbTintMode);
+ }
+ }
+
+ /**
* @see #setThumbOffset(int)
*/
public int getThumbOffset() {
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index c934ad7..747d2b1 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -16,11 +16,15 @@
package android.widget;
+import android.annotation.Nullable;
+import android.graphics.PorterDuff;
import com.android.internal.R;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -48,7 +52,12 @@ public abstract class CompoundButton extends Button implements Checkable {
private boolean mChecked;
private int mButtonResource;
private boolean mBroadcasting;
+
private Drawable mButtonDrawable;
+ private ColorStateList mButtonTint = null;
+ private PorterDuff.Mode mButtonTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasButtonTint = false;
+
private OnCheckedChangeListener mOnCheckedChangeListener;
private OnCheckedChangeListener mOnCheckedChangeWidgetListener;
@@ -74,13 +83,22 @@ public abstract class CompoundButton extends Button implements Checkable {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes);
- Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
+ final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
if (d != null) {
setButtonDrawable(d);
}
- boolean checked = a
- .getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);
+ if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
+ mButtonTint = a.getColorStateList(R.styleable.CompoundButton_buttonTint);
+ mButtonTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.CompoundButton_buttonTintMode, -1), mButtonTintMode);
+ mHasButtonTint = true;
+
+ applyButtonTint();
+ }
+
+ final boolean checked = a.getBoolean(
+ com.android.internal.R.styleable.CompoundButton_checked, false);
setChecked(checked);
a.recycle();
@@ -173,9 +191,11 @@ public abstract class CompoundButton extends Button implements Checkable {
}
/**
- * Set the background to a given Drawable, identified by its resource id.
+ * Set the button graphic to a given Drawable, identified by its resource
+ * id.
*
- * @param resid the resource id of the drawable to use as the background
+ * @param resid the resource id of the drawable to use as the button
+ * graphic
*/
public void setButtonDrawable(int resid) {
if (resid != 0 && resid == mButtonResource) {
@@ -192,23 +212,114 @@ public abstract class CompoundButton extends Button implements Checkable {
}
/**
- * Set the background to a given Drawable
+ * Set the button graphic to a given Drawable
*
- * @param d The Drawable to use as the background
+ * @param d The Drawable to use as the button graphic
*/
public void setButtonDrawable(Drawable d) {
- if (d != null) {
+ if (mButtonDrawable != d) {
if (mButtonDrawable != null) {
mButtonDrawable.setCallback(null);
unscheduleDrawable(mButtonDrawable);
}
- d.setCallback(this);
- d.setVisible(getVisibility() == VISIBLE, false);
+
mButtonDrawable = d;
- setMinHeight(mButtonDrawable.getIntrinsicHeight());
+
+ if (d != null) {
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ d.setVisible(getVisibility() == VISIBLE, false);
+ setMinHeight(d.getIntrinsicHeight());
+ applyButtonTint();
+ }
}
+ }
- refreshDrawableState();
+ /**
+ * Applies a tint to the button drawable.
+ * <p>
+ * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setButtonTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mButtonTint = tint;
+ mButtonTintMode = tintMode;
+ mHasButtonTint = true;
+
+ applyButtonTint();
+ }
+
+ /**
+ * Applies a tint to the button drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @see #setButtonTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ public void setButtonTint(@Nullable ColorStateList tint) {
+ setButtonTint(tint, mButtonTintMode);
+ }
+
+ /**
+ * @return the tint applied to the button drawable
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @see #setButtonTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getButtonTint() {
+ return mButtonTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setButtonTint(ColorStateList)}} to the button drawable. The
+ * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see #setButtonTint(ColorStateList)
+ */
+ public void setButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setButtonTint(mButtonTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the button drawable
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see #setButtonTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getButtonTintMode() {
+ return mButtonTintMode;
+ }
+
+ private void applyButtonTint() {
+ if (mButtonDrawable != null && mHasButtonTint) {
+ mButtonDrawable = mButtonDrawable.mutate();
+ mButtonDrawable.setTint(mButtonTint, mButtonTintMode);
+ }
}
@Override
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 01a6b8a..5a14929 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -18,11 +18,15 @@ package android.widget;
import java.util.ArrayList;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -33,6 +37,8 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
/**
* FrameLayout is designed to block out an area on the screen to display
@@ -62,6 +68,9 @@ public class FrameLayout extends ViewGroup {
@ViewDebug.ExportedProperty(category = "drawing")
private Drawable mForeground;
+ private ColorStateList mForegroundTint = null;
+ private PorterDuff.Mode mForegroundTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasForegroundTint = false;
@ViewDebug.ExportedProperty(category = "padding")
private int mForegroundPaddingLeft = 0;
@@ -119,6 +128,15 @@ public class FrameLayout extends ViewGroup {
setMeasureAllChildren(true);
}
+ if (a.hasValue(R.styleable.FrameLayout_foregroundTint)) {
+ mForegroundTint = a.getColorStateList(R.styleable.FrameLayout_foregroundTint);
+ mForegroundTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.FrameLayout_foregroundTintMode, -1), mForegroundTintMode);
+ mHasForegroundTint = true;
+
+ applyForegroundTint();
+ }
+
mForegroundInPadding = a.getBoolean(
com.android.internal.R.styleable.FrameLayout_foregroundInsidePadding, true);
@@ -231,32 +249,34 @@ public class FrameLayout extends ViewGroup {
* into account by ensuring that the children are inset to be placed
* inside of the padding area.
*
- * @param drawable The Drawable to be drawn on top of the children.
+ * @param d The Drawable to be drawn on top of the children.
*
* @attr ref android.R.styleable#FrameLayout_foreground
*/
- public void setForeground(Drawable drawable) {
- if (mForeground != drawable) {
+ public void setForeground(Drawable d) {
+ if (mForeground != d) {
if (mForeground != null) {
mForeground.setCallback(null);
unscheduleDrawable(mForeground);
}
- mForeground = drawable;
+ mForeground = d;
mForegroundPaddingLeft = 0;
mForegroundPaddingTop = 0;
mForegroundPaddingRight = 0;
mForegroundPaddingBottom = 0;
- if (drawable != null) {
+ if (d != null) {
setWillNotDraw(false);
- drawable.setCallback(this);
- if (drawable.isStateful()) {
- drawable.setState(getDrawableState());
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
}
+ applyForegroundTint();
if (mForegroundGravity == Gravity.FILL) {
Rect padding = new Rect();
- if (drawable.getPadding(padding)) {
+ if (d.getPadding(padding)) {
mForegroundPaddingLeft = padding.left;
mForegroundPaddingTop = padding.top;
mForegroundPaddingRight = padding.right;
@@ -281,6 +301,89 @@ public class FrameLayout extends ViewGroup {
return mForeground;
}
+ /**
+ * Applies a tint to the foreground drawable.
+ * <p>
+ * Subsequent calls to {@link #setForeground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setForegroundTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mForegroundTint = tint;
+ mForegroundTintMode = tintMode;
+ mHasForegroundTint = true;
+
+ applyForegroundTint();
+ }
+
+ /**
+ * Applies a tint to the foreground drawable. Does not modify the current
+ * tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setForeground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setForegroundTint(@Nullable ColorStateList tint) {
+ setForegroundTint(tint, mForegroundTintMode);
+ }
+
+ /**
+ * @return the tint applied to the foreground drawable
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getForegroundTint() {
+ return mForegroundTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setForegroundTint(ColorStateList)}} to the foreground drawable.
+ * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+ * @see #setForegroundTint(ColorStateList)
+ */
+ public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setForegroundTint(mForegroundTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the foreground
+ * drawable
+ * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getForegroundTintMode() {
+ return mForegroundTintMode;
+ }
+
+ private void applyForegroundTint() {
+ if (mForeground != null && mHasForegroundTint) {
+ mForeground = mForeground.mutate();
+ mForeground.setTint(mForegroundTint, mForegroundTintMode);
+ }
+ }
+
int getPaddingLeftWithForeground() {
return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
mPaddingLeft + mForegroundPaddingLeft;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index a40b85e..399e087 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -16,8 +16,10 @@
package android.widget;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -30,6 +32,7 @@ import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Xfermode;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -44,6 +47,8 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
import java.io.IOException;
import java.io.InputStream;
@@ -75,13 +80,18 @@ public class ImageView extends View {
private int mMaxHeight = Integer.MAX_VALUE;
// these are applied to the drawable
- private ColorFilter mColorFilter;
+ private ColorFilter mColorFilter = null;
+ private boolean mHasColorFilter = false;
private Xfermode mXfermode;
private int mAlpha = 255;
private int mViewAlphaScale = 256;
private boolean mColorMod = false;
private Drawable mDrawable = null;
+ private ColorStateList mDrawableTint = null;
+ private PorterDuff.Mode mDrawableTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasDrawableTint = false;
+
private int[] mState = null;
private boolean mMergeState = false;
private int mLevel = 0;
@@ -154,17 +164,21 @@ public class ImageView extends View {
setMaxHeight(a.getDimensionPixelSize(
com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
- int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
+ final int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
if (index >= 0) {
setScaleType(sScaleTypeArray[index]);
}
- int tint = a.getInt(com.android.internal.R.styleable.ImageView_tint, 0);
- if (tint != 0) {
- setColorFilter(tint);
+ if (a.hasValue(R.styleable.ImageView_tint)) {
+ mDrawableTint = a.getColorStateList(R.styleable.ImageView_tint);
+ mDrawableTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ImageView_tintMode, -1), mDrawableTintMode);
+ mHasDrawableTint = true;
+
+ applyDrawableTint();
}
-
- int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
+
+ final int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
if (alpha != 255) {
setAlpha(alpha);
}
@@ -435,6 +449,88 @@ public class ImageView extends View {
}
/**
+ * Applies a tint to the image drawable.
+ * <p>
+ * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ImageView_tint
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mDrawableTint = tint;
+ mDrawableTintMode = tintMode;
+ mHasDrawableTint = true;
+
+ applyDrawableTint();
+ }
+
+ /**
+ * Applies a tint to the image drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ImageView_tint
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setTint(@Nullable ColorStateList tint) {
+ setTint(tint, mDrawableTintMode);
+ }
+
+ /**
+ * @return the tint applied to the image drawable
+ * @attr ref android.R.styleable#ImageView_tint
+ * @see #setTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getTint() {
+ return mDrawableTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setTint(ColorStateList)}} to the image drawable. The default
+ * mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see #setTint(ColorStateList)
+ */
+ public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setTint(mDrawableTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the image drawable
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see #setTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getTintMode() {
+ return mDrawableTintMode;
+ }
+
+ private void applyDrawableTint() {
+ if (mDrawable != null && mHasDrawableTint) {
+ mDrawable = mDrawable.mutate();
+ mDrawable.setTint(mDrawableTint, mDrawableTintMode);
+ }
+ }
+
+ /**
* Sets a Bitmap as the content of this ImageView.
*
* @param bm The bitmap to set
@@ -709,17 +805,20 @@ public class ImageView extends View {
mDrawable.setCallback(null);
unscheduleDrawable(mDrawable);
}
+
mDrawable = d;
+
if (d != null) {
d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
if (d.isStateful()) {
d.setState(getDrawableState());
}
- d.setLevel(mLevel);
- d.setLayoutDirection(getLayoutDirection());
d.setVisible(getVisibility() == VISIBLE, true);
+ d.setLevel(mLevel);
mDrawableWidth = d.getIntrinsicWidth();
mDrawableHeight = d.getIntrinsicHeight();
+ applyDrawableTint();
applyColorMod();
configureBounds();
} else {
@@ -1177,6 +1276,7 @@ public class ImageView extends View {
public void setColorFilter(ColorFilter cf) {
if (mColorFilter != cf) {
mColorFilter = cf;
+ mHasColorFilter = true;
mColorMod = true;
applyColorMod();
invalidate();
@@ -1231,7 +1331,9 @@ public class ImageView extends View {
// re-applied if the Drawable is changed.
if (mDrawable != null && mColorMod) {
mDrawable = mDrawable.mutate();
- mDrawable.setColorFilter(mColorFilter);
+ if (mHasColorFilter) {
+ mDrawable.setColorFilter(mColorFilter);
+ }
mDrawable.setXfermode(mXfermode);
mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
}
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index af32f1c..62a8bec 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -16,13 +16,17 @@
package android.widget;
+import android.annotation.Nullable;
+import android.graphics.PorterDuff;
import com.android.internal.R;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Animatable;
@@ -210,8 +214,26 @@ public class ProgressBar extends View {
private Transformation mTransformation;
private AlphaAnimation mAnimation;
private boolean mHasAnimation;
+
private Drawable mIndeterminateDrawable;
+ private ColorStateList mIndeterminateTint = null;
+ private PorterDuff.Mode mIndeterminateTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasIndeterminateTint = false;
+
private Drawable mProgressDrawable;
+
+ private ColorStateList mProgressTint = null;
+ private PorterDuff.Mode mProgressTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasProgressTint = false;
+
+ private ColorStateList mProgressBackgroundTint = null;
+ private PorterDuff.Mode mProgressBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasProgressBackgroundTint = false;
+
+ private ColorStateList mSecondaryProgressTint = null;
+ private PorterDuff.Mode mSecondaryProgressTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasSecondaryProgressTint = false;
+
private Drawable mCurrentDrawable;
Bitmap mSampleTile;
private boolean mNoInvalidate;
@@ -257,11 +279,11 @@ public class ProgressBar extends View {
mNoInvalidate = true;
- Drawable drawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
- if (drawable != null) {
+ final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
+ if (progressDrawable != null) {
// Calling this method can set mMaxHeight, make sure the corresponding
// XML attribute for mMaxHeight is read after calling this method
- setProgressDrawableTiled(drawable);
+ setProgressDrawableTiled(progressDrawable);
}
@@ -288,9 +310,10 @@ public class ProgressBar extends View {
setSecondaryProgress(
a.getInt(R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
- drawable = a.getDrawable(R.styleable.ProgressBar_indeterminateDrawable);
- if (drawable != null) {
- setIndeterminateDrawableTiled(drawable);
+ final Drawable indeterminateDrawable = a.getDrawable(
+ R.styleable.ProgressBar_indeterminateDrawable);
+ if (indeterminateDrawable != null) {
+ setIndeterminateDrawableTiled(indeterminateDrawable);
}
mOnlyIndeterminate = a.getBoolean(
@@ -303,6 +326,53 @@ public class ProgressBar extends View {
mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);
+ if (a.hasValue(R.styleable.ProgressBar_progressTint)) {
+ mProgressTint = a.getColorStateList(
+ R.styleable.ProgressBar_progressTint);
+ mProgressTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_progressBackgroundTintMode, -1),
+ mProgressTintMode);
+ mHasProgressTint = true;
+
+ applyProgressLayerTint(R.id.progress, mProgressTint,
+ mProgressTintMode, true);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTint)) {
+ mProgressBackgroundTint = a.getColorStateList(
+ R.styleable.ProgressBar_progressBackgroundTint);
+ mProgressBackgroundTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_progressTintMode, -1),
+ mProgressBackgroundTintMode);
+ mHasProgressBackgroundTint = true;
+
+ applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+ mProgressBackgroundTintMode, false);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTint)) {
+ mSecondaryProgressTint = a.getColorStateList(
+ R.styleable.ProgressBar_secondaryProgressTint);
+ mSecondaryProgressTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_secondaryProgressTintMode, -1),
+ mSecondaryProgressTintMode);
+ mHasSecondaryProgressTint = true;
+
+ applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+ mSecondaryProgressTintMode, false);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
+ mIndeterminateTint = a.getColorStateList(
+ R.styleable.ProgressBar_indeterminateTint);
+ mIndeterminateTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_indeterminateTintMode, -1),
+ mIndeterminateTintMode);
+ mHasIndeterminateTint = true;
+
+ applyIndeterminateTint();
+ }
+
a.recycle();
// If not explicitly specified this view is important for accessibility.
@@ -479,16 +549,111 @@ public class ProgressBar extends View {
* @see #setIndeterminate(boolean)
*/
public void setIndeterminateDrawable(Drawable d) {
- if (d != null) {
- d.setCallback(this);
- }
- mIndeterminateDrawable = d;
- if (mIndeterminateDrawable != null && canResolveLayoutDirection()) {
- mIndeterminateDrawable.setLayoutDirection(getLayoutDirection());
+ if (mIndeterminateDrawable != d) {
+ if (mIndeterminateDrawable != null) {
+ mIndeterminateDrawable.setCallback(null);
+ unscheduleDrawable(mIndeterminateDrawable);
+ }
+
+ mIndeterminateDrawable = d;
+
+ if (d != null) {
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ applyIndeterminateTint();
+ }
+
+ if (mIndeterminate) {
+ mCurrentDrawable = d;
+ postInvalidate();
+ }
}
- if (mIndeterminate) {
- mCurrentDrawable = d;
- postInvalidate();
+ }
+
+ /**
+ * Applies a tint to the indeterminate drawable.
+ * <p>
+ * Subsequent calls to {@link #setVisibilminateDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setIndeterminateTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mIndeterminateTint = tint;
+ mIndeterminateTintMode = tintMode;
+ mHasIndeterminateTint = true;
+
+ applyIndeterminateTint();
+ }
+
+ /**
+ * Applies a tint to the indeterminate drawable. Does not modify the
+ * current tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setIndeterminateTint(@Nullable ColorStateList tint) {
+ setIndeterminateTint(tint, mIndeterminateTintMode);
+ }
+
+ /**
+ * @return the tint applied to the indeterminate drawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getIndeterminateTint() {
+ return mIndeterminateTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setIndeterminateTint(ColorStateList)} to the indeterminate
+ * drawable. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see #setIndeterminateTint(ColorStateList)
+ */
+ public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setIndeterminateTint(mIndeterminateTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the indeterminate drawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getIndeterminateTintMode() {
+ return mIndeterminateTintMode;
+ }
+
+ private void applyIndeterminateTint() {
+ if (mIndeterminateDrawable != null && mHasIndeterminateTint) {
+ mIndeterminateDrawable = mIndeterminateDrawable.mutate();
+ mIndeterminateDrawable.setTint(mIndeterminateTint, mIndeterminateTintMode);
}
}
@@ -532,42 +697,340 @@ public class ProgressBar extends View {
* @see #setIndeterminate(boolean)
*/
public void setProgressDrawable(Drawable d) {
- boolean needUpdate;
- if (mProgressDrawable != null && d != mProgressDrawable) {
- mProgressDrawable.setCallback(null);
- needUpdate = true;
- } else {
- needUpdate = false;
- }
+ if (mProgressDrawable != d) {
+ if (mProgressDrawable != null) {
+ mProgressDrawable.setCallback(null);
+ unscheduleDrawable(mProgressDrawable);
+ }
- if (d != null) {
- d.setCallback(this);
- if (canResolveLayoutDirection()) {
+ mProgressDrawable = d;
+
+ if (d != null) {
+ d.setCallback(this);
d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+
+ // Make sure the ProgressBar is always tall enough
+ int drawableHeight = d.getMinimumHeight();
+ if (mMaxHeight < drawableHeight) {
+ mMaxHeight = drawableHeight;
+ requestLayout();
+ }
+
+ if (mHasProgressTint) {
+ applyProgressLayerTint(R.id.progress, mProgressTint, mProgressTintMode, true);
+ }
+
+ if (mHasProgressBackgroundTint) {
+ applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+ mProgressBackgroundTintMode, false);
+ }
+
+ if (mHasSecondaryProgressTint) {
+ applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+ mSecondaryProgressTintMode, false);
+ }
}
- // Make sure the ProgressBar is always tall enough
- int drawableHeight = d.getMinimumHeight();
- if (mMaxHeight < drawableHeight) {
- mMaxHeight = drawableHeight;
- requestLayout();
+ if (!mIndeterminate) {
+ mCurrentDrawable = d;
+ postInvalidate();
}
- }
- mProgressDrawable = d;
- if (!mIndeterminate) {
- mCurrentDrawable = d;
- postInvalidate();
- }
- if (needUpdate) {
updateDrawableBounds(getWidth(), getHeight());
updateDrawableState();
+
doRefreshProgress(R.id.progress, mProgress, false, false);
doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
}
}
/**
+ * Applies a tint to the progress indicator, if one exists, or to the
+ * entire progress drawable otherwise.
+ * <p>
+ * The progress indicator should be specified as a layer with
+ * id {@link android.R.id#progress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setProgressTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mProgressTint = tint;
+ mProgressTintMode = tintMode;
+ mHasProgressTint = true;
+
+ applyProgressLayerTint(R.id.progress, tint, tintMode, true);
+ }
+
+ /**
+ * Applies a tint to the progress indicator, if one exists, or to the
+ * entire progress drawable otherwise. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The progress indicator should be specified as a layer with
+ * id {@link android.R.id#progress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @see #setProgressTint(ColorStateList)
+ */
+ public void setProgressTint(@Nullable ColorStateList tint) {
+ setProgressTint(tint, mProgressTintMode);
+ }
+
+ /**
+ * @return the tint applied to the progress drawable
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @see #setProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getProgressTint() {
+ return mProgressTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setProgressTint(ColorStateList)}} to the progress
+ * indicator. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see #setProgressTint(ColorStateList)
+ */
+ public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setProgressTint(mProgressTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the progress drawable
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see #setProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getProgressTintMode() {
+ return mProgressTintMode;
+ }
+
+ /**
+ * Applies a tint to the progress background, if one exists.
+ * <p>
+ * The progress background must be specified as a layer with
+ * id {@link android.R.id#background} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a progress background will automatically mutate the
+ * drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setProgressBackgroundTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mProgressBackgroundTint = tint;
+ mProgressBackgroundTintMode = tintMode;
+ mHasProgressBackgroundTint = true;
+
+ applyProgressLayerTint(R.id.background, tint, tintMode, false);
+ }
+
+ /**
+ * Applies a tint to the progress background, if one exists. Does not
+ * modify the current tint mode, which is
+ * {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The progress background must be specified as a layer with
+ * id {@link android.R.id#background} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a progress background will automatically mutate the
+ * drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setProgressBackgroundTint(@Nullable ColorStateList tint) {
+ setProgressBackgroundTint(tint, mProgressBackgroundTintMode);
+ }
+
+ /**
+ * @return the tint applied to the progress background
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getProgressBackgroundTint() {
+ return mProgressBackgroundTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setProgressBackgroundTint(ColorStateList)}} to the progress
+ * background. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see #setProgressBackgroundTint(ColorStateList)
+ */
+ public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setProgressBackgroundTint(mProgressBackgroundTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the progress
+ * background
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getProgressBackgroundTintMode() {
+ return mProgressBackgroundTintMode;
+ }
+
+ /**
+ * Applies a tint to the secondary progress indicator, if one exists.
+ * <p>
+ * The secondary progress indicator must be specified as a layer with
+ * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a secondary progress indicator will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setSecondaryProgressTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mSecondaryProgressTint = tint;
+ mSecondaryProgressTintMode = tintMode;
+ mHasSecondaryProgressTint = true;
+
+ applyProgressLayerTint(R.id.secondaryProgress, tint, tintMode, false);
+ }
+
+ /**
+ * Applies a tint to the secondary progress indicator, if one exists.
+ * Does not modify the current tint mode, which is
+ * {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The secondary progress indicator must be specified as a layer with
+ * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a secondary progress indicator will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setSecondaryProgressTint(@Nullable ColorStateList tint) {
+ setSecondaryProgressTint(tint, mSecondaryProgressTintMode);
+ }
+
+ /**
+ * @return the tint applied to the secondary progress drawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getSecondaryProgressTint() {
+ return mSecondaryProgressTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setSecondaryProgressTint(ColorStateList)}} to the secondary
+ * progress indicator. The default mode is
+ * {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see #setSecondaryProgressTint(ColorStateList)
+ */
+ public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setSecondaryProgressTint(mSecondaryProgressTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the secondary
+ * progress drawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getSecondaryProgressTintMode() {
+ return mSecondaryProgressTintMode;
+ }
+
+ private void applyProgressLayerTint(int layerId, @Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode, boolean shouldFallback) {
+ final Drawable d = mProgressDrawable;
+ if (d != null) {
+ mProgressDrawable = d.mutate();
+
+ Drawable layer = null;
+ if (d instanceof LayerDrawable) {
+ layer = ((LayerDrawable) d).findDrawableByLayerId(layerId);
+ }
+
+ if (shouldFallback && layer == null) {
+ layer = d;
+ }
+
+ if (layer != null) {
+ layer.setTint(tint, tintMode);
+ }
+ }
+ }
+
+ /**
* Define the tileable drawable used to draw the progress bar in
* progress mode.
* <p>
@@ -670,6 +1133,22 @@ public class ProgressBar extends View {
}
}
+ private void setDrawableTint(int id, ColorStateList tint, Mode tintMode, boolean fallback) {
+ Drawable layer = null;
+
+ // We expect a layer drawable, so try to find the target ID.
+ final Drawable d = mCurrentDrawable;
+ if (d instanceof LayerDrawable) {
+ layer = ((LayerDrawable) d).findDrawableByLayerId(id);
+ }
+
+ if (fallback && layer == null) {
+ layer = d;
+ }
+
+ layer.mutate().setTint(tint, tintMode);
+ }
+
private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
boolean callBackToApp) {
float scale = mMax > 0 ? (float) progress / (float) mMax : 0;