Merge "Add support for specifying Drawable color filter in XML"
diff --git a/api/current.txt b/api/current.txt
index 1495277..76c30fa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -377,6 +377,8 @@
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
     field public static final int colorBackground = 16842801; // 0x1010031
     field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
+    field public static final int colorFilterColor = 16843767; // 0x10103f7
+    field public static final int colorFilterMode = 16843768; // 0x10103f8
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0f812f1..c603418 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4060,6 +4060,19 @@
              RTL (right-to-left).  See
              {@link android.graphics.drawable.Drawable#setAutoMirrored}. -->
         <attr name="autoMirrored" format="boolean" />
+        <!-- If set, specifies the color to apply to the drawable as a color filter. By
+             default, no color filter is applied. -->
+        <attr name="colorFilterColor" format="color" />
+        <!-- When a color filter color is set, specifies its Porter-Duff blending mode.
+             The default value is multiply. -->
+        <attr name="colorFilterMode">
+            <!-- [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+        </attr>
     </declare-styleable>
 
     <!-- Drawable used to render several states. Each state is represented by
@@ -4344,6 +4357,8 @@
         <!-- Indicates if the drawable needs to be mirrored when its layout direction is
              RTL (right-to-left). -->
         <attr name="autoMirrored" />
+        <attr name="colorFilterColor" />
+        <attr name="colorFilterMode" />
     </declare-styleable>
 
     <!-- Drawable used to draw 9-patches. -->
@@ -4357,6 +4372,8 @@
         <!-- Indicates if the drawable needs to be mirrored when its layout direction is
              RTL (right-to-left). -->
         <attr name="autoMirrored" />
+        <attr name="colorFilterColor" />
+        <attr name="colorFilterMode" />
     </declare-styleable>
 
     <!-- Drawable used to draw a single color. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a0d84c9..9a9b71a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2097,6 +2097,8 @@
   <public type="attr" name="windowContentTransitions" />
   <public type="attr" name="windowContentTransitionManager" />
   <public type="attr" name="translationZ" />
+  <public type="attr" name="colorFilterColor" />
+  <public type="attr" name="colorFilterMode" />
 
   <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
   <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 98e3386..9360558 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -26,6 +26,8 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.Xfermode;
@@ -33,6 +35,7 @@
 import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
 import android.view.Gravity;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -579,6 +582,18 @@
         setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_autoMirrored,
                 false));
 
+        if (a.hasValue(com.android.internal.R.styleable.BitmapDrawable_colorFilterColor)) {
+            final int colorFilterColor = a.getColor(
+                    com.android.internal.R.styleable.BitmapDrawable_colorFilterColor, 0);
+            final int modeValue = a.getInt(
+                    com.android.internal.R.styleable.BitmapDrawable_colorFilterMode,
+                    Mode.MULTIPLY.ordinal());
+            final Mode mode = Drawable.parseColorFilterMode(modeValue);
+            if (mode != null) {
+                setColorFilter(colorFilterColor, mode);
+            }
+        }
+
         final Paint paint = mBitmapState.mPaint;
         paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,
                 paint.isAntiAlias()));
@@ -647,7 +662,7 @@
         }
 
         BitmapState(BitmapState bitmapState) {
-            this(bitmapState.mBitmap);
+            mBitmap = bitmapState.mBitmap;
             mChangingConfigurations = bitmapState.mChangingConfigurations;
             mGravity = bitmapState.mGravity;
             mTileModeX = bitmapState.mTileModeX;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 630add7..b8365aa 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -83,7 +83,7 @@
  *     through the {@link Callback} interface.  All clients should support this
  *     interface (via {@link #setCallback}) so that animations will work.  A
  *     simple way to do this is through the system facilities such as
- *     {@link android.view.View#setBackgroundDrawable(Drawable)} and
+ *     {@link android.view.View#setBackground(Drawable)} and
  *     {@link android.widget.ImageView}.
  * </ul>
  *
@@ -438,9 +438,9 @@
     }
 
     /**
-     * Specify an optional colorFilter for the drawable. Pass null to remove
-     * any filters.
-    */
+     * Specify an optional color filter for the drawable. Pass null to remove
+     * any existing color filter.
+     */
     public abstract void setColorFilter(ColorFilter cf);
 
     /**
@@ -453,13 +453,16 @@
     }
 
     /**
-     * Specify a color and porterduff mode to be the colorfilter for this
+     * Specify a color and Porter-Duff mode to be the color filter for this
      * drawable.
      */
     public void setColorFilter(int color, PorterDuff.Mode mode) {
         setColorFilter(new PorterDuffColorFilter(color, mode));
     }
 
+    /**
+     * Removes the color filter for this drawable.
+     */
     public void clearColorFilter() {
         setColorFilter(null);
     }
@@ -1089,7 +1092,7 @@
 
     /**
      * Return a {@link ConstantState} instance that holds the shared state of this Drawable.
-     *q
+     *
      * @return The ConstantState associated to that Drawable.
      * @see ConstantState
      * @see Drawable#mutate()
@@ -1107,5 +1110,17 @@
 
         return new BitmapDrawable(res, bm);
     }
+
+    /**
+     * Parses a {@link android.graphics.PorterDuff.Mode} from a colorFilterMode
+     * attribute's enum value.
+     */
+    static PorterDuff.Mode parseColorFilterMode(int value) {
+        final PorterDuff.Mode[] modes = PorterDuff.Mode.values();
+        if (value >= 0 && value < modes.length) {
+            return modes[value];
+        }
+        return null;
+    }
 }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index aac7876..a1e0772 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -49,7 +49,6 @@
     private DrawableContainerState mDrawableContainerState;
     private Drawable mCurrDrawable;
     private int mAlpha = 0xFF;
-    private ColorFilter mColorFilter;
 
     private int mCurIndex = -1;
     private boolean mMutated;
@@ -147,8 +146,8 @@
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        if (mColorFilter != cf) {
-            mColorFilter = cf;
+        if (mDrawableContainerState.mColorFilter != cf) {
+            mDrawableContainerState.mColorFilter = cf;
             if (mCurrDrawable != null) {
                 mCurrDrawable.mutate().setColorFilter(cf);
             }
@@ -359,7 +358,7 @@
                 }
                 d.setVisible(isVisible(), true);
                 d.setDither(mDrawableContainerState.mDither);
-                d.setColorFilter(mColorFilter);
+                d.setColorFilter(mDrawableContainerState.mColorFilter);
                 d.setState(getState());
                 d.setLevel(getLevel());
                 d.setBounds(getBounds());
@@ -507,6 +506,8 @@
 
         boolean mAutoMirrored;
 
+        ColorFilter mColorFilter;
+
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
@@ -527,6 +528,7 @@
                 mEnterFadeDuration = orig.mEnterFadeDuration;
                 mExitFadeDuration = orig.mExitFadeDuration;
                 mAutoMirrored = orig.mAutoMirrored;
+                mColorFilter = orig.mColorFilter;
 
                 // Cloning the following values may require creating futures.
                 mConstantPadding = orig.getConstantPadding();
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 9c57a2c..515d3c1 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -26,12 +26,15 @@
 import android.graphics.NinePatch;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
 import android.util.TypedValue;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -133,6 +136,9 @@
             // lazy allocation of a paint
             setDither(state.mDither);
         }
+        if (state.mColorFilter != null) {
+            setColorFilter(state.mColorFilter);
+        }
         setAutoMirrored(state.mAutoMirrored);
         if (mNinePatch != null) {
             computeBitmapSize();
@@ -366,9 +372,25 @@
 
         final boolean automirrored = a.getBoolean(
                 com.android.internal.R.styleable.NinePatchDrawable_autoMirrored, false);
+        final NinePatchState ninePatchState = new NinePatchState(
+                new NinePatch(bitmap, bitmap.getNinePatchChunk()), padding, opticalInsets, dither,
+                automirrored);
 
-        setNinePatchState(new NinePatchState(new NinePatch(bitmap, bitmap.getNinePatchChunk()),
-                padding, opticalInsets, dither, automirrored), r);
+        if (a.hasValue(com.android.internal.R.styleable.NinePatchDrawable_colorFilterColor)) {
+            final int colorFilterColor = a.getColor(
+                    com.android.internal.R.styleable.NinePatchDrawable_colorFilterColor, 0);
+            final int modeValue = a.getInt(
+                    com.android.internal.R.styleable.NinePatchDrawable_colorFilterMode,
+                    Mode.MULTIPLY.ordinal());
+            final Mode mode = Drawable.parseColorFilterMode(modeValue);
+            if (mode != null) {
+                // This will be applied to the paint by setNinePatchState().
+                ninePatchState.mColorFilter = new PorterDuffColorFilter(colorFilterColor, mode);
+            }
+        }
+
+        setNinePatchState(ninePatchState, r);
+
         mNinePatchState.mTargetDensity = mTargetDensity;
 
         a.recycle();
@@ -447,6 +469,7 @@
         int mChangingConfigurations;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
         boolean mAutoMirrored;
+        ColorFilter mColorFilter;
 
         NinePatchState(NinePatch ninePatch, Rect padding) {
             this(ninePatch, padding, new Rect(), DEFAULT_DITHER, false);
@@ -477,6 +500,7 @@
             mChangingConfigurations = state.mChangingConfigurations;
             mTargetDensity = state.mTargetDensity;
             mAutoMirrored = state.mAutoMirrored;
+            mColorFilter = state.mColorFilter;
         }
 
         @Override