Loading core/java/android/animation/ValueAnimator.java +9 −15 Original line number Diff line number Diff line Loading @@ -522,8 +522,7 @@ public class ValueAnimator extends Animator { * animations possible. * */ private static class AnimationHandler extends Handler implements Choreographer.OnAnimateListener { private static class AnimationHandler extends Handler implements Runnable { // The per-thread list of all active animations private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>(); Loading @@ -539,7 +538,7 @@ public class ValueAnimator extends Animator { private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>(); private final Choreographer mChoreographer; private boolean mIsChoreographed; private boolean mAnimationScheduled; private AnimationHandler() { mChoreographer = Choreographer.getInstance(); Loading Loading @@ -644,22 +643,17 @@ public class ValueAnimator extends Animator { // If there are still active or delayed animations, schedule a future call to // onAnimate to process the next frame of the animations. if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) { if (!mIsChoreographed) { mIsChoreographed = true; mChoreographer.addOnAnimateListener(this); } mChoreographer.scheduleAnimation(); } else { if (mIsChoreographed) { mIsChoreographed = false; mChoreographer.removeOnAnimateListener(this); } if (!mAnimationScheduled && (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())) { mChoreographer.postAnimationCallback(this); mAnimationScheduled = true; } } // Called by the Choreographer. @Override public void onAnimate() { public void run() { mAnimationScheduled = false; doAnimationFrame(); } } Loading core/java/android/view/Choreographer.java +75 −244 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package android.view; import com.android.internal.util.ArrayUtils; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading @@ -28,8 +26,8 @@ import android.util.Log; /** * Coordinates animations and drawing for UI on a particular thread. * * This object is thread-safe. Other threads can add and remove listeners * or schedule work to occur at a later time on the UI thread. * This object is thread-safe. Other threads can post callbacks to run at a later time * on the UI thread. * * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver} * can only be accessed from the UI thread so operations that touch the event receiver Loading @@ -42,8 +40,8 @@ public final class Choreographer { private static final boolean DEBUG = false; // Amount of time in ms to wait before actually disposing of the display event // receiver after all listeners have been removed. private static final long DISPOSE_RECEIVER_DELAY = 200; // receiver when it has not been needed for some time. private static final long DISPOSE_RECEIVER_DELAY = 30 * 1000; // The default amount of time in ms between animation frames. // When vsync is not enabled, we want to have some idea of how long we should Loading Loading @@ -96,11 +94,8 @@ public final class Choreographer { private Callback mCallbackPool; private OnAnimateListener[] mOnAnimateListeners; private OnDrawListener[] mOnDrawListeners; private Callback mOnAnimateCallbacks; private Callback mOnDrawCallbacks; private Callback mAnimationCallbacks; private Callback mDrawCallbacks; private boolean mAnimationScheduled; private boolean mDrawScheduled; Loading Loading @@ -159,196 +154,21 @@ public final class Choreographer { sFrameDelay = frameDelay; } /** * Schedules animation (and drawing) to occur on the next frame synchronization boundary. */ public void scheduleAnimation() { synchronized (mLock) { scheduleAnimationLocked(false); } } private void scheduleAnimationLocked(boolean force) { if (!mAnimationScheduled && (force || mOnAnimateListeners != null || mOnAnimateCallbacks != null)) { mAnimationScheduled = true; if (USE_VSYNC) { if (DEBUG) { Log.d(TAG, "Scheduling vsync for animation."); } // If running on the Looper thread, then schedule the vsync immediately, // otherwise post a message to schedule the vsync from the UI thread // as soon as possible. if (!mFrameDisplayEventReceiverNeeded) { mFrameDisplayEventReceiverNeeded = true; if (mFrameDisplayEventReceiver != null) { mHandler.removeMessages(MSG_DO_DISPOSE_RECEIVER); } } if (isRunningOnLooperThreadLocked()) { doScheduleVsyncLocked(); } else { mHandler.sendMessageAtFrontOfQueue( mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC)); } } else { final long now = SystemClock.uptimeMillis(); final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); if (DEBUG) { Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); } mHandler.sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime); } } } /** * Returns true if {@link #scheduleAnimation()} has been called but * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has * not yet been called. */ public boolean isAnimationScheduled() { synchronized (mLock) { return mAnimationScheduled; } } /** * Schedules drawing to occur on the next frame synchronization boundary. * Must be called on the UI thread. */ public void scheduleDraw() { synchronized (mLock) { scheduleDrawLocked(); } } private void scheduleDrawLocked() { if (!mDrawScheduled && (mOnDrawListeners != null || mOnDrawCallbacks != null)) { mDrawScheduled = true; if (USE_ANIMATION_TIMER_FOR_DRAW) { scheduleAnimationLocked(true); } else { if (DEBUG) { Log.d(TAG, "Scheduling draw immediately."); } mHandler.sendEmptyMessage(MSG_DO_DRAW); } } } /** * Returns true if {@link #scheduleDraw()} has been called but * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has * not yet been called. */ public boolean isDrawScheduled() { synchronized (mLock) { return mDrawScheduled; } } /** * Adds an animation listener. * * @param listener The listener to add. */ public void addOnAnimateListener(OnAnimateListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } if (DEBUG) { Log.d(TAG, "Adding onAnimate listener: " + listener); } synchronized (mLock) { mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class, mOnAnimateListeners, listener); } } /** * Removes an animation listener. * * @param listener The listener to remove. */ public void removeOnAnimateListener(OnAnimateListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } if (DEBUG) { Log.d(TAG, "Removing onAnimate listener: " + listener); } synchronized (mLock) { mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class, mOnAnimateListeners, listener); stopTimingLoopIfNoListenersOrCallbacksLocked(); } } /** * Adds a draw listener. * * @param listener The listener to add. */ public void addOnDrawListener(OnDrawListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } if (DEBUG) { Log.d(TAG, "Adding onDraw listener: " + listener); } synchronized (mLock) { mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class, mOnDrawListeners, listener); } } /** * Removes a draw listener. * Must be called on the UI thread. * * @param listener The listener to remove. */ public void removeOnDrawListener(OnDrawListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } if (DEBUG) { Log.d(TAG, "Removing onDraw listener: " + listener); } synchronized (mLock) { mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class, mOnDrawListeners, listener); stopTimingLoopIfNoListenersOrCallbacksLocked(); } } /** * Posts a callback to run on the next animation cycle and schedules an animation cycle. * The callback only runs once and then is automatically removed. * * @param runnable The callback to run during the next animation cycle. * * @see #removeOnAnimateCallback * @see #removeAnimationCallback */ public void postOnAnimateCallback(Runnable runnable) { public void postAnimationCallback(Runnable runnable) { if (runnable == null) { throw new IllegalArgumentException("runnable must not be null"); } synchronized (mLock) { mOnAnimateCallbacks = addCallbackLocked(mOnAnimateCallbacks, runnable); scheduleAnimationLocked(false); mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, runnable); scheduleAnimationLocked(); } } Loading @@ -359,15 +179,15 @@ public final class Choreographer { * * @param runnable The animation callback to remove. * * @see #postOnAnimateCallback * @see #postAnimationCallback */ public void removeOnAnimateCallback(Runnable runnable) { public void removeAnimationCallback(Runnable runnable) { if (runnable == null) { throw new IllegalArgumentException("runnable must not be null"); } synchronized (mLock) { mOnAnimateCallbacks = removeCallbackLocked(mOnAnimateCallbacks, runnable); stopTimingLoopIfNoListenersOrCallbacksLocked(); mAnimationCallbacks = removeCallbackLocked(mAnimationCallbacks, runnable); stopTimingLoopIfNoCallbacksLocked(); } } Loading @@ -377,14 +197,14 @@ public final class Choreographer { * * @param runnable The callback to run during the next draw cycle. * * @see #removeOnDrawCallback * @see #removeDrawCallback */ public void postOnDrawCallback(Runnable runnable) { public void postDrawCallback(Runnable runnable) { if (runnable == null) { throw new IllegalArgumentException("runnable must not be null"); } synchronized (mLock) { mOnDrawCallbacks = addCallbackLocked(mOnDrawCallbacks, runnable); mDrawCallbacks = addCallbackLocked(mDrawCallbacks, runnable); scheduleDrawLocked(); } } Loading @@ -396,15 +216,63 @@ public final class Choreographer { * * @param runnable The draw callback to remove. * * @see #postOnDrawCallback * @see #postDrawCallback */ public void removeOnDrawCallback(Runnable runnable) { public void removeDrawCallback(Runnable runnable) { if (runnable == null) { throw new IllegalArgumentException("runnable must not be null"); } synchronized (mLock) { mOnDrawCallbacks = removeCallbackLocked(mOnDrawCallbacks, runnable); stopTimingLoopIfNoListenersOrCallbacksLocked(); mDrawCallbacks = removeCallbackLocked(mDrawCallbacks, runnable); stopTimingLoopIfNoCallbacksLocked(); } } private void scheduleAnimationLocked() { if (!mAnimationScheduled) { mAnimationScheduled = true; if (USE_VSYNC) { if (DEBUG) { Log.d(TAG, "Scheduling vsync for animation."); } // If running on the Looper thread, then schedule the vsync immediately, // otherwise post a message to schedule the vsync from the UI thread // as soon as possible. if (!mFrameDisplayEventReceiverNeeded) { mFrameDisplayEventReceiverNeeded = true; if (mFrameDisplayEventReceiver != null) { mHandler.removeMessages(MSG_DO_DISPOSE_RECEIVER); } } if (isRunningOnLooperThreadLocked()) { doScheduleVsyncLocked(); } else { mHandler.sendMessageAtFrontOfQueue( mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC)); } } else { final long now = SystemClock.uptimeMillis(); final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); if (DEBUG) { Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); } mHandler.sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime); } } } private void scheduleDrawLocked() { if (!mDrawScheduled) { mDrawScheduled = true; if (USE_ANIMATION_TIMER_FOR_DRAW) { scheduleAnimationLocked(); } else { if (DEBUG) { Log.d(TAG, "Scheduling draw immediately."); } mHandler.sendEmptyMessage(MSG_DO_DRAW); } } } Loading @@ -418,7 +286,6 @@ public final class Choreographer { void doAnimationInner() { final long start; final OnAnimateListener[] listeners; final Callback callbacks; synchronized (mLock) { if (!mAnimationScheduled) { Loading @@ -433,15 +300,8 @@ public final class Choreographer { } mLastAnimationTime = start; listeners = mOnAnimateListeners; callbacks = mOnAnimateCallbacks; mOnAnimateCallbacks = null; } if (listeners != null) { for (int i = 0; i < listeners.length; i++) { listeners[i].onAnimate(); } callbacks = mAnimationCallbacks; mAnimationCallbacks = null; } if (callbacks != null) { Loading @@ -458,7 +318,6 @@ public final class Choreographer { void doDraw() { final long start; final OnDrawListener[] listeners; final Callback callbacks; synchronized (mLock) { if (!mDrawScheduled) { Loading @@ -473,15 +332,8 @@ public final class Choreographer { } mLastDrawTime = start; listeners = mOnDrawListeners; callbacks = mOnDrawCallbacks; mOnDrawCallbacks = null; } if (listeners != null) { for (int i = 0; i < listeners.length; i++) { listeners[i].onDraw(); } callbacks = mDrawCallbacks; mDrawCallbacks = null; } if (callbacks != null) { Loading Loading @@ -520,9 +372,8 @@ public final class Choreographer { } } private void stopTimingLoopIfNoListenersOrCallbacksLocked() { if (mOnAnimateListeners == null && mOnDrawListeners == null && mOnAnimateCallbacks == null && mOnDrawCallbacks == null) { private void stopTimingLoopIfNoCallbacksLocked() { if (mAnimationCallbacks == null && mDrawCallbacks == null) { if (DEBUG) { Log.d(TAG, "Stopping timing loop."); } Loading Loading @@ -627,26 +478,6 @@ public final class Choreographer { mCallbackPool = callback; } /** * Listens for animation frame timing events. */ public static interface OnAnimateListener { /** * Called to animate properties before drawing the frame. */ public void onAnimate(); } /** * Listens for draw frame timing events. */ public static interface OnDrawListener { /** * Called to draw the frame. */ public void onDraw(); } private final class FrameHandler extends Handler { public FrameHandler(Looper looper) { super(looper); Loading core/java/android/view/ViewRootImpl.java +29 −9 Original line number Diff line number Diff line Loading @@ -97,8 +97,7 @@ import java.util.List; */ @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) public final class ViewRootImpl extends Handler implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks, Choreographer.OnDrawListener { View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { private static final String TAG = "ViewRootImpl"; private static final boolean DBG = false; private static final boolean LOCAL_LOGV = false; Loading Loading @@ -463,8 +462,6 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mChoreographer.addOnDrawListener(this); mView = view; mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); Loading Loading @@ -841,7 +838,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mChoreographer.scheduleDraw(); scheduleFrame(); } } Loading @@ -849,8 +846,21 @@ public final class ViewRootImpl extends Handler implements ViewParent, mTraversalScheduled = false; } @Override public void onDraw() { void scheduleFrame() { if (!mFrameScheduled) { mChoreographer.postDrawCallback(mFrameRunnable); mFrameScheduled = true; } } void unscheduleFrame() { if (mFrameScheduled) { mFrameScheduled = false; mChoreographer.removeDrawCallback(mFrameRunnable); } } void doFrame() { if (mInputEventReceiver != null) { mInputEventReceiver.consumeBatchedInputEvents(); } Loading Loading @@ -2376,7 +2386,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, mInputChannel = null; } mChoreographer.removeOnDrawListener(this); unscheduleFrame(); } void updateConfiguration(Configuration config, boolean force) { Loading Loading @@ -3923,6 +3933,16 @@ public final class ViewRootImpl extends Handler implements ViewParent, } } final class FrameRunnable implements Runnable { @Override public void run() { mFrameScheduled = false; doFrame(); } } final FrameRunnable mFrameRunnable = new FrameRunnable(); boolean mFrameScheduled; final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); Loading @@ -3935,7 +3955,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, @Override public void onBatchedInputEventPending() { mChoreographer.scheduleDraw(); scheduleFrame(); } } WindowInputEventReceiver mInputEventReceiver; Loading services/java/com/android/server/wm/WindowManagerService.java +21 −11 Original line number Diff line number Diff line Loading @@ -142,8 +142,7 @@ import java.util.List; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs, Choreographer.OnAnimateListener { implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { static final String TAG = "WindowManager"; static final boolean DEBUG = false; static final boolean DEBUG_ADD_REMOVE = false; Loading Loading @@ -603,6 +602,18 @@ public class WindowManagerService extends IWindowManager.Stub } private LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields(); private final class AnimationRunnable implements Runnable { @Override public void run() { synchronized(mWindowMap) { mAnimationScheduled = false; performLayoutAndPlaceSurfacesLocked(); } } } final AnimationRunnable mAnimationRunnable = new AnimationRunnable(); boolean mAnimationScheduled; final class DragInputEventReceiver extends InputEventReceiver { public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); Loading Loading @@ -724,7 +735,6 @@ public class WindowManagerService extends IWindowManager.Stub Looper.prepare(); WindowManagerService s = new WindowManagerService(mContext, mPM, mHaveInputMethods, mAllowBootMessages); s.mChoreographer.addOnAnimateListener(s); android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_DISPLAY); android.os.Process.setCanSelfBackground(false); Loading Loading @@ -5441,7 +5451,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mScreenRotationAnimation.setRotation(rotation, mFxSession, MAX_ANIMATION_DURATION, mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) { mChoreographer.scheduleAnimation(); scheduleAnimationLocked(); } } Surface.setOrientation(0, rotation); Loading Loading @@ -6882,7 +6892,7 @@ public class WindowManagerService extends IWindowManager.Stub case FORCE_GC: { synchronized(mWindowMap) { if (mChoreographer.isAnimationScheduled()) { if (mAnimationScheduled) { // If we are animating, don't do the gc now but // delay a bit so we don't interrupt the animation. mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), Loading Loading @@ -8980,7 +8990,7 @@ public class WindowManagerService extends IWindowManager.Stub if (needRelayout) { requestTraversalLocked(); } else if (mInnerFields.mAnimating) { mChoreographer.scheduleAnimation(); scheduleAnimationLocked(); } // Finally update all input windows now that the window changes have stabilized. Loading Loading @@ -9100,10 +9110,10 @@ public class WindowManagerService extends IWindowManager.Stub } } @Override public void onAnimate() { synchronized(mWindowMap) { performLayoutAndPlaceSurfacesLocked(); void scheduleAnimationLocked() { if (!mAnimationScheduled) { mChoreographer.postAnimationCallback(mAnimationRunnable); mAnimationScheduled = true; } } Loading Loading @@ -9423,7 +9433,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation"); if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION, mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) { mChoreographer.scheduleAnimation(); scheduleAnimationLocked(); } else { mScreenRotationAnimation = null; updateRotation = true; Loading services/java/com/android/server/wm/WindowState.java +2 −2 Original line number Diff line number Diff line Loading @@ -1593,7 +1593,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true); } if (requestAnim) { mService.mChoreographer.scheduleAnimation(); mService.scheduleAnimationLocked(); } return true; } Loading Loading @@ -1634,7 +1634,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } if (requestAnim) { mService.mChoreographer.scheduleAnimation(); mService.scheduleAnimationLocked(); } return true; } Loading Loading
core/java/android/animation/ValueAnimator.java +9 −15 Original line number Diff line number Diff line Loading @@ -522,8 +522,7 @@ public class ValueAnimator extends Animator { * animations possible. * */ private static class AnimationHandler extends Handler implements Choreographer.OnAnimateListener { private static class AnimationHandler extends Handler implements Runnable { // The per-thread list of all active animations private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>(); Loading @@ -539,7 +538,7 @@ public class ValueAnimator extends Animator { private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>(); private final Choreographer mChoreographer; private boolean mIsChoreographed; private boolean mAnimationScheduled; private AnimationHandler() { mChoreographer = Choreographer.getInstance(); Loading Loading @@ -644,22 +643,17 @@ public class ValueAnimator extends Animator { // If there are still active or delayed animations, schedule a future call to // onAnimate to process the next frame of the animations. if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) { if (!mIsChoreographed) { mIsChoreographed = true; mChoreographer.addOnAnimateListener(this); } mChoreographer.scheduleAnimation(); } else { if (mIsChoreographed) { mIsChoreographed = false; mChoreographer.removeOnAnimateListener(this); } if (!mAnimationScheduled && (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())) { mChoreographer.postAnimationCallback(this); mAnimationScheduled = true; } } // Called by the Choreographer. @Override public void onAnimate() { public void run() { mAnimationScheduled = false; doAnimationFrame(); } } Loading
core/java/android/view/Choreographer.java +75 −244 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package android.view; import com.android.internal.util.ArrayUtils; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading @@ -28,8 +26,8 @@ import android.util.Log; /** * Coordinates animations and drawing for UI on a particular thread. * * This object is thread-safe. Other threads can add and remove listeners * or schedule work to occur at a later time on the UI thread. * This object is thread-safe. Other threads can post callbacks to run at a later time * on the UI thread. * * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver} * can only be accessed from the UI thread so operations that touch the event receiver Loading @@ -42,8 +40,8 @@ public final class Choreographer { private static final boolean DEBUG = false; // Amount of time in ms to wait before actually disposing of the display event // receiver after all listeners have been removed. private static final long DISPOSE_RECEIVER_DELAY = 200; // receiver when it has not been needed for some time. private static final long DISPOSE_RECEIVER_DELAY = 30 * 1000; // The default amount of time in ms between animation frames. // When vsync is not enabled, we want to have some idea of how long we should Loading Loading @@ -96,11 +94,8 @@ public final class Choreographer { private Callback mCallbackPool; private OnAnimateListener[] mOnAnimateListeners; private OnDrawListener[] mOnDrawListeners; private Callback mOnAnimateCallbacks; private Callback mOnDrawCallbacks; private Callback mAnimationCallbacks; private Callback mDrawCallbacks; private boolean mAnimationScheduled; private boolean mDrawScheduled; Loading Loading @@ -159,196 +154,21 @@ public final class Choreographer { sFrameDelay = frameDelay; } /** * Schedules animation (and drawing) to occur on the next frame synchronization boundary. */ public void scheduleAnimation() { synchronized (mLock) { scheduleAnimationLocked(false); } } private void scheduleAnimationLocked(boolean force) { if (!mAnimationScheduled && (force || mOnAnimateListeners != null || mOnAnimateCallbacks != null)) { mAnimationScheduled = true; if (USE_VSYNC) { if (DEBUG) { Log.d(TAG, "Scheduling vsync for animation."); } // If running on the Looper thread, then schedule the vsync immediately, // otherwise post a message to schedule the vsync from the UI thread // as soon as possible. if (!mFrameDisplayEventReceiverNeeded) { mFrameDisplayEventReceiverNeeded = true; if (mFrameDisplayEventReceiver != null) { mHandler.removeMessages(MSG_DO_DISPOSE_RECEIVER); } } if (isRunningOnLooperThreadLocked()) { doScheduleVsyncLocked(); } else { mHandler.sendMessageAtFrontOfQueue( mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC)); } } else { final long now = SystemClock.uptimeMillis(); final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); if (DEBUG) { Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); } mHandler.sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime); } } } /** * Returns true if {@link #scheduleAnimation()} has been called but * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has * not yet been called. */ public boolean isAnimationScheduled() { synchronized (mLock) { return mAnimationScheduled; } } /** * Schedules drawing to occur on the next frame synchronization boundary. * Must be called on the UI thread. */ public void scheduleDraw() { synchronized (mLock) { scheduleDrawLocked(); } } private void scheduleDrawLocked() { if (!mDrawScheduled && (mOnDrawListeners != null || mOnDrawCallbacks != null)) { mDrawScheduled = true; if (USE_ANIMATION_TIMER_FOR_DRAW) { scheduleAnimationLocked(true); } else { if (DEBUG) { Log.d(TAG, "Scheduling draw immediately."); } mHandler.sendEmptyMessage(MSG_DO_DRAW); } } } /** * Returns true if {@link #scheduleDraw()} has been called but * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has * not yet been called. */ public boolean isDrawScheduled() { synchronized (mLock) { return mDrawScheduled; } } /** * Adds an animation listener. * * @param listener The listener to add. */ public void addOnAnimateListener(OnAnimateListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } if (DEBUG) { Log.d(TAG, "Adding onAnimate listener: " + listener); } synchronized (mLock) { mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class, mOnAnimateListeners, listener); } } /** * Removes an animation listener. * * @param listener The listener to remove. */ public void removeOnAnimateListener(OnAnimateListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } if (DEBUG) { Log.d(TAG, "Removing onAnimate listener: " + listener); } synchronized (mLock) { mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class, mOnAnimateListeners, listener); stopTimingLoopIfNoListenersOrCallbacksLocked(); } } /** * Adds a draw listener. * * @param listener The listener to add. */ public void addOnDrawListener(OnDrawListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } if (DEBUG) { Log.d(TAG, "Adding onDraw listener: " + listener); } synchronized (mLock) { mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class, mOnDrawListeners, listener); } } /** * Removes a draw listener. * Must be called on the UI thread. * * @param listener The listener to remove. */ public void removeOnDrawListener(OnDrawListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } if (DEBUG) { Log.d(TAG, "Removing onDraw listener: " + listener); } synchronized (mLock) { mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class, mOnDrawListeners, listener); stopTimingLoopIfNoListenersOrCallbacksLocked(); } } /** * Posts a callback to run on the next animation cycle and schedules an animation cycle. * The callback only runs once and then is automatically removed. * * @param runnable The callback to run during the next animation cycle. * * @see #removeOnAnimateCallback * @see #removeAnimationCallback */ public void postOnAnimateCallback(Runnable runnable) { public void postAnimationCallback(Runnable runnable) { if (runnable == null) { throw new IllegalArgumentException("runnable must not be null"); } synchronized (mLock) { mOnAnimateCallbacks = addCallbackLocked(mOnAnimateCallbacks, runnable); scheduleAnimationLocked(false); mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, runnable); scheduleAnimationLocked(); } } Loading @@ -359,15 +179,15 @@ public final class Choreographer { * * @param runnable The animation callback to remove. * * @see #postOnAnimateCallback * @see #postAnimationCallback */ public void removeOnAnimateCallback(Runnable runnable) { public void removeAnimationCallback(Runnable runnable) { if (runnable == null) { throw new IllegalArgumentException("runnable must not be null"); } synchronized (mLock) { mOnAnimateCallbacks = removeCallbackLocked(mOnAnimateCallbacks, runnable); stopTimingLoopIfNoListenersOrCallbacksLocked(); mAnimationCallbacks = removeCallbackLocked(mAnimationCallbacks, runnable); stopTimingLoopIfNoCallbacksLocked(); } } Loading @@ -377,14 +197,14 @@ public final class Choreographer { * * @param runnable The callback to run during the next draw cycle. * * @see #removeOnDrawCallback * @see #removeDrawCallback */ public void postOnDrawCallback(Runnable runnable) { public void postDrawCallback(Runnable runnable) { if (runnable == null) { throw new IllegalArgumentException("runnable must not be null"); } synchronized (mLock) { mOnDrawCallbacks = addCallbackLocked(mOnDrawCallbacks, runnable); mDrawCallbacks = addCallbackLocked(mDrawCallbacks, runnable); scheduleDrawLocked(); } } Loading @@ -396,15 +216,63 @@ public final class Choreographer { * * @param runnable The draw callback to remove. * * @see #postOnDrawCallback * @see #postDrawCallback */ public void removeOnDrawCallback(Runnable runnable) { public void removeDrawCallback(Runnable runnable) { if (runnable == null) { throw new IllegalArgumentException("runnable must not be null"); } synchronized (mLock) { mOnDrawCallbacks = removeCallbackLocked(mOnDrawCallbacks, runnable); stopTimingLoopIfNoListenersOrCallbacksLocked(); mDrawCallbacks = removeCallbackLocked(mDrawCallbacks, runnable); stopTimingLoopIfNoCallbacksLocked(); } } private void scheduleAnimationLocked() { if (!mAnimationScheduled) { mAnimationScheduled = true; if (USE_VSYNC) { if (DEBUG) { Log.d(TAG, "Scheduling vsync for animation."); } // If running on the Looper thread, then schedule the vsync immediately, // otherwise post a message to schedule the vsync from the UI thread // as soon as possible. if (!mFrameDisplayEventReceiverNeeded) { mFrameDisplayEventReceiverNeeded = true; if (mFrameDisplayEventReceiver != null) { mHandler.removeMessages(MSG_DO_DISPOSE_RECEIVER); } } if (isRunningOnLooperThreadLocked()) { doScheduleVsyncLocked(); } else { mHandler.sendMessageAtFrontOfQueue( mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC)); } } else { final long now = SystemClock.uptimeMillis(); final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); if (DEBUG) { Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); } mHandler.sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime); } } } private void scheduleDrawLocked() { if (!mDrawScheduled) { mDrawScheduled = true; if (USE_ANIMATION_TIMER_FOR_DRAW) { scheduleAnimationLocked(); } else { if (DEBUG) { Log.d(TAG, "Scheduling draw immediately."); } mHandler.sendEmptyMessage(MSG_DO_DRAW); } } } Loading @@ -418,7 +286,6 @@ public final class Choreographer { void doAnimationInner() { final long start; final OnAnimateListener[] listeners; final Callback callbacks; synchronized (mLock) { if (!mAnimationScheduled) { Loading @@ -433,15 +300,8 @@ public final class Choreographer { } mLastAnimationTime = start; listeners = mOnAnimateListeners; callbacks = mOnAnimateCallbacks; mOnAnimateCallbacks = null; } if (listeners != null) { for (int i = 0; i < listeners.length; i++) { listeners[i].onAnimate(); } callbacks = mAnimationCallbacks; mAnimationCallbacks = null; } if (callbacks != null) { Loading @@ -458,7 +318,6 @@ public final class Choreographer { void doDraw() { final long start; final OnDrawListener[] listeners; final Callback callbacks; synchronized (mLock) { if (!mDrawScheduled) { Loading @@ -473,15 +332,8 @@ public final class Choreographer { } mLastDrawTime = start; listeners = mOnDrawListeners; callbacks = mOnDrawCallbacks; mOnDrawCallbacks = null; } if (listeners != null) { for (int i = 0; i < listeners.length; i++) { listeners[i].onDraw(); } callbacks = mDrawCallbacks; mDrawCallbacks = null; } if (callbacks != null) { Loading Loading @@ -520,9 +372,8 @@ public final class Choreographer { } } private void stopTimingLoopIfNoListenersOrCallbacksLocked() { if (mOnAnimateListeners == null && mOnDrawListeners == null && mOnAnimateCallbacks == null && mOnDrawCallbacks == null) { private void stopTimingLoopIfNoCallbacksLocked() { if (mAnimationCallbacks == null && mDrawCallbacks == null) { if (DEBUG) { Log.d(TAG, "Stopping timing loop."); } Loading Loading @@ -627,26 +478,6 @@ public final class Choreographer { mCallbackPool = callback; } /** * Listens for animation frame timing events. */ public static interface OnAnimateListener { /** * Called to animate properties before drawing the frame. */ public void onAnimate(); } /** * Listens for draw frame timing events. */ public static interface OnDrawListener { /** * Called to draw the frame. */ public void onDraw(); } private final class FrameHandler extends Handler { public FrameHandler(Looper looper) { super(looper); Loading
core/java/android/view/ViewRootImpl.java +29 −9 Original line number Diff line number Diff line Loading @@ -97,8 +97,7 @@ import java.util.List; */ @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) public final class ViewRootImpl extends Handler implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks, Choreographer.OnDrawListener { View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { private static final String TAG = "ViewRootImpl"; private static final boolean DBG = false; private static final boolean LOCAL_LOGV = false; Loading Loading @@ -463,8 +462,6 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mChoreographer.addOnDrawListener(this); mView = view; mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); Loading Loading @@ -841,7 +838,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mChoreographer.scheduleDraw(); scheduleFrame(); } } Loading @@ -849,8 +846,21 @@ public final class ViewRootImpl extends Handler implements ViewParent, mTraversalScheduled = false; } @Override public void onDraw() { void scheduleFrame() { if (!mFrameScheduled) { mChoreographer.postDrawCallback(mFrameRunnable); mFrameScheduled = true; } } void unscheduleFrame() { if (mFrameScheduled) { mFrameScheduled = false; mChoreographer.removeDrawCallback(mFrameRunnable); } } void doFrame() { if (mInputEventReceiver != null) { mInputEventReceiver.consumeBatchedInputEvents(); } Loading Loading @@ -2376,7 +2386,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, mInputChannel = null; } mChoreographer.removeOnDrawListener(this); unscheduleFrame(); } void updateConfiguration(Configuration config, boolean force) { Loading Loading @@ -3923,6 +3933,16 @@ public final class ViewRootImpl extends Handler implements ViewParent, } } final class FrameRunnable implements Runnable { @Override public void run() { mFrameScheduled = false; doFrame(); } } final FrameRunnable mFrameRunnable = new FrameRunnable(); boolean mFrameScheduled; final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); Loading @@ -3935,7 +3955,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, @Override public void onBatchedInputEventPending() { mChoreographer.scheduleDraw(); scheduleFrame(); } } WindowInputEventReceiver mInputEventReceiver; Loading
services/java/com/android/server/wm/WindowManagerService.java +21 −11 Original line number Diff line number Diff line Loading @@ -142,8 +142,7 @@ import java.util.List; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs, Choreographer.OnAnimateListener { implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { static final String TAG = "WindowManager"; static final boolean DEBUG = false; static final boolean DEBUG_ADD_REMOVE = false; Loading Loading @@ -603,6 +602,18 @@ public class WindowManagerService extends IWindowManager.Stub } private LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields(); private final class AnimationRunnable implements Runnable { @Override public void run() { synchronized(mWindowMap) { mAnimationScheduled = false; performLayoutAndPlaceSurfacesLocked(); } } } final AnimationRunnable mAnimationRunnable = new AnimationRunnable(); boolean mAnimationScheduled; final class DragInputEventReceiver extends InputEventReceiver { public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); Loading Loading @@ -724,7 +735,6 @@ public class WindowManagerService extends IWindowManager.Stub Looper.prepare(); WindowManagerService s = new WindowManagerService(mContext, mPM, mHaveInputMethods, mAllowBootMessages); s.mChoreographer.addOnAnimateListener(s); android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_DISPLAY); android.os.Process.setCanSelfBackground(false); Loading Loading @@ -5441,7 +5451,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mScreenRotationAnimation.setRotation(rotation, mFxSession, MAX_ANIMATION_DURATION, mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) { mChoreographer.scheduleAnimation(); scheduleAnimationLocked(); } } Surface.setOrientation(0, rotation); Loading Loading @@ -6882,7 +6892,7 @@ public class WindowManagerService extends IWindowManager.Stub case FORCE_GC: { synchronized(mWindowMap) { if (mChoreographer.isAnimationScheduled()) { if (mAnimationScheduled) { // If we are animating, don't do the gc now but // delay a bit so we don't interrupt the animation. mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), Loading Loading @@ -8980,7 +8990,7 @@ public class WindowManagerService extends IWindowManager.Stub if (needRelayout) { requestTraversalLocked(); } else if (mInnerFields.mAnimating) { mChoreographer.scheduleAnimation(); scheduleAnimationLocked(); } // Finally update all input windows now that the window changes have stabilized. Loading Loading @@ -9100,10 +9110,10 @@ public class WindowManagerService extends IWindowManager.Stub } } @Override public void onAnimate() { synchronized(mWindowMap) { performLayoutAndPlaceSurfacesLocked(); void scheduleAnimationLocked() { if (!mAnimationScheduled) { mChoreographer.postAnimationCallback(mAnimationRunnable); mAnimationScheduled = true; } } Loading Loading @@ -9423,7 +9433,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation"); if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION, mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) { mChoreographer.scheduleAnimation(); scheduleAnimationLocked(); } else { mScreenRotationAnimation = null; updateRotation = true; Loading
services/java/com/android/server/wm/WindowState.java +2 −2 Original line number Diff line number Diff line Loading @@ -1593,7 +1593,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true); } if (requestAnim) { mService.mChoreographer.scheduleAnimation(); mService.scheduleAnimationLocked(); } return true; } Loading Loading @@ -1634,7 +1634,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } if (requestAnim) { mService.mChoreographer.scheduleAnimation(); mService.scheduleAnimationLocked(); } return true; } Loading