summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-02-15 15:06:01 -0800
committerJeff Brown <jeffbrown@google.com>2012-02-15 15:06:01 -0800
commit4a06c8008b2edd6677f9a411af79b0a4971b87fe (patch)
treece3bca001e3f2a7778d39be2cb5049f7b1620e16 /core
parentfef3d62b16bccd9ef7a32c2e1da94f694b34c405 (diff)
downloadframeworks_base-4a06c8008b2edd6677f9a411af79b0a4971b87fe.zip
frameworks_base-4a06c8008b2edd6677f9a411af79b0a4971b87fe.tar.gz
frameworks_base-4a06c8008b2edd6677f9a411af79b0a4971b87fe.tar.bz2
Simplify Choreographer API.
Removed the listeners and schedule animation / draw methods. Instead all requests are posted as one-shot callbacks, which is a better match for how clients actually use the Choreographer. Bug: 5721047 Change-Id: I113180b2713a300e4444d0d987f52b8157b7ac15
Diffstat (limited to 'core')
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java24
-rw-r--r--core/java/android/view/Choreographer.java319
-rw-r--r--core/java/android/view/ViewRootImpl.java38
3 files changed, 113 insertions, 268 deletions
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index cc1efb9..6fbeee3 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -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>();
@@ -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();
@@ -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();
}
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 658da2f..917389c 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -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;
@@ -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
@@ -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
@@ -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;
@@ -160,195 +155,20 @@ public final class Choreographer {
}
/**
- * 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();
}
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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);
+ }
}
}
@@ -418,7 +286,6 @@ public final class Choreographer {
void doAnimationInner() {
final long start;
- final OnAnimateListener[] listeners;
final Callback callbacks;
synchronized (mLock) {
if (!mAnimationScheduled) {
@@ -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) {
@@ -458,7 +318,6 @@ public final class Choreographer {
void doDraw() {
final long start;
- final OnDrawListener[] listeners;
final Callback callbacks;
synchronized (mLock) {
if (!mDrawScheduled) {
@@ -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) {
@@ -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.");
}
@@ -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);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1930a5e..fbcb423 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -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;
@@ -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);
@@ -841,7 +838,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
- mChoreographer.scheduleDraw();
+ scheduleFrame();
}
}
@@ -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();
}
@@ -2376,7 +2386,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
mInputChannel = null;
}
- mChoreographer.removeOnDrawListener(this);
+ unscheduleFrame();
}
void updateConfiguration(Configuration config, boolean force) {
@@ -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);
@@ -3935,7 +3955,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
@Override
public void onBatchedInputEventPending() {
- mChoreographer.scheduleDraw();
+ scheduleFrame();
}
}
WindowInputEventReceiver mInputEventReceiver;