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,