diff options
-rwxr-xr-x | core/java/android/animation/ValueAnimator.java | 2 | ||||
-rw-r--r-- | core/java/android/view/Choreographer.java | 380 | ||||
-rw-r--r-- | core/java/android/view/View.java | 21 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 198 | ||||
-rw-r--r-- | services/java/com/android/server/wm/WindowManagerService.java | 2 |
5 files changed, 295 insertions, 308 deletions
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index e2b8ce4..fade20c 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -647,7 +647,7 @@ public class ValueAnimator extends Animator { // onAnimate to process the next frame of the animations. if (!mAnimationScheduled && (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())) { - mChoreographer.postAnimationCallback(this, null); + mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null); mAnimationScheduled = true; } } diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index d217cab..1cb15a6 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -65,24 +65,22 @@ public final class Choreographer { } }; - // System property to enable/disable vsync for animations and drawing. - // Enabled by default. + // Enable/disable vsync for animations and drawing. private static final boolean USE_VSYNC = SystemProperties.getBoolean( "debug.choreographer.vsync", true); - // System property to enable/disable the use of the vsync / animation timer - // for drawing rather than drawing immediately. - // Temporarily disabled by default because postponing performTraversals() violates - // assumptions about traversals happening in-order relative to other posted messages. - // Bug: 5721047 - private static final boolean USE_ANIMATION_TIMER_FOR_DRAW = SystemProperties.getBoolean( - "debug.choreographer.animdraw", false); + // Enable/disable allowing traversals to proceed immediately if no drawing occurred + // during the previous frame. When true, the Choreographer can degrade more gracefully + // if drawing takes longer than a frame, but it may potentially block in eglSwapBuffers() + // if there are two dirty buffers enqueued. + // When false, we always schedule traversals on strict vsync boundaries. + private static final boolean USE_PIPELINING = SystemProperties.getBoolean( + "debug.choreographer.pipeline", false); - private static final int MSG_DO_ANIMATION = 0; - private static final int MSG_DO_DRAW = 1; - private static final int MSG_DO_SCHEDULE_VSYNC = 2; - private static final int MSG_DO_SCHEDULE_ANIMATION = 3; - private static final int MSG_DO_SCHEDULE_DRAW = 4; + private static final int MSG_DO_FRAME = 0; + private static final int MSG_DO_SCHEDULE_VSYNC = 1; + private static final int MSG_DO_SCHEDULE_CALLBACK = 2; + private static final int MSG_DO_TRAVERSAL = 3; private final Object mLock = new Object(); @@ -92,20 +90,41 @@ public final class Choreographer { private Callback mCallbackPool; - private final CallbackQueue mAnimationCallbackQueue = new CallbackQueue(); - private final CallbackQueue mDrawCallbackQueue = new CallbackQueue(); + private final CallbackQueue[] mCallbackQueues; - private boolean mAnimationScheduled; - private boolean mDrawScheduled; - private long mLastAnimationTime; - private long mLastDrawTime; + private boolean mFrameScheduled; + private long mLastFrameTime; + private boolean mDrewLastFrame; + private boolean mTraversalScheduled; + + /** + * Callback type: Input callback. Runs first. + */ + public static final int CALLBACK_INPUT = 0; + + /** + * Callback type: Animation callback. Runs before traversals. + */ + public static final int CALLBACK_ANIMATION = 1; + + /** + * Callback type: Traversal callback. Handles layout and draw. Runs last + * after all other asynchronous messages have been handled. + */ + public static final int CALLBACK_TRAVERSAL = 2; + + private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL; private Choreographer(Looper looper) { mLooper = looper; mHandler = new FrameHandler(looper); mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; - mLastAnimationTime = Long.MIN_VALUE; - mLastDrawTime = Long.MIN_VALUE; + mLastFrameTime = Long.MIN_VALUE; + + mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; + for (int i = 0; i <= CALLBACK_LAST; i++) { + mCallbackQueues[i] = new CallbackQueue(); + } } /** @@ -177,156 +196,142 @@ public final class Choreographer { } /** - * Posts a callback to run on the next animation cycle. + * Posts a callback to run on the next frame. * The callback only runs once and then is automatically removed. * - * @param action The callback action to run during the next animation cycle. + * @param callbackType The callback type. + * @param action The callback action to run during the next frame. * @param token The callback token, or null if none. * - * @see #removeAnimationCallback + * @see #removeCallbacks */ - public void postAnimationCallback(Runnable action, Object token) { - postAnimationCallbackDelayed(action, token, 0); + public void postCallback(int callbackType, Runnable action, Object token) { + postCallbackDelayed(callbackType, action, token, 0); } /** - * Posts a callback to run on the next animation cycle following the specified delay. + * Posts a callback to run on the next frame following the specified delay. * The callback only runs once and then is automatically removed. * - * @param action The callback action to run during the next animation cycle after - * the specified delay. + * @param callbackType The callback type. + * @param action The callback action to run during the next frame after the specified delay. * @param token The callback token, or null if none. * @param delayMillis The delay time in milliseconds. * - * @see #removeAnimationCallback + * @see #removeCallback */ - public void postAnimationCallbackDelayed(Runnable action, Object token, long delayMillis) { + public void postCallbackDelayed(int callbackType, + Runnable action, Object token, long delayMillis) { if (action == null) { throw new IllegalArgumentException("action must not be null"); } + if (callbackType < 0 || callbackType > CALLBACK_LAST) { + throw new IllegalArgumentException("callbackType is invalid"); + } if (DEBUG) { - Log.d(TAG, "PostAnimationCallback: " + action + ", token=" + token + Log.d(TAG, "PostCallback: type=" + callbackType + + ", action=" + action + ", token=" + token + ", delayMillis=" + delayMillis); } synchronized (mLock) { + if (USE_PIPELINING && callbackType == CALLBACK_INPUT) { + Message msg = Message.obtain(mHandler, action); + msg.setAsynchronous(true); + mHandler.sendMessage(msg); + return; + } + final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; - mAnimationCallbackQueue.addCallbackLocked(dueTime, action, token); + mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { - scheduleAnimationLocked(now); + if (USE_PIPELINING && callbackType == CALLBACK_TRAVERSAL) { + if (!mDrewLastFrame) { + if (DEBUG) { + Log.d(TAG, "Scheduling traversal immediately."); + } + if (!mTraversalScheduled) { + mTraversalScheduled = true; + Message msg = mHandler.obtainMessage(MSG_DO_TRAVERSAL); + msg.setAsynchronous(true); + mHandler.sendMessageAtTime(msg, dueTime); + } + return; + } + if (DEBUG) { + Log.d(TAG, "Scheduling traversal on next frame."); + } + } + scheduleFrameLocked(now); } else { - Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_ANIMATION, action); + Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); + msg.arg1 = callbackType; + msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, dueTime); } } } /** - * Removes animation callbacks that have the specified action and token. + * Removes callbacks that have the specified action and token. * + * @param callbackType The callback type. * @param action The action property of the callbacks to remove, or null to remove * callbacks with any action. * @param token The token property of the callbacks to remove, or null to remove * callbacks with any token. * - * @see #postAnimationCallback - * @see #postAnimationCallbackDelayed + * @see #postCallback + * @see #postCallbackDelayed */ - public void removeAnimationCallbacks(Runnable action, Object token) { - if (DEBUG) { - Log.d(TAG, "RemoveAnimationCallbacks: " + action + ", token=" + token); - } - - synchronized (mLock) { - mAnimationCallbackQueue.removeCallbacksLocked(action, token); - if (action != null && token == null) { - mHandler.removeMessages(MSG_DO_SCHEDULE_ANIMATION, action); - } - } - } - - /** - * Posts a callback to run on the next draw cycle. - * The callback only runs once and then is automatically removed. - * - * @param action The callback action to run during the next draw cycle. - * @param token The callback token, or null if none. - * - * @see #removeDrawCallback - */ - public void postDrawCallback(Runnable action, Object token) { - postDrawCallbackDelayed(action, token, 0); - } - - /** - * Posts a callback to run on the next draw cycle following the specified delay. - * The callback only runs once and then is automatically removed. - * - * @param action The callback action to run during the next animation cycle after - * the specified delay. - * @param token The callback token, or null if none. - * @param delayMillis The delay time in milliseconds. - * - * @see #removeDrawCallback - */ - public void postDrawCallbackDelayed(Runnable action, Object token, long delayMillis) { - if (action == null) { - throw new IllegalArgumentException("action must not be null"); + public void removeCallbacks(int callbackType, Runnable action, Object token) { + if (callbackType < 0 || callbackType > CALLBACK_LAST) { + throw new IllegalArgumentException("callbackType is invalid"); } if (DEBUG) { - Log.d(TAG, "PostDrawCallback: " + action + ", token=" + token - + ", delayMillis=" + delayMillis); + Log.d(TAG, "RemoveCallbacks: type=" + callbackType + + ", action=" + action + ", token=" + token); } synchronized (mLock) { - final long now = SystemClock.uptimeMillis(); - final long dueTime = now + delayMillis; - mDrawCallbackQueue.addCallbackLocked(dueTime, action, token); - scheduleDrawLocked(now); - - if (dueTime <= now) { - scheduleDrawLocked(now); - } else { - Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_DRAW, action); - mHandler.sendMessageAtTime(msg, dueTime); + mCallbackQueues[callbackType].removeCallbacksLocked(action, token); + if (action != null && token == null) { + mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action); } } } /** - * Removes draw callbacks that have the specified action and token. + * Tells the choreographer that the application has actually drawn to a surface. * - * @param action The action property of the callbacks to remove, or null to remove - * callbacks with any action. - * @param token The token property of the callbacks to remove, or null to remove - * callbacks with any token. - * - * @see #postDrawCallback - * @see #postDrawCallbackDelayed + * It uses this information to determine whether to draw immediately or to + * post a draw to the next vsync because it might otherwise block. */ - public void removeDrawCallbacks(Runnable action, Object token) { + public void notifyDrawOccurred() { if (DEBUG) { - Log.d(TAG, "RemoveDrawCallbacks: " + action + ", token=" + token); + Log.d(TAG, "Draw occurred."); } - synchronized (mLock) { - mDrawCallbackQueue.removeCallbacksLocked(action, token); - if (action != null && token == null) { - mHandler.removeMessages(MSG_DO_SCHEDULE_DRAW, action); + if (USE_PIPELINING) { + synchronized (mLock) { + if (!mDrewLastFrame) { + mDrewLastFrame = true; + scheduleFrameLocked(SystemClock.uptimeMillis()); + } } } } - private void scheduleAnimationLocked(long now) { - if (!mAnimationScheduled) { - mAnimationScheduled = true; + private void scheduleFrameLocked(long now) { + if (!mFrameScheduled) { + mFrameScheduled = true; if (USE_VSYNC) { if (DEBUG) { - Log.d(TAG, "Scheduling vsync for animation."); + Log.d(TAG, "Scheduling next frame on vsync."); } // If running on the Looper thread, then schedule the vsync immediately, @@ -340,125 +345,94 @@ public final class Choreographer { mHandler.sendMessageAtFrontOfQueue(msg); } } else { - final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); + final long nextFrameTime = Math.max(mLastFrameTime + sFrameDelay, now); if (DEBUG) { - Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); + Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); } - Message msg = mHandler.obtainMessage(MSG_DO_ANIMATION); + Message msg = mHandler.obtainMessage(MSG_DO_FRAME); msg.setAsynchronous(true); - mHandler.sendMessageAtTime(msg, nextAnimationTime); + mHandler.sendMessageAtTime(msg, nextFrameTime); } } } - private void scheduleDrawLocked(long now) { - if (!mDrawScheduled) { - mDrawScheduled = true; - if (USE_ANIMATION_TIMER_FOR_DRAW) { - scheduleAnimationLocked(now); - } else { - if (DEBUG) { - Log.d(TAG, "Scheduling draw immediately."); - } - Message msg = mHandler.obtainMessage(MSG_DO_DRAW); - msg.setAsynchronous(true); - mHandler.sendMessageAtTime(msg, now); - } - } - } - - void doAnimation() { - doAnimationInner(); - - if (USE_ANIMATION_TIMER_FOR_DRAW) { - doDraw(); - } - } - - void doAnimationInner() { - final long start; - Callback callbacks; + void doFrame(int frame) { synchronized (mLock) { - if (!mAnimationScheduled) { + if (!mFrameScheduled) { return; // no work to do } - mAnimationScheduled = false; - - start = SystemClock.uptimeMillis(); - if (DEBUG) { - Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime) - + " ms have elapsed since previous animation."); - } - mLastAnimationTime = start; - - callbacks = mAnimationCallbackQueue.extractDueCallbacksLocked(start); + mFrameScheduled = false; + mLastFrameTime = SystemClock.uptimeMillis(); + mDrewLastFrame = false; } - if (callbacks != null) { - runCallbacks(callbacks); - synchronized (mLock) { - recycleCallbacksLocked(callbacks); - } - } + doCallbacks(Choreographer.CALLBACK_INPUT); + doCallbacks(Choreographer.CALLBACK_ANIMATION); + doCallbacks(Choreographer.CALLBACK_TRAVERSAL); if (DEBUG) { - Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms."); + Log.d(TAG, "Frame " + frame + ": Finished, took " + + (SystemClock.uptimeMillis() - mLastFrameTime) + " ms."); } } - void doDraw() { + void doCallbacks(int callbackType) { final long start; Callback callbacks; synchronized (mLock) { - if (!mDrawScheduled) { - return; // no work to do - } - mDrawScheduled = false; - start = SystemClock.uptimeMillis(); - if (DEBUG) { - Log.d(TAG, "Performing draw: " + Math.max(0, start - mLastDrawTime) - + " ms have elapsed since previous draw."); - } - mLastDrawTime = start; + callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(start); - callbacks = mDrawCallbackQueue.extractDueCallbacksLocked(start); + if (USE_PIPELINING && callbackType == CALLBACK_TRAVERSAL && mTraversalScheduled) { + mTraversalScheduled = false; + mHandler.removeMessages(MSG_DO_TRAVERSAL); + } } if (callbacks != null) { - runCallbacks(callbacks); - synchronized (mLock) { - recycleCallbacksLocked(callbacks); + for (Callback c = callbacks; c != null; c = c.next) { + if (DEBUG) { + Log.d(TAG, "RunCallback: type=" + callbackType + + ", action=" + c.action + ", token=" + c.token + + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); + } + c.action.run(); } - } - if (DEBUG) { - Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms."); + synchronized (mLock) { + do { + final Callback next = callbacks.next; + recycleCallbackLocked(callbacks); + callbacks = next; + } while (callbacks != null); + } } } void doScheduleVsync() { synchronized (mLock) { - if (mAnimationScheduled) { + if (mFrameScheduled) { scheduleVsyncLocked(); } } } - void doScheduleAnimation() { + void doScheduleCallback(int callbackType) { synchronized (mLock) { - final long now = SystemClock.uptimeMillis(); - if (mAnimationCallbackQueue.hasDueCallbacksLocked(now)) { - scheduleAnimationLocked(now); + if (!mFrameScheduled) { + final long now = SystemClock.uptimeMillis(); + if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) { + scheduleFrameLocked(now); + } } } } - void doScheduleDraw() { + void doTraversal() { synchronized (mLock) { - final long now = SystemClock.uptimeMillis(); - if (mDrawCallbackQueue.hasDueCallbacksLocked(now)) { - scheduleDrawLocked(now); + if (mTraversalScheduled) { + mTraversalScheduled = false; + doCallbacks(CALLBACK_TRAVERSAL); } } } @@ -471,25 +445,6 @@ public final class Choreographer { return Looper.myLooper() == mLooper; } - private void runCallbacks(Callback head) { - while (head != null) { - if (DEBUG) { - Log.d(TAG, "RunCallback: " + head.action + ", token=" + head.token - + ", waitMillis=" + (SystemClock.uptimeMillis() - head.dueTime)); - } - head.action.run(); - head = head.next; - } - } - - private void recycleCallbacksLocked(Callback head) { - while (head != null) { - final Callback next = head.next; - recycleCallbackLocked(head); - head = next; - } - } - private Callback obtainCallbackLocked(long dueTime, Runnable action, Object token) { Callback callback = mCallbackPool; if (callback == null) { @@ -519,20 +474,17 @@ public final class Choreographer { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_DO_ANIMATION: - doAnimation(); - break; - case MSG_DO_DRAW: - doDraw(); + case MSG_DO_FRAME: + doFrame(0); break; case MSG_DO_SCHEDULE_VSYNC: doScheduleVsync(); break; - case MSG_DO_SCHEDULE_ANIMATION: - doScheduleAnimation(); + case MSG_DO_SCHEDULE_CALLBACK: + doScheduleCallback(msg.arg1); break; - case MSG_DO_SCHEDULE_DRAW: - doScheduleDraw(); + case MSG_DO_TRAVERSAL: + doTraversal(); break; } } @@ -545,7 +497,7 @@ public final class Choreographer { @Override public void onVsync(long timestampNanos, int frame) { - doAnimation(); + doFrame(frame); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 770d899..2ab27fc 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8981,7 +8981,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal public void postOnAnimation(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { - attachInfo.mViewRootImpl.mChoreographer.postAnimationCallback(action, null); + attachInfo.mViewRootImpl.mChoreographer.postCallback( + Choreographer.CALLBACK_ANIMATION, action, null); } else { // Assume that post will succeed later ViewRootImpl.getRunQueue().post(action); @@ -9005,8 +9006,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal public void postOnAnimationDelayed(Runnable action, long delayMillis) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { - attachInfo.mViewRootImpl.mChoreographer.postAnimationCallbackDelayed( - action, null, delayMillis); + attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( + Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); } else { // Assume that post will succeed later ViewRootImpl.getRunQueue().postDelayed(action, delayMillis); @@ -9031,7 +9032,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { attachInfo.mHandler.removeCallbacks(action); - attachInfo.mViewRootImpl.mChoreographer.removeAnimationCallbacks(action, null); + attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( + Choreographer.CALLBACK_ANIMATION, action, null); } else { // Assume that post will succeed later ViewRootImpl.getRunQueue().removeCallbacks(action); @@ -12226,8 +12228,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal if (verifyDrawable(who) && what != null) { final long delay = when - SystemClock.uptimeMillis(); if (mAttachInfo != null) { - mAttachInfo.mViewRootImpl.mChoreographer.postAnimationCallbackDelayed( - what, who, Choreographer.subtractFrameDelay(delay)); + mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( + Choreographer.CALLBACK_ANIMATION, what, who, + Choreographer.subtractFrameDelay(delay)); } else { ViewRootImpl.getRunQueue().postDelayed(what, delay); } @@ -12243,7 +12246,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal public void unscheduleDrawable(Drawable who, Runnable what) { if (verifyDrawable(who) && what != null) { if (mAttachInfo != null) { - mAttachInfo.mViewRootImpl.mChoreographer.removeAnimationCallbacks(what, who); + mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( + Choreographer.CALLBACK_ANIMATION, what, who); } else { ViewRootImpl.getRunQueue().removeCallbacks(what); } @@ -12261,7 +12265,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal */ public void unscheduleDrawable(Drawable who) { if (mAttachInfo != null && who != null) { - mAttachInfo.mViewRootImpl.mChoreographer.removeAnimationCallbacks(null, who); + mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( + Choreographer.CALLBACK_ANIMATION, null, who); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 14b8084..86f4226 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -877,50 +877,6 @@ public final class ViewRootImpl implements ViewParent, public void bringChildToFront(View child) { } - public void scheduleTraversals() { - if (!mTraversalScheduled) { - mTraversalScheduled = true; - mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); - scheduleFrame(); - } - } - - public void unscheduleTraversals() { - if (mTraversalScheduled) { - mTraversalScheduled = false; - mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); - } - } - - void scheduleFrame() { - if (!mFrameScheduled) { - mFrameScheduled = true; - mChoreographer.postDrawCallback(mFrameRunnable, null); - } - } - - void unscheduleFrame() { - unscheduleTraversals(); - - if (mFrameScheduled) { - mFrameScheduled = false; - mChoreographer.removeDrawCallbacks(mFrameRunnable, null); - } - } - - void doFrame() { - if (mInputEventReceiver != null) { - mInputEventReceiver.consumeBatchedInputEvents(); - } - doProcessInputEvents(); - - if (mTraversalScheduled) { - mTraversalScheduled = false; - mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); - doTraversal(); - } - } - int getHostVisibility() { return mAppVisible ? mView.getVisibility() : View.GONE; } @@ -954,41 +910,67 @@ public final class ViewRootImpl implements ViewParent, } } - private void doTraversal() { - if (mProfile) { - Debug.startMethodTracing("ViewAncestor"); + void scheduleTraversals() { + if (!mTraversalScheduled) { + mTraversalScheduled = true; + mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); + mChoreographer.postCallback( + Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); } + } - final long traversalStartTime; - if (ViewDebug.DEBUG_LATENCY) { - traversalStartTime = System.nanoTime(); - if (mLastTraversalFinishedTimeNanos != 0) { - Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals(); it has been " - + ((traversalStartTime - mLastTraversalFinishedTimeNanos) * 0.000001f) - + "ms since the last traversals finished."); - } else { - Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals()."); - } + void unscheduleTraversals() { + if (mTraversalScheduled) { + mTraversalScheduled = false; + mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); + mChoreographer.removeCallbacks( + Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); } + } - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals"); - try { - performTraversals(); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } + void doTraversal() { + if (mTraversalScheduled) { + mTraversalScheduled = false; + mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); - if (ViewDebug.DEBUG_LATENCY) { - long now = System.nanoTime(); - Log.d(ViewDebug.DEBUG_LATENCY_TAG, "performTraversals() took " - + ((now - traversalStartTime) * 0.000001f) - + "ms."); - mLastTraversalFinishedTimeNanos = now; - } + doConsumeBatchedInput(false); + doProcessInputEvents(); + + if (mProfile) { + Debug.startMethodTracing("ViewAncestor"); + } + + final long traversalStartTime; + if (ViewDebug.DEBUG_LATENCY) { + traversalStartTime = System.nanoTime(); + if (mLastTraversalFinishedTimeNanos != 0) { + Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals(); it has been " + + ((traversalStartTime - mLastTraversalFinishedTimeNanos) * 0.000001f) + + "ms since the last traversals finished."); + } else { + Log.d(ViewDebug.DEBUG_LATENCY_TAG, "Starting performTraversals()."); + } + } - if (mProfile) { - Debug.stopMethodTracing(); - mProfile = false; + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals"); + try { + performTraversals(); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + + if (ViewDebug.DEBUG_LATENCY) { + long now = System.nanoTime(); + Log.d(ViewDebug.DEBUG_LATENCY_TAG, "performTraversals() took " + + ((now - traversalStartTime) * 0.000001f) + + "ms."); + mLastTraversalFinishedTimeNanos = now; + } + + if (mProfile) { + Debug.stopMethodTracing(); + mProfile = false; + } } } @@ -1937,6 +1919,7 @@ public final class ViewRootImpl implements ViewParent, final boolean fullRedrawNeeded = mFullRedrawNeeded; mFullRedrawNeeded = false; + mChoreographer.notifyDrawOccurred(); Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); try { @@ -2460,7 +2443,7 @@ public final class ViewRootImpl implements ViewParent, mInputChannel = null; } - unscheduleFrame(); + unscheduleTraversals(); } void updateConfiguration(Configuration config, boolean force) { @@ -3837,6 +3820,7 @@ public final class ViewRootImpl implements ViewParent, Message msg = mHandler.obtainMessage(MSG_IME_FINISHED_EVENT); msg.arg1 = seq; msg.arg2 = handled ? 1 : 0; + msg.setAsynchronous(true); mHandler.sendMessage(msg); } @@ -3962,11 +3946,13 @@ public final class ViewRootImpl implements ViewParent, private void scheduleProcessInputEvents() { if (!mProcessInputEventsScheduled) { mProcessInputEventsScheduled = true; - mHandler.sendEmptyMessage(MSG_PROCESS_INPUT_EVENTS); + Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS); + msg.setAsynchronous(true); + mHandler.sendMessage(msg); } } - private void doProcessInputEvents() { + void doProcessInputEvents() { while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) { QueuedInputEvent q = mFirstPendingInputEvent; mFirstPendingInputEvent = q.mNext; @@ -4038,15 +4024,42 @@ public final class ViewRootImpl implements ViewParent, } } - final class FrameRunnable implements Runnable { + void scheduleConsumeBatchedInput() { + if (!mConsumeBatchedInputScheduled) { + mConsumeBatchedInputScheduled = true; + mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, + mConsumedBatchedInputRunnable, null); + } + } + + void unscheduleConsumeBatchedInput() { + if (mConsumeBatchedInputScheduled) { + mConsumeBatchedInputScheduled = false; + mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT, + mConsumedBatchedInputRunnable, null); + } + } + + void doConsumeBatchedInput(boolean callback) { + if (mConsumeBatchedInputScheduled) { + mConsumeBatchedInputScheduled = false; + if (!callback) { + mChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT, + mConsumedBatchedInputRunnable, null); + } + if (mInputEventReceiver != null) { + mInputEventReceiver.consumeBatchedInputEvents(); + } + } + } + + final class TraversalRunnable implements Runnable { @Override public void run() { - mFrameScheduled = false; - doFrame(); + doTraversal(); } } - final FrameRunnable mFrameRunnable = new FrameRunnable(); - boolean mFrameScheduled; + final TraversalRunnable mTraversalRunnable = new TraversalRunnable(); final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { @@ -4060,11 +4073,28 @@ public final class ViewRootImpl implements ViewParent, @Override public void onBatchedInputEventPending() { - scheduleFrame(); + scheduleConsumeBatchedInput(); + } + + @Override + public void dispose() { + unscheduleConsumeBatchedInput(); + super.dispose(); } } WindowInputEventReceiver mInputEventReceiver; + final class ConsumeBatchedInputRunnable implements Runnable { + @Override + public void run() { + doConsumeBatchedInput(true); + doProcessInputEvents(); + } + } + final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable = + new ConsumeBatchedInputRunnable(); + boolean mConsumeBatchedInputScheduled; + final class InvalidateOnAnimationRunnable implements Runnable { private boolean mPosted; private ArrayList<View> mViews = new ArrayList<View>(); @@ -4100,7 +4130,7 @@ public final class ViewRootImpl implements ViewParent, } if (mPosted && mViews.isEmpty() && mViewRects.isEmpty()) { - mChoreographer.removeAnimationCallbacks(this, null); + mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, this, null); mPosted = false; } } @@ -4141,7 +4171,7 @@ public final class ViewRootImpl implements ViewParent, private void postIfNeededLocked() { if (!mPosted) { - mChoreographer.postAnimationCallback(this, null); + mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null); mPosted = true; } } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index a978b35..03fce58 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -8749,7 +8749,7 @@ public class WindowManagerService extends IWindowManager.Stub void scheduleAnimationLocked() { if (!mAnimationScheduled) { - mChoreographer.postAnimationCallback(mAnimationRunnable, null); + mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationRunnable, null); mAnimationScheduled = true; } } |