From 09deff1bd970bd6749d78b6c85026a9985e6a1f3 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Tue, 24 May 2016 15:14:38 -0400 Subject: [PATCH] Prevent LayerDrawable bounds updates from being re-entrant Collect child invalidations during layer bounds change, then dispatch a single invalidation if any children requested invalidation. This prevents re-entrance from, for example, a LayerDrawable.updateLayerBounds() call invoking setBounds() on a child, which necessarily calls invalidateSelf() and immediately propagates up to ImageView.invalidateDrawable(), which then calls configureBounds() and puts us back in updateLayerBounds(). Bug: 28636072 Change-Id: I36c9eefc18904d493292d51b37e4b05cfddcf794 --- .../graphics/drawable/LayerDrawable.java | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index c67b0081456ba..1864206118b21 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -104,6 +104,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { private Rect mHotspotBounds; private boolean mMutated; + private boolean mSuspendChildInvalidation; + private boolean mChildRequestedInvalidation; + /** * Creates a new layer drawable with the list of specified layers. * @@ -944,9 +947,37 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return mLayerState.mPaddingMode; } + /** + * Temporarily suspends child invalidation. + * + * @see #resumeChildInvalidation() + */ + private void suspendChildInvalidation() { + mSuspendChildInvalidation = true; + } + + /** + * Resumes child invalidation after suspension, immediately performing an + * invalidation if one was requested by a child during suspension. + * + * @see #suspendChildInvalidation() + */ + private void resumeChildInvalidation() { + mSuspendChildInvalidation = false; + + if (mChildRequestedInvalidation) { + mChildRequestedInvalidation = false; + invalidateSelf(); + } + } + @Override public void invalidateDrawable(@NonNull Drawable who) { - invalidateSelf(); + if (mSuspendChildInvalidation) { + mChildRequestedInvalidation = true; + } else { + invalidateSelf(); + } } @Override @@ -1482,6 +1513,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } private void updateLayerBounds(Rect bounds) { + try { + suspendChildInvalidation(); + updateLayerBoundsInternal(bounds); + } finally { + resumeChildInvalidation(); + } + } + + private void updateLayerBoundsInternal(Rect bounds) { int paddingL = 0; int paddingT = 0; int paddingR = 0;