Fix flashing artifacts caused by invalidation bugs
Therea re 2 fixes here:
- We sometimes cleared a flag in ViewAncestor too soon that controlled
how invalidated areas were redrawn (related to whether the invalidates
happened on opaque views or not).
- TransitionDrawable was always setting/restoring alpha values on its
drawables every time it was drawn. setAlpha on BitmapDrawable causes
an invalidation, so essentially this was an infinite invalidation/redrawing
loop. The fix was to notice when the animation was done and to simply
draw the appropriate drawable[s].
Change-Id: I1849a5a909b0039a0e9bce0aa3cfc33c50f8f854
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index afbedaf..ca11c70 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);
@@ -1748,7 +1753,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;
@@ -1878,9 +1883,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);