Skip to content

Commit a393bed

Browse files
Romain GuyAndroid (Google) Code Review
authored andcommitted
Merge "Add a new OnDrawListener to ViewRoot"
2 parents 7bf1ebd + 25eba5c commit a393bed

File tree

3 files changed

+246
-157
lines changed

3 files changed

+246
-157
lines changed

api/current.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24148,22 +24148,29 @@ package android.view {
2414824148
}
2414924149

2415024150
public final class ViewTreeObserver {
24151+
method public void addOnDrawListener(android.view.ViewTreeObserver.OnDrawListener);
2415124152
method public void addOnGlobalFocusChangeListener(android.view.ViewTreeObserver.OnGlobalFocusChangeListener);
2415224153
method public void addOnGlobalLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
2415324154
method public void addOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
2415424155
method public void addOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
2415524156
method public void addOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
24157+
method public final void dispatchOnDraw();
2415624158
method public final void dispatchOnGlobalLayout();
2415724159
method public final boolean dispatchOnPreDraw();
2415824160
method public boolean isAlive();
2415924161
method public deprecated void removeGlobalOnLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
24162+
method public void removeOnDrawListener(android.view.ViewTreeObserver.OnDrawListener);
2416024163
method public void removeOnGlobalFocusChangeListener(android.view.ViewTreeObserver.OnGlobalFocusChangeListener);
2416124164
method public void removeOnGlobalLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
2416224165
method public void removeOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
2416324166
method public void removeOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
2416424167
method public void removeOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
2416524168
}
2416624169

24170+
public static abstract interface ViewTreeObserver.OnDrawListener {
24171+
method public abstract void onDraw();
24172+
}
24173+
2416724174
public static abstract interface ViewTreeObserver.OnGlobalFocusChangeListener {
2416824175
method public abstract void onGlobalFocusChanged(android.view.View, android.view.View);
2416924176
}

core/java/android/view/ViewRootImpl.java

Lines changed: 145 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,9 +2039,10 @@ private void draw(boolean fullRedrawNeeded) {
20392039

20402040
scrollToRectOrFocus(null, false);
20412041

2042-
if (mAttachInfo.mViewScrollChanged) {
2043-
mAttachInfo.mViewScrollChanged = false;
2044-
mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
2042+
final AttachInfo attachInfo = mAttachInfo;
2043+
if (attachInfo.mViewScrollChanged) {
2044+
attachInfo.mViewScrollChanged = false;
2045+
attachInfo.mTreeObserver.dispatchOnScrollChanged();
20452046
}
20462047

20472048
int yoff;
@@ -2056,8 +2057,8 @@ private void draw(boolean fullRedrawNeeded) {
20562057
fullRedrawNeeded = true;
20572058
}
20582059

2059-
final float appScale = mAttachInfo.mApplicationScale;
2060-
final boolean scalingRequired = mAttachInfo.mScalingRequired;
2060+
final float appScale = attachInfo.mApplicationScale;
2061+
final boolean scalingRequired = attachInfo.mScalingRequired;
20612062

20622063
int resizeAlpha = 0;
20632064
if (mResizeBuffer != null) {
@@ -2086,7 +2087,7 @@ private void draw(boolean fullRedrawNeeded) {
20862087
}
20872088

20882089
if (fullRedrawNeeded) {
2089-
mAttachInfo.mIgnoreDirtyState = true;
2090+
attachInfo.mIgnoreDirtyState = true;
20902091
dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
20912092
}
20922093

@@ -2099,8 +2100,10 @@ private void draw(boolean fullRedrawNeeded) {
20992100
appScale + ", width=" + mWidth + ", height=" + mHeight);
21002101
}
21012102

2103+
attachInfo.mTreeObserver.dispatchOnDraw();
2104+
21022105
if (!dirty.isEmpty() || mIsAnimating) {
2103-
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
2106+
if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
21042107
// Draw with hardware renderer.
21052108
mIsAnimating = false;
21062109
mHardwareYOffset = yoff;
@@ -2111,154 +2114,164 @@ private void draw(boolean fullRedrawNeeded) {
21112114
mPreviousDirty.set(dirty);
21122115
dirty.setEmpty();
21132116

2114-
if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this,
2117+
if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
21152118
animating ? null : mCurrentDirty)) {
21162119
mPreviousDirty.set(0, 0, mWidth, mHeight);
21172120
}
2118-
} else {
2119-
// Draw with software renderer.
2120-
Canvas canvas;
2121-
try {
2122-
int left = dirty.left;
2123-
int top = dirty.top;
2124-
int right = dirty.right;
2125-
int bottom = dirty.bottom;
2126-
2127-
final long lockCanvasStartTime;
2128-
if (ViewDebug.DEBUG_LATENCY) {
2129-
lockCanvasStartTime = System.nanoTime();
2130-
}
2131-
2132-
canvas = mSurface.lockCanvas(dirty);
2121+
} else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
2122+
return;
2123+
}
2124+
}
21332125

2134-
if (ViewDebug.DEBUG_LATENCY) {
2135-
long now = System.nanoTime();
2136-
Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- lockCanvas() took "
2137-
+ ((now - lockCanvasStartTime) * 0.000001f) + "ms");
2138-
}
2126+
if (animating) {
2127+
mFullRedrawNeeded = true;
2128+
scheduleTraversals();
2129+
}
2130+
}
21392131

2140-
if (left != dirty.left || top != dirty.top || right != dirty.right ||
2141-
bottom != dirty.bottom) {
2142-
mAttachInfo.mIgnoreDirtyState = true;
2143-
}
2132+
/**
2133+
* @return true if drawing was succesful, false if an error occured
2134+
*/
2135+
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
2136+
boolean scalingRequired, Rect dirty) {
21442137

2145-
// TODO: Do this in native
2146-
canvas.setDensity(mDensity);
2147-
} catch (Surface.OutOfResourcesException e) {
2148-
Log.e(TAG, "OutOfResourcesException locking surface", e);
2149-
try {
2150-
if (!sWindowSession.outOfMemory(mWindow)) {
2151-
Slog.w(TAG, "No processes killed for memory; killing self");
2152-
Process.killProcess(Process.myPid());
2153-
}
2154-
} catch (RemoteException ex) {
2155-
}
2156-
mLayoutRequested = true; // ask wm for a new surface next time.
2157-
return;
2158-
} catch (IllegalArgumentException e) {
2159-
Log.e(TAG, "IllegalArgumentException locking surface", e);
2160-
// Don't assume this is due to out of memory, it could be
2161-
// something else, and if it is something else then we could
2162-
// kill stuff (or ourself) for no reason.
2163-
mLayoutRequested = true; // ask wm for a new surface next time.
2164-
return;
2165-
}
2138+
// Draw with software renderer.
2139+
Canvas canvas;
2140+
try {
2141+
int left = dirty.left;
2142+
int top = dirty.top;
2143+
int right = dirty.right;
2144+
int bottom = dirty.bottom;
21662145

2167-
try {
2168-
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2169-
Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2170-
+ canvas.getWidth() + ", h=" + canvas.getHeight());
2171-
//canvas.drawARGB(255, 255, 0, 0);
2172-
}
2146+
final long lockCanvasStartTime;
2147+
if (ViewDebug.DEBUG_LATENCY) {
2148+
lockCanvasStartTime = System.nanoTime();
2149+
}
21732150

2174-
long startTime = 0L;
2175-
if (ViewDebug.DEBUG_PROFILE_DRAWING) {
2176-
startTime = SystemClock.elapsedRealtime();
2177-
}
2151+
canvas = mSurface.lockCanvas(dirty);
21782152

2179-
// If this bitmap's format includes an alpha channel, we
2180-
// need to clear it before drawing so that the child will
2181-
// properly re-composite its drawing on a transparent
2182-
// background. This automatically respects the clip/dirty region
2183-
// or
2184-
// If we are applying an offset, we need to clear the area
2185-
// where the offset doesn't appear to avoid having garbage
2186-
// left in the blank areas.
2187-
if (!canvas.isOpaque() || yoff != 0) {
2188-
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2189-
}
2153+
if (ViewDebug.DEBUG_LATENCY) {
2154+
long now = System.nanoTime();
2155+
Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- lockCanvas() took "
2156+
+ ((now - lockCanvasStartTime) * 0.000001f) + "ms");
2157+
}
21902158

2191-
dirty.setEmpty();
2192-
mIsAnimating = false;
2193-
mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
2194-
mView.mPrivateFlags |= View.DRAWN;
2159+
if (left != dirty.left || top != dirty.top || right != dirty.right ||
2160+
bottom != dirty.bottom) {
2161+
attachInfo.mIgnoreDirtyState = true;
2162+
}
21952163

2196-
if (DEBUG_DRAW) {
2197-
Context cxt = mView.getContext();
2198-
Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2199-
", metrics=" + cxt.getResources().getDisplayMetrics() +
2200-
", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2201-
}
2202-
try {
2203-
canvas.translate(0, -yoff);
2204-
if (mTranslator != null) {
2205-
mTranslator.translateCanvas(canvas);
2206-
}
2207-
canvas.setScreenDensity(scalingRequired
2208-
? DisplayMetrics.DENSITY_DEVICE : 0);
2209-
mAttachInfo.mSetIgnoreDirtyState = false;
2164+
// TODO: Do this in native
2165+
canvas.setDensity(mDensity);
2166+
} catch (Surface.OutOfResourcesException e) {
2167+
Log.e(TAG, "OutOfResourcesException locking surface", e);
2168+
try {
2169+
if (!sWindowSession.outOfMemory(mWindow)) {
2170+
Slog.w(TAG, "No processes killed for memory; killing self");
2171+
Process.killProcess(Process.myPid());
2172+
}
2173+
} catch (RemoteException ex) {
2174+
}
2175+
mLayoutRequested = true; // ask wm for a new surface next time.
2176+
return false;
2177+
} catch (IllegalArgumentException e) {
2178+
Log.e(TAG, "IllegalArgumentException locking surface", e);
2179+
// Don't assume this is due to out of memory, it could be
2180+
// something else, and if it is something else then we could
2181+
// kill stuff (or ourself) for no reason.
2182+
mLayoutRequested = true; // ask wm for a new surface next time.
2183+
return false;
2184+
}
22102185

2211-
final long drawStartTime;
2212-
if (ViewDebug.DEBUG_LATENCY) {
2213-
drawStartTime = System.nanoTime();
2214-
}
2186+
try {
2187+
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
2188+
Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
2189+
+ canvas.getWidth() + ", h=" + canvas.getHeight());
2190+
//canvas.drawARGB(255, 255, 0, 0);
2191+
}
22152192

2216-
mView.draw(canvas);
2193+
long startTime = 0L;
2194+
if (ViewDebug.DEBUG_PROFILE_DRAWING) {
2195+
startTime = SystemClock.elapsedRealtime();
2196+
}
22172197

2218-
if (ViewDebug.DEBUG_LATENCY) {
2219-
long now = System.nanoTime();
2220-
Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- draw() took "
2221-
+ ((now - drawStartTime) * 0.000001f) + "ms");
2222-
}
2223-
} finally {
2224-
if (!mAttachInfo.mSetIgnoreDirtyState) {
2225-
// Only clear the flag if it was not set during the mView.draw() call
2226-
mAttachInfo.mIgnoreDirtyState = false;
2227-
}
2228-
}
2198+
// If this bitmap's format includes an alpha channel, we
2199+
// need to clear it before drawing so that the child will
2200+
// properly re-composite its drawing on a transparent
2201+
// background. This automatically respects the clip/dirty region
2202+
// or
2203+
// If we are applying an offset, we need to clear the area
2204+
// where the offset doesn't appear to avoid having garbage
2205+
// left in the blank areas.
2206+
if (!canvas.isOpaque() || yoff != 0) {
2207+
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
2208+
}
22292209

2230-
if (false && ViewDebug.consistencyCheckEnabled) {
2231-
mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
2232-
}
2210+
dirty.setEmpty();
2211+
mIsAnimating = false;
2212+
attachInfo.mDrawingTime = SystemClock.uptimeMillis();
2213+
mView.mPrivateFlags |= View.DRAWN;
22332214

2234-
if (ViewDebug.DEBUG_PROFILE_DRAWING) {
2235-
EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
2236-
}
2237-
} finally {
2238-
final long unlockCanvasAndPostStartTime;
2239-
if (ViewDebug.DEBUG_LATENCY) {
2240-
unlockCanvasAndPostStartTime = System.nanoTime();
2241-
}
2215+
if (DEBUG_DRAW) {
2216+
Context cxt = mView.getContext();
2217+
Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
2218+
", metrics=" + cxt.getResources().getDisplayMetrics() +
2219+
", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
2220+
}
2221+
try {
2222+
canvas.translate(0, -yoff);
2223+
if (mTranslator != null) {
2224+
mTranslator.translateCanvas(canvas);
2225+
}
2226+
canvas.setScreenDensity(scalingRequired
2227+
? DisplayMetrics.DENSITY_DEVICE : 0);
2228+
attachInfo.mSetIgnoreDirtyState = false;
22422229

2243-
surface.unlockCanvasAndPost(canvas);
2230+
final long drawStartTime;
2231+
if (ViewDebug.DEBUG_LATENCY) {
2232+
drawStartTime = System.nanoTime();
2233+
}
22442234

2245-
if (ViewDebug.DEBUG_LATENCY) {
2246-
long now = System.nanoTime();
2247-
Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- unlockCanvasAndPost() took "
2248-
+ ((now - unlockCanvasAndPostStartTime) * 0.000001f) + "ms");
2249-
}
2235+
mView.draw(canvas);
22502236

2251-
if (LOCAL_LOGV) {
2252-
Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2253-
}
2237+
if (ViewDebug.DEBUG_LATENCY) {
2238+
long now = System.nanoTime();
2239+
Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- draw() took "
2240+
+ ((now - drawStartTime) * 0.000001f) + "ms");
2241+
}
2242+
} finally {
2243+
if (!attachInfo.mSetIgnoreDirtyState) {
2244+
// Only clear the flag if it was not set during the mView.draw() call
2245+
attachInfo.mIgnoreDirtyState = false;
22542246
}
22552247
}
2256-
}
22572248

2258-
if (animating) {
2259-
mFullRedrawNeeded = true;
2260-
scheduleTraversals();
2249+
if (false && ViewDebug.consistencyCheckEnabled) {
2250+
mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
2251+
}
2252+
2253+
if (ViewDebug.DEBUG_PROFILE_DRAWING) {
2254+
EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
2255+
}
2256+
} finally {
2257+
final long unlockCanvasAndPostStartTime;
2258+
if (ViewDebug.DEBUG_LATENCY) {
2259+
unlockCanvasAndPostStartTime = System.nanoTime();
2260+
}
2261+
2262+
surface.unlockCanvasAndPost(canvas);
2263+
2264+
if (ViewDebug.DEBUG_LATENCY) {
2265+
long now = System.nanoTime();
2266+
Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- unlockCanvasAndPost() took "
2267+
+ ((now - unlockCanvasAndPostStartTime) * 0.000001f) + "ms");
2268+
}
2269+
2270+
if (LOCAL_LOGV) {
2271+
Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
2272+
}
22612273
}
2274+
return true;
22622275
}
22632276

22642277
void invalidateDisplayLists() {

0 commit comments

Comments
 (0)