Workaround Drawable mutation bugs

Seems that certain drawable classes have bugs
around mutation on older API levels. We now
workaround them by not mutating on those API
levels.

BUG: 24667869
Change-Id: Ibe9917cdd3efd279876226a02d3e1f91a50b73a7
diff --git a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java b/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
index 8245ffc..a8fb7ac 100644
--- a/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
+++ b/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
@@ -22,7 +22,10 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.graphics.drawable.InsetDrawable;
 import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.StateListDrawable;
 import android.os.Build;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.ColorUtils;
@@ -592,22 +595,51 @@
     }
 
     public static void tintDrawable(Drawable drawable, TintInfo tint, int[] state) {
-        if (drawable == drawable.mutate()) {
-            if (tint.mHasTintList || tint.mHasTintMode) {
-                drawable.setColorFilter(createTintFilter(
-                        tint.mHasTintList ? tint.mTintList : null,
-                        tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE,
-                        state));
-            } else {
-                drawable.clearColorFilter();
-            }
+        if (shouldMutateBackground(drawable) && drawable.mutate() != drawable) {
+            Log.d(TAG, "Mutated drawable is not the same instance as the input.");
+            return;
+        }
 
-            if (Build.VERSION.SDK_INT <= 10) {
-                // On Gingerbread, GradientDrawable does not invalidate itself when it's
-                // ColorFilter has changed, so we need to force an invalidation
-                drawable.invalidateSelf();
+        if (tint.mHasTintList || tint.mHasTintMode) {
+            drawable.setColorFilter(createTintFilter(
+                    tint.mHasTintList ? tint.mTintList : null,
+                    tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE,
+                    state));
+        } else {
+            drawable.clearColorFilter();
+        }
+
+        if (Build.VERSION.SDK_INT <= 10) {
+            // On Gingerbread, GradientDrawable does not invalidate itself when it's
+            // ColorFilter has changed, so we need to force an invalidation
+            drawable.invalidateSelf();
+        }
+    }
+
+    private static boolean shouldMutateBackground(Drawable drawable) {
+        if (Build.VERSION.SDK_INT >= 16) {
+            // For SDK 16+, we should be fine mutating the drawable
+            return true;
+        }
+
+        if (drawable instanceof LayerDrawable) {
+            return Build.VERSION.SDK_INT >= 16;
+        } else if (drawable instanceof InsetDrawable) {
+            return Build.VERSION.SDK_INT >= 14;
+        } else if (drawable instanceof DrawableContainer) {
+            // If we have a DrawableContainer, let's traverse it's child array
+            final Drawable.ConstantState state = drawable.getConstantState();
+            if (state instanceof DrawableContainer.DrawableContainerState) {
+                final DrawableContainer.DrawableContainerState containerState =
+                        (DrawableContainer.DrawableContainerState) state;
+                for (Drawable child : containerState.getChildren()) {
+                    if (!shouldMutateBackground(child)) {
+                        return false;
+                    }
+                }
             }
         }
+        return true;
     }
 
     private static PorterDuffColorFilter createTintFilter(ColorStateList tint,