Fix support for TouchFeedbackDrawable tint mode

Change-Id: I86bff1c5e69d9a193deb52559948b20ddca99751
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 2810c43..3773a49 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -44,9 +44,6 @@
  * Documentation pending.
  */
 public class TouchFeedbackDrawable extends LayerDrawable {
-    private static final PorterDuffXfermode DST_ATOP = new PorterDuffXfermode(Mode.DST_ATOP);
-    private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
-
     /** The maximum number of ripples supported. */
     private static final int MAX_RIPPLES = 10;
 
@@ -153,10 +150,8 @@
      * @param tintMode A Porter-Duff blending mode
      */
     public void setTintMode(Mode tintMode) {
-        if (mState.mTintMode != tintMode) {
-            mState.mTintMode = tintMode;
-            invalidateSelf();
-        }
+        mState.setTintMode(tintMode);
+        invalidateSelf();
     }
 
     @Override
@@ -187,8 +182,8 @@
         }
 
         if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
-            mState.mTintMode = Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP);
+            mState.setTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
         }
 
         if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_pinned] == 0) {
@@ -238,8 +233,8 @@
         }
 
         if (a.hasValue(R.styleable.TouchFeedbackDrawable_tintMode)) {
-            mState.mTintMode = Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP);
+            mState.setTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
         }
 
         if (a.hasValue(R.styleable.TouchFeedbackDrawable_pinned)) {
@@ -382,8 +377,9 @@
         // If we have ripples and content, we need a masking layer. This will
         // merge DST_ATOP onto (effectively under) the ripple layer.
         if (drewRipples && !projected && rippleRestoreCount >= 0) {
+            final PorterDuffXfermode xfermode = mState.getTintXfermode();
             canvas.saveLayer(bounds.left, bounds.top,
-                    bounds.right, bounds.bottom, getMaskingPaint(DST_ATOP), 0);
+                    bounds.right, bounds.bottom, getMaskingPaint(xfermode), 0);
         }
 
         Drawable mask = null;
@@ -401,7 +397,7 @@
         if (mask != null && drewRipples) {
             // TODO: This will also mask the lower layer, which is bad.
             canvas.saveLayer(bounds.left, bounds.top, bounds.right,
-                    bounds.bottom, getMaskingPaint(DST_IN), 0);
+                    bounds.bottom, getMaskingPaint(mState.mTintXfermode), 0);
             mask.draw(canvas);
         }
 
@@ -459,7 +455,7 @@
     static class TouchFeedbackState extends LayerState {
         int[] mTouchThemeAttrs;
         ColorStateList mTint;
-        Mode mTintMode;
+        PorterDuffXfermode mTintXfermode;
         boolean mPinned;
 
         public TouchFeedbackState(
@@ -469,10 +465,19 @@
             if (orig != null) {
                 mTouchThemeAttrs = orig.mTouchThemeAttrs;
                 mTint = orig.mTint;
-                mTintMode = orig.mTintMode;
+                mTintXfermode = orig.mTintXfermode;
                 mPinned = orig.mPinned;
             }
         }
+        
+        public void setTintMode(Mode mode) {
+            final Mode invertedMode = TouchFeedbackState.invertPorterDuffMode(mode);
+            mTintXfermode = new PorterDuffXfermode(invertedMode);
+        }
+        
+        public PorterDuffXfermode getTintXfermode() {
+            return mTintXfermode;
+        }
 
         @Override
         public boolean canApplyTheme() {
@@ -493,6 +498,33 @@
         public Drawable newDrawable(Resources res, Theme theme) {
             return new TouchFeedbackDrawable(this, res, theme);
         }
+
+        /**
+         * Inverts SRC and DST in PorterDuff blending modes.
+         */
+        private static Mode invertPorterDuffMode(Mode src) {
+            switch (src) {
+                case SRC_ATOP:
+                    return Mode.DST_ATOP;
+                case SRC_IN:
+                    return Mode.DST_IN;
+                case SRC_OUT:
+                    return Mode.DST_OUT;
+                case SRC_OVER:
+                    return Mode.DST_OVER;
+                case DST_ATOP:
+                    return Mode.SRC_ATOP;
+                case DST_IN:
+                    return Mode.SRC_IN;
+                case DST_OUT:
+                    return Mode.SRC_OUT;
+                case DST_OVER:
+                    return Mode.SRC_OVER;
+                default:
+                    // Everything else is agnostic to SRC versus DST.
+                    return src;
+            }
+        }
     }
 
     private TouchFeedbackDrawable(TouchFeedbackState state, Resources res, Theme theme) {