Add attributes and accessors for tinting View drawables

Also cleans up handling in setters for managed drawables.

BUG: 15391544
Change-Id: Idc08f7eaea0050feb6403566985a6d58185b81f8
diff --git a/api/current.txt b/api/current.txt
index 704a60a..5f51f37 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -320,6 +320,8 @@
     field public static final int backgroundDimEnabled = 16843295; // 0x101021f
     field public static final int backgroundSplit = 16843659; // 0x101038b
     field public static final int backgroundStacked = 16843658; // 0x101038a
+    field public static final int backgroundTint = 16843885; // 0x101046d
+    field public static final int backgroundTintMode = 16843886; // 0x101046e
     field public static final int backupAgent = 16843391; // 0x101027f
     field public static final int banner = 16843762; // 0x10103f2
     field public static final int baseline = 16843548; // 0x101031c
@@ -344,6 +346,8 @@
     field public static final int buttonStyleInset = 16842826; // 0x101004a
     field public static final int buttonStyleSmall = 16842825; // 0x1010049
     field public static final int buttonStyleToggle = 16842827; // 0x101004b
+    field public static final int buttonTint = 16843889; // 0x1010471
+    field public static final int buttonTintMode = 16843890; // 0x1010472
     field public static final int cacheColorHint = 16843009; // 0x1010101
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
@@ -554,6 +558,8 @@
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
+    field public static final int foregroundTint = 16843887; // 0x101046f
+    field public static final int foregroundTintMode = 16843888; // 0x1010470
     field public static final int format = 16843013; // 0x1010105
     field public static final int format12Hour = 16843722; // 0x10103ca
     field public static final int format24Hour = 16843723; // 0x10103cb
@@ -636,6 +642,8 @@
     field public static final int indeterminateDuration = 16843069; // 0x101013d
     field public static final int indeterminateOnly = 16843066; // 0x101013a
     field public static final int indeterminateProgressStyle = 16843544; // 0x1010318
+    field public static final int indeterminateTint = 16843883; // 0x101046b
+    field public static final int indeterminateTintMode = 16843884; // 0x101046c
     field public static final int indicatorEnd = 16843730; // 0x10103d2
     field public static final int indicatorLeft = 16843021; // 0x101010d
     field public static final int indicatorRight = 16843022; // 0x101010e
@@ -911,6 +919,8 @@
     field public static final int privateImeOptions = 16843299; // 0x1010223
     field public static final int process = 16842769; // 0x1010011
     field public static final int progress = 16843063; // 0x1010137
+    field public static final int progressBackgroundTint = 16843879; // 0x1010467
+    field public static final int progressBackgroundTintMode = 16843880; // 0x1010468
     field public static final int progressBarPadding = 16843545; // 0x1010319
     field public static final int progressBarStyle = 16842871; // 0x1010077
     field public static final int progressBarStyleHorizontal = 16842872; // 0x1010078
@@ -921,6 +931,8 @@
     field public static final int progressBarStyleSmallInverse = 16843400; // 0x1010288
     field public static final int progressBarStyleSmallTitle = 16843279; // 0x101020f
     field public static final int progressDrawable = 16843068; // 0x101013c
+    field public static final int progressTint = 16843877; // 0x1010465
+    field public static final int progressTintMode = 16843878; // 0x1010466
     field public static final int prompt = 16843131; // 0x101017b
     field public static final int propertyName = 16843489; // 0x10102e1
     field public static final int protectionLevel = 16842761; // 0x1010009
@@ -1013,6 +1025,8 @@
     field public static final int searchSuggestSelection = 16843224; // 0x10101d8
     field public static final int searchSuggestThreshold = 16843373; // 0x101026d
     field public static final int secondaryProgress = 16843064; // 0x1010138
+    field public static final int secondaryProgressTint = 16843881; // 0x1010469
+    field public static final int secondaryProgressTintMode = 16843882; // 0x101046a
     field public static final int seekBarStyle = 16842875; // 0x101007b
     field public static final int segmentedButtonStyle = 16843568; // 0x1010330
     field public static final int selectAllOnFocus = 16843102; // 0x101015e
@@ -1216,6 +1230,8 @@
     field public static final int thumb = 16843074; // 0x1010142
     field public static final int thumbOffset = 16843075; // 0x1010143
     field public static final int thumbTextPadding = 16843634; // 0x1010372
+    field public static final int thumbTint = 16843891; // 0x1010473
+    field public static final int thumbTintMode = 16843892; // 0x1010474
     field public static final int thumbnail = 16843429; // 0x10102a5
     field public static final int tileMode = 16843265; // 0x1010201
     field public static final int timeZone = 16843724; // 0x10103cc
@@ -32516,6 +32532,8 @@
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
     method public android.graphics.drawable.Drawable getBackground();
+    method public android.content.res.ColorStateList getBackgroundTint();
+    method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
     method public int getBaseline();
     method public final int getBottom();
     method protected float getBottomFadingEdgeStrength();
@@ -32793,6 +32811,8 @@
     method public void setBackgroundColor(int);
     method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setBackgroundResource(int);
+    method public void setBackgroundTint(android.content.res.ColorStateList);
+    method public void setBackgroundTintMode(android.graphics.PorterDuff.Mode);
     method public final void setBottom(int);
     method public void setCameraDistance(float);
     method public void setClickable(boolean);
@@ -35759,10 +35779,14 @@
     method public boolean getSplitTrack();
     method public android.graphics.drawable.Drawable getThumb();
     method public int getThumbOffset();
+    method public android.content.res.ColorStateList getThumbTint();
+    method public android.graphics.PorterDuff.Mode getThumbTintMode();
     method public void setKeyProgressIncrement(int);
     method public void setSplitTrack(boolean);
     method public void setThumb(android.graphics.drawable.Drawable);
     method public void setThumbOffset(int);
+    method public void setThumbTint(android.content.res.ColorStateList);
+    method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public abstract class AbsSpinner extends android.widget.AdapterView {
@@ -36177,9 +36201,13 @@
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet);
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int);
     ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int, int);
+    method public android.content.res.ColorStateList getButtonTint();
+    method public android.graphics.PorterDuff.Mode getButtonTintMode();
     method public boolean isChecked();
     method public void setButtonDrawable(int);
     method public void setButtonDrawable(android.graphics.drawable.Drawable);
+    method public void setButtonTint(android.content.res.ColorStateList);
+    method public void setButtonTintMode(android.graphics.PorterDuff.Mode);
     method public void setChecked(boolean);
     method public void setOnCheckedChangeListener(android.widget.CompoundButton.OnCheckedChangeListener);
     method public void toggle();
@@ -36440,10 +36468,14 @@
     method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
     method public android.graphics.drawable.Drawable getForeground();
     method public int getForegroundGravity();
+    method public android.content.res.ColorStateList getForegroundTint();
+    method public android.graphics.PorterDuff.Mode getForegroundTintMode();
     method public boolean getMeasureAllChildren();
     method protected void onLayout(boolean, int, int, int, int);
     method public void setForeground(android.graphics.drawable.Drawable);
     method public void setForegroundGravity(int);
+    method public void setForegroundTint(android.content.res.ColorStateList);
+    method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
     method public void setMeasureAllChildren(boolean);
   }
 
@@ -36652,6 +36684,8 @@
     method public int getMaxHeight();
     method public int getMaxWidth();
     method public android.widget.ImageView.ScaleType getScaleType();
+    method public android.content.res.ColorStateList getTint();
+    method public android.graphics.PorterDuff.Mode getTintMode();
     method public int[] onCreateDrawableState(int);
     method public void setAdjustViewBounds(boolean);
     method public deprecated void setAlpha(int);
@@ -36673,6 +36707,8 @@
     method public void setMaxHeight(int);
     method public void setMaxWidth(int);
     method public void setScaleType(android.widget.ImageView.ScaleType);
+    method public void setTint(android.content.res.ColorStateList);
+    method public void setTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public static final class ImageView.ScaleType extends java.lang.Enum {
@@ -37045,11 +37081,19 @@
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int);
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int);
     method public android.graphics.drawable.Drawable getIndeterminateDrawable();
+    method public android.content.res.ColorStateList getIndeterminateTint();
+    method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
     method public android.view.animation.Interpolator getInterpolator();
     method public synchronized int getMax();
     method public synchronized int getProgress();
+    method public android.content.res.ColorStateList getProgressBackgroundTint();
+    method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
     method public android.graphics.drawable.Drawable getProgressDrawable();
+    method public android.content.res.ColorStateList getProgressTint();
+    method public android.graphics.PorterDuff.Mode getProgressTintMode();
     method public synchronized int getSecondaryProgress();
+    method public android.content.res.ColorStateList getSecondaryProgressTint();
+    method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
     method public final synchronized void incrementProgressBy(int);
     method public final synchronized void incrementSecondaryProgressBy(int);
     method public synchronized boolean isIndeterminate();
@@ -37058,13 +37102,21 @@
     method public synchronized void setIndeterminate(boolean);
     method public void setIndeterminateDrawable(android.graphics.drawable.Drawable);
     method public void setIndeterminateDrawableTiled(android.graphics.drawable.Drawable);
+    method public void setIndeterminateTint(android.content.res.ColorStateList);
+    method public void setIndeterminateTintMode(android.graphics.PorterDuff.Mode);
     method public void setInterpolator(android.content.Context, int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public synchronized void setMax(int);
     method public synchronized void setProgress(int);
+    method public void setProgressBackgroundTint(android.content.res.ColorStateList);
+    method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
     method public void setProgressDrawable(android.graphics.drawable.Drawable);
     method public void setProgressDrawableTiled(android.graphics.drawable.Drawable);
+    method public void setProgressTint(android.content.res.ColorStateList);
+    method public void setProgressTintMode(android.graphics.PorterDuff.Mode);
     method public synchronized void setSecondaryProgress(int);
+    method public void setSecondaryProgressTint(android.content.res.ColorStateList);
+    method public void setSecondaryProgressTintMode(android.graphics.PorterDuff.Mode);
   }
 
   public class QuickContactBadge extends android.widget.ImageView implements android.view.View.OnClickListener {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b9e56f3..cafb044 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25,6 +25,7 @@
 import android.annotation.Nullable;
 import android.content.ClipData;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -44,6 +45,7 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.Shader;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManagerGlobal;
@@ -3187,6 +3189,9 @@
 
     @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
     private Drawable mBackground;
+    private ColorStateList mBackgroundTint = null;
+    private PorterDuff.Mode mBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
+    private boolean mHasBackgroundTint = false;
 
     /**
      * Display list used for backgrounds.
@@ -4022,6 +4027,16 @@
                     setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
                             a.getResourceId(attr, 0)));
                     break;
+                case R.styleable.View_backgroundTint:
+                    // This will get applied later during setBackground().
+                    mBackgroundTint = a.getColorStateList(R.styleable.View_backgroundTint);
+                    mHasBackgroundTint = true;
+                    break;
+                case R.styleable.View_backgroundTintMode:
+                    // This will get applied later during setBackground().
+                    mBackgroundTintMode = Drawable.parseTintMode(a.getInt(
+                            R.styleable.View_backgroundTintMode, -1), mBackgroundTintMode);
+                    break;
             }
         }
 
@@ -15703,7 +15718,7 @@
             return;
         }
 
-        Drawable d= null;
+        Drawable d = null;
         if (resid != 0) {
             d = mContext.getDrawable(resid);
         }
@@ -15779,8 +15794,9 @@
 
             // Compare the minimum sizes of the old Drawable and the new.  If there isn't an old or
             // if it has a different minimum size, we should layout again
-            if (mBackground == null || mBackground.getMinimumHeight() != background.getMinimumHeight() ||
-                    mBackground.getMinimumWidth() != background.getMinimumWidth()) {
+            if (mBackground == null
+                    || mBackground.getMinimumHeight() != background.getMinimumHeight()
+                    || mBackground.getMinimumWidth() != background.getMinimumWidth()) {
                 requestLayout = true;
             }
 
@@ -15791,6 +15807,8 @@
             background.setVisible(getVisibility() == VISIBLE, false);
             mBackground = background;
 
+            applyBackgroundTint();
+
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
                 mPrivateFlags &= ~PFLAG_SKIP_DRAW;
                 mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND;
@@ -15846,6 +15864,88 @@
     }
 
     /**
+     * Applies a tint to the background drawable.
+     * <p>
+     * Subsequent calls to {@link #setBackground(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#View_backgroundTint
+     * @attr ref android.R.styleable#View_backgroundTintMode
+     * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+     */
+    private void setBackgroundTint(@Nullable ColorStateList tint,
+            @Nullable PorterDuff.Mode tintMode) {
+        mBackgroundTint = tint;
+        mBackgroundTintMode = tintMode;
+        mHasBackgroundTint = true;
+
+        applyBackgroundTint();
+    }
+
+    /**
+     * Applies a tint to the background drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+     * <p>
+     * Subsequent calls to {@link #setBackground(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#View_backgroundTint
+     * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    public void setBackgroundTint(@Nullable ColorStateList tint) {
+        setBackgroundTint(tint, mBackgroundTintMode);
+    }
+
+    /**
+     * @return the tint applied to the background drawable
+     * @attr ref android.R.styleable#View_backgroundTint
+     * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public ColorStateList getBackgroundTint() {
+        return mBackgroundTint;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setBackgroundTint(ColorStateList)}} to the background 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#View_backgroundTintMode
+     * @see #setBackgroundTint(ColorStateList)
+     */
+    public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        setBackgroundTint(mBackgroundTint, tintMode);
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the background drawable
+     * @attr ref android.R.styleable#View_backgroundTintMode
+     * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+     */
+    @Nullable
+    public PorterDuff.Mode getBackgroundTintMode() {
+        return mBackgroundTintMode;
+    }
+
+    private void applyBackgroundTint() {
+        if (mBackground != null && mHasBackgroundTint) {
+            mBackground = mBackground.mutate();
+            mBackground.setTint(mBackgroundTint, mBackgroundTintMode);
+        }
+    }
+
+    /**
      * Sets the padding. The view may add on the space required to display
      * the scrollbars, depending on the style and visibility of the scrollbars.
      * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop},
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.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 @@
         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 @@
      * @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 @@
         } else {
             needUpdate = false;
         }
+
         if (thumb != null) {
             thumb.setCallback(this);
             if (canResolveLayoutDirection()) {
@@ -136,8 +156,12 @@
                 requestLayout();
             }
         }
+
         mThumb = thumb;
+
+        applyThumbTint();
         invalidate();
+
         if (needUpdate) {
             updateThumbAndTrackPos(getWidth(), getHeight());
             if (thumb != null && thumb.isStateful()) {
@@ -160,6 +184,88 @@
     }
 
     /**
+     * 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 @@
     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 @@
         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 @@
     }
 
     /**
-     * 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 @@
     }
 
     /**
-     * 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());
-        }
 
-        refreshDrawableState();
+            mButtonDrawable = d;
+
+            if (d != null) {
+                d.setCallback(this);
+                d.setLayoutDirection(getLayoutDirection());
+                if (d.isStateful()) {
+                    d.setState(getDrawableState());
+                }
+                d.setVisible(getVisibility() == VISIBLE, false);
+                setMinHeight(d.getIntrinsicHeight());
+                applyButtonTint();
+            }
+        }
+    }
+
+    /**
+     * 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 @@
 
 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.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 @@
 
     @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 @@
             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 @@
      * 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 @@
         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.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.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.R;
+
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -75,13 +80,18 @@
     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 @@
         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 @@
     }
 
     /**
+     * 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 @@
             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 void setColorFilter(ColorFilter cf) {
         if (mColorFilter != cf) {
             mColorFilter = cf;
+            mHasColorFilter = true;
             mColorMod = true;
             applyColorMod();
             invalidate();
@@ -1231,7 +1331,9 @@
         // 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 @@
     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 @@
         
         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 @@
         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 @@
 
         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 @@
      * @see #setIndeterminate(boolean)
      */
     public void setIndeterminateDrawable(Drawable d) {
-        if (d != null) {
-            d.setCallback(this);
+        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();
+            }
         }
-        mIndeterminateDrawable = d;
-        if (mIndeterminateDrawable != null && canResolveLayoutDirection()) {
-            mIndeterminateDrawable.setLayoutDirection(getLayoutDirection());
-        }
-        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 @@
      * @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 @@
         }
     }
 
+    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;
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e807d69..8d8f69e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2432,6 +2432,30 @@
 
         <!-- Sets the state-based animator for the View. -->
         <attr name="stateListAnimator" format="reference"/>
+
+        <!-- Tint to apply to the background. -->
+        <attr name="backgroundTint" format="color" />
+
+        <!-- Blending mode used to apply the background tint. -->
+        <attr name="backgroundTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3021,7 +3045,29 @@
         <!-- Indicates the initial checked state of this button. -->
         <attr name="checked" format="boolean" />
         <!-- Drawable used for the button graphic (e.g. checkbox, radio button, etc). -->
-        <attr name="button" format="reference"/>
+        <attr name="button" format="reference" />
+        <!-- Tint to apply to the button graphic. -->
+        <attr name="buttonTint" format="color" />
+        <!-- Blending mode used to apply the button graphic tint. -->
+        <attr name="buttonTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
     <declare-styleable name="CheckedTextView">
         <!-- Indicates the initial checked state of this text. -->
@@ -3106,6 +3152,28 @@
         <!-- Determines whether to measure all children or just those in
              the VISIBLE or INVISIBLE state when measuring. Defaults to false. -->
         <attr name="measureAllChildren" format="boolean" />
+        <!-- Tint to apply to the foreground. -->
+        <attr name="foregroundTint" format="color" />
+        <!-- Blending mode used to apply the foreground tint. -->
+        <attr name="foregroundTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
     <declare-styleable name="ExpandableListView">
         <!-- Indicator shown beside the group View. This can be a stateful Drawable. -->
@@ -3211,6 +3279,10 @@
         <!-- @hide The alpha value (0-255) set on the ImageView's drawable. Equivalent
              to calling ImageView.setAlpha(int), not the same as View.setAlpha(float). -->
         <attr name="drawableAlpha" format="integer" />
+        <!-- Tint to apply to the image. -->
+        <attr name="tint" />
+        <!-- Blending mode used to apply the image tint. -->
+        <attr name="tintMode" />
     </declare-styleable>
     <declare-styleable name="ToggleButton">
         <!-- The text for the button when it is checked. -->
@@ -3401,6 +3473,98 @@
         <!-- Defines if the associated drawables need to be mirrored when in RTL mode.
              Default is false -->
         <attr name="mirrorForRtl" format="boolean" />
+        <!-- Tint to apply to the progress indicator. -->
+        <attr name="progressTint" format="color" />
+        <!-- Blending mode used to apply the progress indicator tint. -->
+        <attr name="progressTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+        <!-- Tint to apply to the progress indicator background. -->
+        <attr name="progressBackgroundTint" format="color" />
+        <!-- Blending mode used to apply the progress indicator background tint. -->
+        <attr name="progressBackgroundTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+        <!-- Tint to apply to the secondary progress indicator. -->
+        <attr name="secondaryProgressTint" format="color" />
+        <!-- Blending mode used to apply the secondary progress indicator tint. -->
+        <attr name="secondaryProgressTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+        <!-- Tint to apply to the indepterminate progress indicator. -->
+        <attr name="indeterminateTint" format="color" />
+        <!-- Blending mode used to apply the indeterminate progress indicator tint. -->
+        <attr name="indeterminateTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+        <!-- Tint to apply to the background. -->
+        <attr name="backgroundTint" />
+        <!-- Blending mode used to apply the background tint. -->
+        <attr name="backgroundTintMode" />
     </declare-styleable>
 
     <declare-styleable name="SeekBar">
@@ -3410,6 +3574,28 @@
         <attr name="thumbOffset" format="dimension" />
         <!-- Whether to split the track and leave a gap for the thumb drawable. -->
         <attr name="splitTrack" format="boolean" />
+        <!-- Tint to apply to the button graphic. -->
+        <attr name="thumbTint" format="color" />
+        <!-- Blending mode used to apply the button graphic tint. -->
+        <attr name="thumbTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="StackView">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 202c127..1580d69 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2190,6 +2190,22 @@
   <public type="attr" name="searchKeyphraseSupportedLocales" />
   <public type="attr" name="windowTransitionBackgroundFadeDuration" />
   <public type="attr" name="overlapAnchor" />
+  <public type="attr" name="progressTint" />
+  <public type="attr" name="progressTintMode" />
+  <public type="attr" name="progressBackgroundTint" />
+  <public type="attr" name="progressBackgroundTintMode" />
+  <public type="attr" name="secondaryProgressTint" />
+  <public type="attr" name="secondaryProgressTintMode" />
+  <public type="attr" name="indeterminateTint" />
+  <public type="attr" name="indeterminateTintMode" />
+  <public type="attr" name="backgroundTint" />
+  <public type="attr" name="backgroundTintMode" />
+  <public type="attr" name="foregroundTint" />
+  <public type="attr" name="foregroundTintMode" />
+  <public type="attr" name="buttonTint" />
+  <public type="attr" name="buttonTintMode" />
+  <public type="attr" name="thumbTint" />
+  <public type="attr" name="thumbTintMode" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index cb88e3d..40b55a7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1260,8 +1260,10 @@
     /**
      * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
      * attribute's enum value.
+     *
+     * @hide
      */
-    static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+    public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
         switch (value) {
             case 3: return Mode.SRC_OVER;
             case 5: return Mode.SRC_IN;