Avoid drawable invalidation during draw()

Prevents infinite invalidation loop when reusing a drawable asset within
a single draw() call. Also reduces unnecessary extra invalidations due to
drawable setters (ex. setBounds()) being called during draw().

Bug: 26329675
Change-Id: I31b3c99e8efd4193415cc562a84c8939a2f56c2d
(cherry picked from commit 8cda8e915916b3166e4496589b802fd1ed553c77)
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index dea004e..5f8d49d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3481,6 +3481,9 @@
 
     private int[] mDrawableState = null;
 
+    /** Whether draw() is currently being called. */
+    private boolean mInDraw = false;
+
     ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND;
 
     /**
@@ -16151,6 +16154,8 @@
      */
     @CallSuper
     public void draw(Canvas canvas) {
+        mInDraw = true;
+
         final int privateFlags = mPrivateFlags;
         final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
@@ -16195,6 +16200,7 @@
             onDrawForeground(canvas);
 
             // we're done...
+            mInDraw = false;
             return;
         }
 
@@ -16342,6 +16348,8 @@
 
         // Step 6, draw decorations (foreground, scrollbars)
         onDrawForeground(canvas);
+
+        mInDraw = false;
     }
 
     /**
@@ -16786,7 +16794,8 @@
      */
     @Override
     public void invalidateDrawable(@NonNull Drawable drawable) {
-        if (verifyDrawable(drawable)) {
+        // Don't invalidate if a drawable changes during drawing.
+        if (verifyDrawable(drawable) && !mInDraw) {
             final Rect dirty = drawable.getDirtyBounds();
             final int scrollX = mScrollX;
             final int scrollY = mScrollY;