Merge change 1747 into donut

* changes:
  Fixes #1846038. The dirty region can sometimes be modified by SurfaceFlinger. When this happens, force the view hierarchy to ignore the dirty flags.
This commit is contained in:
Android (Google) Code Review
2009-05-14 21:49:12 -07:00
4 changed files with 57 additions and 27 deletions

View File

@@ -1449,7 +1449,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
@ViewDebug.FlagToString(mask = LAYOUT_REQUIRED, equals = LAYOUT_REQUIRED, @ViewDebug.FlagToString(mask = LAYOUT_REQUIRED, equals = LAYOUT_REQUIRED,
name = "LAYOUT_REQUIRED"), name = "LAYOUT_REQUIRED"),
@ViewDebug.FlagToString(mask = DRAWING_CACHE_VALID, equals = DRAWING_CACHE_VALID, @ViewDebug.FlagToString(mask = DRAWING_CACHE_VALID, equals = DRAWING_CACHE_VALID,
name = "DRAWING_CACHE_VALID", outputIf = false), name = "DRAWING_CACHE_INVALID", outputIf = false),
@ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "DRAWN", outputIf = true), @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "DRAWN", outputIf = true),
@ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "NOT_DRAWN", outputIf = false), @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "NOT_DRAWN", outputIf = false),
@ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY_OPAQUE, name = "DIRTY_OPAQUE"),
@@ -5739,13 +5739,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
final int restoreCount = canvas.save(); final int restoreCount = canvas.save();
canvas.translate(-mScrollX, -mScrollY); canvas.translate(-mScrollX, -mScrollY);
mPrivateFlags = (mPrivateFlags & ~DIRTY_MASK) | DRAWN; mPrivateFlags |= DRAWN;
// Fast path for layouts with no backgrounds // Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
if (ViewDebug.TRACE_HIERARCHY) { if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
} }
mPrivateFlags &= ~DIRTY_MASK;
dispatchDraw(canvas); dispatchDraw(canvas);
} else { } else {
draw(canvas); draw(canvas);
@@ -5792,7 +5793,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
canvas = new Canvas(bitmap); canvas = new Canvas(bitmap);
} }
if ((backgroundColor&0xff000000) != 0) { if ((backgroundColor & 0xff000000) != 0) {
bitmap.eraseColor(backgroundColor); bitmap.eraseColor(backgroundColor);
} }
@@ -5800,6 +5801,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
final int restoreCount = canvas.save(); final int restoreCount = canvas.save();
canvas.translate(-mScrollX, -mScrollY); canvas.translate(-mScrollX, -mScrollY);
// Temporarily remove the dirty mask
int flags = mPrivateFlags;
mPrivateFlags &= ~DIRTY_MASK;
// Fast path for layouts with no backgrounds // Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
dispatchDraw(canvas); dispatchDraw(canvas);
@@ -5807,6 +5812,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
draw(canvas); draw(canvas);
} }
mPrivateFlags = flags;
canvas.restoreToCount(restoreCount); canvas.restoreToCount(restoreCount);
if (attachInfo != null) { if (attachInfo != null) {
@@ -5927,8 +5934,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
} }
final boolean dirtyOpaque = (mPrivateFlags & DIRTY_MASK) == DIRTY_OPAQUE; final int privateFlags = mPrivateFlags;
mPrivateFlags = (mPrivateFlags & ~DIRTY_MASK) | DRAWN; final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN;
/* /*
* Draw traversal performs several drawing steps which must be executed * Draw traversal performs several drawing steps which must be executed
@@ -8158,7 +8167,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* window. * window.
*/ */
static class AttachInfo { static class AttachInfo {
interface Callbacks { interface Callbacks {
void playSoundEffect(int effectId); void playSoundEffect(int effectId);
boolean performHapticFeedback(int effectId, boolean always); boolean performHapticFeedback(int effectId, boolean always);
@@ -8287,6 +8295,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/ */
long mDrawingTime; long mDrawingTime;
/**
* Indicates whether or not ignoring the DIRTY_MASK flags.
*/
boolean mIgnoreDirtyState;
/** /**
* Indicates whether the view's window is currently in touch mode. * Indicates whether the view's window is currently in touch mode.
*/ */

View File

@@ -1235,10 +1235,11 @@ public class ViewDebug {
for (int j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
final FlagToString flagMapping = mapping[j]; final FlagToString flagMapping = mapping[j];
final boolean ifTrue = flagMapping.outputIf(); final boolean ifTrue = flagMapping.outputIf();
final boolean test = (intValue & flagMapping.mask()) == flagMapping.equals(); final int maskResult = intValue & flagMapping.mask();
final boolean test = maskResult == flagMapping.equals();
if ((test && ifTrue) || (!test && !ifTrue)) { if ((test && ifTrue) || (!test && !ifTrue)) {
final String name = flagMapping.name(); final String name = flagMapping.name();
final String value = ifTrue ? "true" : "false"; final String value = "0x" + Integer.toHexString(maskResult);
writeEntry(out, prefix, name, "", value); writeEntry(out, prefix, name, "", value);
} }
} }

View File

@@ -1403,9 +1403,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
} }
} }
// Clear the flag as early as possible to allow draw() implementations // Sets the flag as early as possible to allow draw() implementations
// to call invalidate() successfully when doing animations // to call invalidate() successfully when doing animations
child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN; child.mPrivateFlags |= DRAWN;
if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) && if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
(child.mPrivateFlags & DRAW_ANIMATION) == 0) { (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
@@ -1482,6 +1482,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (ViewDebug.TRACE_HIERARCHY) { if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
} }
child.mPrivateFlags &= ~DIRTY_MASK;
child.dispatchDraw(canvas); child.dispatchDraw(canvas);
} else { } else {
child.draw(canvas); child.draw(canvas);

View File

@@ -537,7 +537,6 @@ public final class ViewRoot extends Handler implements ViewParent,
} }
dirty = mTempRect; dirty = mTempRect;
} }
// TODO: When doing a union with mDirty != empty, we must cancel all the DIRTY_OPAQUE flags
mDirty.union(dirty); mDirty.union(dirty);
if (!mWillDrawSoon) { if (!mWillDrawSoon) {
scheduleTraversals(); scheduleTraversals();
@@ -1142,8 +1141,7 @@ public final class ViewRoot extends Handler implements ViewParent,
} }
int yoff; int yoff;
final boolean scrolling = mScroller != null final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();
&& mScroller.computeScrollOffset();
if (scrolling) { if (scrolling) {
yoff = mScroller.getCurrY(); yoff = mScroller.getCurrY();
} else { } else {
@@ -1158,13 +1156,14 @@ public final class ViewRoot extends Handler implements ViewParent,
if (mUseGL) { if (mUseGL) {
if (!dirty.isEmpty()) { if (!dirty.isEmpty()) {
Canvas canvas = mGlCanvas; Canvas canvas = mGlCanvas;
if (mGL!=null && canvas != null) { if (mGL != null && canvas != null) {
mGL.glDisable(GL_SCISSOR_TEST); mGL.glDisable(GL_SCISSOR_TEST);
mGL.glClearColor(0, 0, 0, 0); mGL.glClearColor(0, 0, 0, 0);
mGL.glClear(GL_COLOR_BUFFER_BIT); mGL.glClear(GL_COLOR_BUFFER_BIT);
mGL.glEnable(GL_SCISSOR_TEST); mGL.glEnable(GL_SCISSOR_TEST);
mAttachInfo.mDrawingTime = SystemClock.uptimeMillis(); mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
mAttachInfo.mIgnoreDirtyState = true;
mView.mPrivateFlags |= View.DRAWN; mView.mPrivateFlags |= View.DRAWN;
float scale = mAppScale; float scale = mAppScale;
@@ -1182,6 +1181,8 @@ public final class ViewRoot extends Handler implements ViewParent,
canvas.restoreToCount(saveCount); canvas.restoreToCount(saveCount);
} }
mAttachInfo.mIgnoreDirtyState = false;
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface); mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
checkEglErrors(); checkEglErrors();
@@ -1201,8 +1202,10 @@ public final class ViewRoot extends Handler implements ViewParent,
return; return;
} }
if (fullRedrawNeeded) if (fullRedrawNeeded) {
mAttachInfo.mIgnoreDirtyState = true;
dirty.union(0, 0, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale)); dirty.union(0, 0, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
}
if (DEBUG_ORIENTATION || DEBUG_DRAW) { if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Log.v("ViewRoot", "Draw " + mView + "/" Log.v("ViewRoot", "Draw " + mView + "/"
@@ -1214,7 +1217,18 @@ public final class ViewRoot extends Handler implements ViewParent,
Canvas canvas; Canvas canvas;
try { try {
int left = dirty.left;
int top = dirty.top;
int right = dirty.right;
int bottom = dirty.bottom;
canvas = surface.lockCanvas(dirty); canvas = surface.lockCanvas(dirty);
if (left != dirty.left || top != dirty.top || right != dirty.right ||
bottom != dirty.bottom) {
mAttachInfo.mIgnoreDirtyState = true;
}
// TODO: Do this in native // TODO: Do this in native
canvas.setDensityScale(mDensity); canvas.setDensityScale(mDensity);
} catch (Surface.OutOfResourcesException e) { } catch (Surface.OutOfResourcesException e) {
@@ -1242,12 +1256,11 @@ public final class ViewRoot extends Handler implements ViewParent,
// need to clear it before drawing so that the child will // need to clear it before drawing so that the child will
// properly re-composite its drawing on a transparent // properly re-composite its drawing on a transparent
// background. This automatically respects the clip/dirty region // background. This automatically respects the clip/dirty region
if (!canvas.isOpaque()) { // or
canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); // If we are applying an offset, we need to clear the area
} else if (yoff != 0) { // where the offset doesn't appear to avoid having garbage
// If we are applying an offset, we need to clear the area // left in the blank areas.
// where the offset doesn't appear to avoid having garbage if (!canvas.isOpaque() || yoff != 0) {
// left in the blank areas.
canvas.drawColor(0, PorterDuff.Mode.CLEAR); canvas.drawColor(0, PorterDuff.Mode.CLEAR);
} }
@@ -1257,9 +1270,10 @@ public final class ViewRoot extends Handler implements ViewParent,
mView.mPrivateFlags |= View.DRAWN; mView.mPrivateFlags |= View.DRAWN;
float scale = mAppScale; float scale = mAppScale;
Context cxt = mView.getContext();
if (DEBUG_DRAW) { if (DEBUG_DRAW) {
Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + ", appScale=" + mAppScale); Context cxt = mView.getContext();
Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
", appScale=" + mAppScale);
} }
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try { try {
@@ -1269,14 +1283,15 @@ public final class ViewRoot extends Handler implements ViewParent,
canvas.scale(scale, scale); canvas.scale(scale, scale);
} }
mView.draw(canvas); mView.draw(canvas);
if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
}
} finally { } finally {
mAttachInfo.mIgnoreDirtyState = false;
canvas.restoreToCount(saveCount); canvas.restoreToCount(saveCount);
} }
if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
}
if (Config.DEBUG && ViewDebug.showFps) { if (Config.DEBUG && ViewDebug.showFps) {
int now = (int)SystemClock.elapsedRealtime(); int now = (int)SystemClock.elapsedRealtime();
if (sDrawTime != 0) { if (sDrawTime != 0) {