Merge "Fix flashing artifacts caused by invalidation bugs"
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index 40e99a1..ad660c1 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -288,6 +288,10 @@
 
     private final int mDensity;
 
+    // This flag tracks when the mIgnoreDirtyState flag is set during draw(), to avoid
+    // clearing that flag prematurely
+    private boolean mSetIgnoreDirtyState = false;
+
     /**
      * Consistency verifier for debugging purposes.
      */
@@ -672,6 +676,7 @@
             }
         }
         if (!mDirty.isEmpty() && !mDirty.contains(dirty)) {
+            mSetIgnoreDirtyState = true;
             mAttachInfo.mIgnoreDirtyState = true;
         }
         mDirty.union(dirty);
@@ -1747,7 +1752,7 @@
             mAttachInfo.mIgnoreDirtyState = true;
             dirty.union(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
         }
-        
+
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
             if (!dirty.isEmpty() || mIsAnimating) {
                 mIsAnimating = false;
@@ -1877,9 +1882,13 @@
                         }
                         canvas.setScreenDensity(scalingRequired
                                 ? DisplayMetrics.DENSITY_DEVICE : 0);
+                        mSetIgnoreDirtyState = false;
                         mView.draw(canvas);
                     } finally {
-                        mAttachInfo.mIgnoreDirtyState = false;
+                        if (!mSetIgnoreDirtyState) {
+                            // Only clear the flag if it was not set during the mView.draw() call
+                            mAttachInfo.mIgnoreDirtyState = false;
+                        }
                     }
 
                     if (false && ViewDebug.consistencyCheckEnabled) {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index a4734ff..7e03e1c 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -405,8 +405,11 @@
 
     @Override
     public void setAlpha(int alpha) {
-        mBitmapState.mPaint.setAlpha(alpha);
-        invalidateSelf();
+        int oldAlpha = mBitmapState.mPaint.getAlpha();
+        if (alpha != oldAlpha) {
+            mBitmapState.mPaint.setAlpha(alpha);
+            invalidateSelf();
+        }
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 9a3ca40..483fa56 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -187,8 +187,20 @@
         final int alpha = mAlpha;
         final boolean crossFade = mCrossFade;
         final ChildDrawable[] array = mLayerState.mChildren;
-        Drawable d;
 
+        if (done) {
+            // the setAlpha() calls below trigger invalidation and redraw. If we're done, just draw
+            // the appropriate drawable[s] and return
+            if (!crossFade || alpha == 0) {
+                array[0].mDrawable.draw(canvas);
+            }
+            if (alpha == 0xFF) {
+                array[1].mDrawable.draw(canvas);
+            }
+            return;
+        }
+
+        Drawable d;
         d = array[0].mDrawable;
         if (crossFade) {
             d.setAlpha(255 - alpha);