summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java2
-rw-r--r--core/java/android/view/Choreographer.java380
-rw-r--r--core/java/android/view/View.java21
-rw-r--r--core/java/android/view/ViewRootImpl.java198
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java2
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;
}
}