Choreographer.java revision 7ae9d5faad5816f7e567ec1ec77e78d746cf7e5c
196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown/*
296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Copyright (C) 2011 The Android Open Source Project
396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown *
496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * you may not use this file except in compliance with the License.
696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * You may obtain a copy of the License at
796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown *
896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown *
1096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Unless required by applicable law or agreed to in writing, software
1196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * See the License for the specific language governing permissions and
1496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * limitations under the License.
1596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */
1696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
1796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownpackage android.view;
1896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
1996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Handler;
2096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Looper;
2196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Message;
2296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.SystemClock;
2396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.SystemProperties;
2496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.util.Log;
2596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
2696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown/**
278bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * Coordinates animations and drawing for UI on a particular thread.
2887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown *
294a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * This object is thread-safe.  Other threads can post callbacks to run at a later time
304a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * on the UI thread.
3187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown *
3258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver}
3358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * can only be accessed from the UI thread so operations that touch the event receiver
3458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * are posted to the UI thread if needed.
3558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown *
3696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @hide
3796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */
38968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brownpublic final class Choreographer {
3996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final String TAG = "Choreographer";
4096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean DEBUG = false;
4196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
4296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // The default amount of time in ms between animation frames.
4396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // When vsync is not enabled, we want to have some idea of how long we should
4496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // wait before posting the next animation message.  It is important that the
4596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // default value be less than the true inter-frame delay on all devices to avoid
4696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // situations where we might skip frames by waiting too long (we must compensate
4796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // for jitter and hardware variations).  Regardless of this value, the animation
4896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // and display loop is ultimately rate-limited by how fast new graphics buffers can
4996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // be dequeued.
5096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final long DEFAULT_FRAME_DELAY = 10;
5196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
5296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // The number of milliseconds between animation frames.
5387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
5496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
5596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // Thread local storage for the choreographer.
5696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final ThreadLocal<Choreographer> sThreadInstance =
5796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            new ThreadLocal<Choreographer>() {
5896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
5996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        protected Choreographer initialValue() {
6096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            Looper looper = Looper.myLooper();
6196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (looper == null) {
6296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                throw new IllegalStateException("The current thread must have a looper!");
6396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
6496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            return new Choreographer(looper);
6596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
6696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    };
6796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
6896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // System property to enable/disable vsync for animations and drawing.
6996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // Enabled by default.
7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean USE_VSYNC = SystemProperties.getBoolean(
7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            "debug.choreographer.vsync", true);
7296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
7396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // System property to enable/disable the use of the vsync / animation timer
7496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // for drawing rather than drawing immediately.
7590a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown    // Temporarily disabled by default because postponing performTraversals() violates
7690a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown    // assumptions about traversals happening in-order relative to other posted messages.
7790a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown    // Bug: 5721047
7896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean USE_ANIMATION_TIMER_FOR_DRAW = SystemProperties.getBoolean(
7990a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown            "debug.choreographer.animdraw", false);
8096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
8196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final int MSG_DO_ANIMATION = 0;
8296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final int MSG_DO_DRAW = 1;
8358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private static final int MSG_DO_SCHEDULE_VSYNC = 2;
847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private static final int MSG_DO_SCHEDULE_ANIMATION = 3;
857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private static final int MSG_DO_SCHEDULE_DRAW = 4;
8696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
8787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private final Object mLock = new Object();
8887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private final Looper mLooper;
90968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private final FrameHandler mHandler;
911654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown    private final FrameDisplayEventReceiver mDisplayEventReceiver;
92968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
93968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private Callback mCallbackPool;
9496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
954a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown    private Callback mAnimationCallbacks;
964a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown    private Callback mDrawCallbacks;
97968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
9896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private boolean mAnimationScheduled;
9996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private boolean mDrawScheduled;
10096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private long mLastAnimationTime;
10196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private long mLastDrawTime;
10296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
10396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private Choreographer(Looper looper) {
10496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLooper = looper;
105968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        mHandler = new FrameHandler(looper);
1061654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown        mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
10796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLastAnimationTime = Long.MIN_VALUE;
10896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLastDrawTime = Long.MIN_VALUE;
10996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
11096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
11196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
1128bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * Gets the choreographer for the calling thread.  Must be called from
1138bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * a thread that already has a {@link android.os.Looper} associated with it.
11496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
11596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return The choreographer for this thread.
11696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @throws IllegalStateException if the thread does not have a looper.
11796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
11896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static Choreographer getInstance() {
11996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sThreadInstance.get();
12096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
12196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
12296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
12396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The amount of time, in milliseconds, between each frame of the animation. This is a
12496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * requested time that the animation will attempt to honor, but the actual delay between
12596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * frames may be different, depending on system load and capabilities. This is a static
12696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
12796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
12996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
13096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
13196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
13296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return the requested time between frames, in milliseconds
13396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
13496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static long getFrameDelay() {
13596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sFrameDelay;
13696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
13796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
13896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
13996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The amount of time, in milliseconds, between each frame of the animation. This is a
14096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * requested time that the animation will attempt to honor, but the actual delay between
14196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * frames may be different, depending on system load and capabilities. This is a static
14296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
14396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
14496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
14596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
14696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
14796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
14896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param frameDelay the requested time between frames, in milliseconds
14996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
15096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static void setFrameDelay(long frameDelay) {
15196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        sFrameDelay = frameDelay;
15296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
15396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
15496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
1557ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * Subtracts typical frame delay time from a delay interval in milliseconds.
1567ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     *
1577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * This method can be used to compensate for animation delay times that have baked
1587ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * in assumptions about the frame delay.  For example, it's quite common for code to
1597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * assume a 60Hz frame time and bake in a 16ms delay.  When we call
1607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
1617ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * posting the animation callback but let the animation timer take care of the remaining
1627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * frame delay time.
1637ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     *
1647ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * This method is somewhat conservative about how much of the frame delay it
1657ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
1667ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * default is 10ms even though many parts of the system assume 16ms.  Consequently,
1677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * we might still wait 6ms before posting an animation callback that we want to run
1687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * on the next frame, but this is much better than waiting a whole 16ms and likely
1697ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * missing the deadline.
1707ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     *
1717ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param delayMillis The original delay time including an assumed frame delay.
1727ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @return The adjusted delay time with the assumed frame delay subtracted out.
1737ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     */
1747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public static long subtractFrameDelay(long delayMillis) {
1757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        final long frameDelay = sFrameDelay;
1767ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
1777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
1787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
1797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    /**
1802b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * Posts a callback to run on the next animation cycle.
181968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     * The callback only runs once and then is automatically removed.
182968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
1837ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The callback action to run during the next animation cycle.
1847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
185968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
1864a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown     * @see #removeAnimationCallback
187968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
1887ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public void postAnimationCallback(Runnable action, Object token) {
1897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        postAnimationCallbackDelayed(action, token, 0);
190968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
191968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
192968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    /**
1932b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * Posts a callback to run on the next animation cycle following the specified delay.
1942b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * The callback only runs once and then is automatically removed.
1952b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
1967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The callback action to run during the next animation cycle after
1972b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * the specified delay.
1987ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
1992b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @param delayMillis The delay time in milliseconds.
2002b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
2012b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @see #removeAnimationCallback
2022b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     */
2037ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public void postAnimationCallbackDelayed(Runnable action, Object token, long delayMillis) {
2047ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        if (action == null) {
2057ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            throw new IllegalArgumentException("action must not be null");
2062b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
2077ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
2087ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
2097ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long now = SystemClock.uptimeMillis();
2107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long dueTime = now + delayMillis;
2117ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, dueTime, action, token);
2127ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
2137ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (dueTime <= now) {
2147ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleAnimationLocked(now);
2157ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            } else {
2167ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_ANIMATION, action);
2177ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                mHandler.sendMessageAtTime(msg, dueTime);
2187ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
2192b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
2202b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    }
2212b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown
2222b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    /**
2237ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * Removes animation callbacks that have the specified action and token.
224968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
2257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The action property of the callbacks to remove, or null to remove
2267ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any action.
2277ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The token property of the callbacks to remove, or null to remove
2287ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any token.
229968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
2304a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown     * @see #postAnimationCallback
2312b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @see #postAnimationCallbackDelayed
232968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
2337ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public void removeAnimationCallbacks(Runnable action, Object token) {
234968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        synchronized (mLock) {
2357ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            mAnimationCallbacks = removeCallbacksLocked(mAnimationCallbacks, action, token);
2367ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (action != null && token == null) {
2377ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                mHandler.removeMessages(MSG_DO_SCHEDULE_ANIMATION, action);
2387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
239968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
240968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
241968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
242968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    /**
2432b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * Posts a callback to run on the next draw cycle.
244968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     * The callback only runs once and then is automatically removed.
245968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
2467ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The callback action to run during the next draw cycle.
2477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
248968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
2494a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown     * @see #removeDrawCallback
250968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
2517ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public void postDrawCallback(Runnable action, Object token) {
2527ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        postDrawCallbackDelayed(action, token, 0);
253968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
254968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
255968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    /**
2562b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * Posts a callback to run on the next draw cycle following the specified delay.
2572b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * The callback only runs once and then is automatically removed.
2582b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
2597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The callback action to run during the next animation cycle after
2602b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * the specified delay.
2617ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
2622b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @param delayMillis The delay time in milliseconds.
2632b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
2642b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @see #removeDrawCallback
2652b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     */
2667ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public void postDrawCallbackDelayed(Runnable action, Object token, long delayMillis) {
2677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        if (action == null) {
2687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            throw new IllegalArgumentException("action must not be null");
2692b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
2707ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
2717ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
2727ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long now = SystemClock.uptimeMillis();
2737ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long dueTime = now + delayMillis;
2747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            mDrawCallbacks = addCallbackLocked(mDrawCallbacks, dueTime, action, token);
2757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            scheduleDrawLocked(now);
2767ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
2777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (dueTime <= now) {
2787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleDrawLocked(now);
2797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            } else {
2807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_DRAW, action);
2817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                mHandler.sendMessageAtTime(msg, dueTime);
2827ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
2832b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
2842b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    }
2852b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown
2862b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    /**
2877ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * Removes draw callbacks that have the specified action and token.
288968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
2897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The action property of the callbacks to remove, or null to remove
2907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any action.
2917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The token property of the callbacks to remove, or null to remove
2927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any token.
293968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
2944a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown     * @see #postDrawCallback
2952b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @see #postDrawCallbackDelayed
296968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
2977ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public void removeDrawCallbacks(Runnable action, Object token) {
298968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        synchronized (mLock) {
2997ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            mDrawCallbacks = removeCallbacksLocked(mDrawCallbacks, action, token);
3007ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (action != null && token == null) {
3017ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                mHandler.removeMessages(MSG_DO_SCHEDULE_DRAW, action);
3027ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
3034a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown        }
3044a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown    }
3054a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
3067ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private void scheduleAnimationLocked(long now) {
3074a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown        if (!mAnimationScheduled) {
3084a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            mAnimationScheduled = true;
3094a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            if (USE_VSYNC) {
3104a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
3114a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                    Log.d(TAG, "Scheduling vsync for animation.");
3124a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
3134a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
3144a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // If running on the Looper thread, then schedule the vsync immediately,
3154a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // otherwise post a message to schedule the vsync from the UI thread
3164a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // as soon as possible.
3174a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (isRunningOnLooperThreadLocked()) {
3187ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    scheduleVsyncLocked();
3194a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                } else {
320e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
321e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    msg.setAsynchronous(true);
322e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    mHandler.sendMessageAtFrontOfQueue(msg);
3234a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
3244a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            } else {
3254a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now);
3264a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
3274a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                    Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms.");
3284a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
329e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_ANIMATION);
330e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                msg.setAsynchronous(true);
331e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                mHandler.sendMessageAtTime(msg, nextAnimationTime);
3324a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            }
3334a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown        }
3344a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown    }
3354a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
3367ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private void scheduleDrawLocked(long now) {
3374a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown        if (!mDrawScheduled) {
3384a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            mDrawScheduled = true;
3394a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            if (USE_ANIMATION_TIMER_FOR_DRAW) {
3407ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleAnimationLocked(now);
3414a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            } else {
3424a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
3434a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                    Log.d(TAG, "Scheduling draw immediately.");
3444a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
345e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_DRAW);
346e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                msg.setAsynchronous(true);
3477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                mHandler.sendMessageAtTime(msg, now);
3484a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            }
34996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
35096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
35196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
352968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    void doAnimation() {
35387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        doAnimationInner();
35487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
35587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (USE_ANIMATION_TIMER_FOR_DRAW) {
35687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            doDraw();
35787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
35887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    }
35987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
360968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    void doAnimationInner() {
36187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        final long start;
3627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        Callback callbacks;
36387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
36487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            if (!mAnimationScheduled) {
36587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                return; // no work to do
36687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            }
36796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mAnimationScheduled = false;
36896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
36987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            start = SystemClock.uptimeMillis();
37096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (DEBUG) {
37196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime)
37296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                        + " ms have elapsed since previous animation.");
37396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
37496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mLastAnimationTime = start;
37596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
3764a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            callbacks = mAnimationCallbacks;
3777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (callbacks != null) {
3787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                if (callbacks.dueTime > start) {
3797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    callbacks = null;
3807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                } else {
3817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    Callback predecessor = callbacks;
3827ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    Callback successor = predecessor.next;
3837ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    while (successor != null) {
3847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                        if (successor.dueTime > start) {
3857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                            predecessor.next = null;
3867ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                            break;
3877ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                        }
3887ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                        predecessor = successor;
3897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                        successor = successor.next;
3907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    }
3917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    mAnimationCallbacks = successor;
3927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                }
3937ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
39496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
39596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
396968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        if (callbacks != null) {
397968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            runCallbacks(callbacks);
398968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            synchronized (mLock) {
399968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                recycleCallbacksLocked(callbacks);
400968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
401968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
402968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
40387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (DEBUG) {
40487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms.");
40596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
40696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
40796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
408968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    void doDraw() {
40987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        final long start;
4107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        Callback callbacks;
41187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
41287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            if (!mDrawScheduled) {
41387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                return; // no work to do
41487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            }
41596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mDrawScheduled = false;
41696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
41787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            start = SystemClock.uptimeMillis();
41896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (DEBUG) {
41996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                Log.d(TAG, "Performing draw: " + Math.max(0, start - mLastDrawTime)
42096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                        + " ms have elapsed since previous draw.");
42196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
42296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mLastDrawTime = start;
42396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
4244a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            callbacks = mDrawCallbacks;
4257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (callbacks != null) {
4267ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                if (callbacks.dueTime > start) {
4277ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    callbacks = null;
4287ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                } else {
4297ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    Callback predecessor = callbacks;
4307ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    Callback successor = predecessor.next;
4317ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    while (successor != null) {
4327ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                        if (successor.dueTime > start) {
4337ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                            predecessor.next = null;
4347ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                            break;
4357ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                        }
4367ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                        predecessor = successor;
4377ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                        successor = successor.next;
4387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    }
4397ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    mDrawCallbacks = successor;
4407ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                }
4417ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
44296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
44387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
444968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        if (callbacks != null) {
445968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            runCallbacks(callbacks);
446968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            synchronized (mLock) {
447968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                recycleCallbacksLocked(callbacks);
448968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
449968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
450968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
45187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (DEBUG) {
45287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms.");
45387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
45496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
45596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
456968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    void doScheduleVsync() {
45758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        synchronized (mLock) {
4587ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (mAnimationScheduled) {
4597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleVsyncLocked();
4607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
46158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        }
46258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
46358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
4647ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    void doScheduleAnimation() {
4657ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
4667ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long now = SystemClock.uptimeMillis();
4677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (mAnimationCallbacks != null && mAnimationCallbacks.dueTime <= now) {
4687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleAnimationLocked(now);
4697ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
47096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
47196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
47296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
4737ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    void doScheduleDraw() {
4747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
4757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long now = SystemClock.uptimeMillis();
4767ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (mDrawCallbacks != null && mDrawCallbacks.dueTime <= now) {
4777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleDrawLocked(now);
4787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
4797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        }
4807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
4817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
4827ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private void scheduleVsyncLocked() {
4837ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        mDisplayEventReceiver.scheduleVsync();
4847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
4857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
48658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private boolean isRunningOnLooperThreadLocked() {
48758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        return Looper.myLooper() == mLooper;
48858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
48958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
4907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private Callback addCallbackLocked(Callback head,
4917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            long dueTime, Runnable action, Object token) {
4927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        Callback callback = obtainCallbackLocked(dueTime, action, token);
493968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        if (head == null) {
494968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            return callback;
495968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
4967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        Callback entry = head;
4977ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        if (dueTime < entry.dueTime) {
4987ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            callback.next = entry;
4997ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            return callback;
5007ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        }
5017ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        while (entry.next != null) {
5027ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (dueTime < entry.next.dueTime) {
5037ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                callback.next = entry.next;
5047ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                break;
5057ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
5067ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            entry = entry.next;
507968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
5087ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        entry.next = callback;
509968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        return head;
510968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
511968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
5127ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private Callback removeCallbacksLocked(Callback head, Runnable action, Object token) {
513968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        Callback predecessor = null;
514968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        for (Callback callback = head; callback != null;) {
515968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            final Callback next = callback.next;
5167ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if ((action == null || callback.action == action)
5177ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    && (token == null || callback.token == token)) {
518968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                if (predecessor != null) {
519968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    predecessor.next = next;
520968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                } else {
521968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    head = next;
522968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                }
523968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                recycleCallbackLocked(callback);
524968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            } else {
525968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                predecessor = callback;
526968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
527968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            callback = next;
528968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
529968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        return head;
530968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
531968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
532968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private void runCallbacks(Callback head) {
533968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        while (head != null) {
5347ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            head.action.run();
535968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            head = head.next;
536968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
537968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
538968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
539968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private void recycleCallbacksLocked(Callback head) {
540968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        while (head != null) {
541968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            final Callback next = head.next;
542968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            recycleCallbackLocked(head);
543968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            head = next;
544968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
545968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
546968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
5477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private Callback obtainCallbackLocked(long dueTime, Runnable action, Object token) {
548968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        Callback callback = mCallbackPool;
549968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        if (callback == null) {
550968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            callback = new Callback();
551968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        } else {
552968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            mCallbackPool = callback.next;
553968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            callback.next = null;
554968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
5557ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.dueTime = dueTime;
5567ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.action = action;
5577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.token = token;
558968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        return callback;
559968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
560968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
561968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private void recycleCallbackLocked(Callback callback) {
5627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.action = null;
5637ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.token = null;
564968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        callback.next = mCallbackPool;
565968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        mCallbackPool = callback;
566968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
567968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
568968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private final class FrameHandler extends Handler {
569968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public FrameHandler(Looper looper) {
570968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            super(looper);
571968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
572968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
573968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        @Override
574968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public void handleMessage(Message msg) {
575968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            switch (msg.what) {
576968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                case MSG_DO_ANIMATION:
577968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    doAnimation();
578968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
579968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                case MSG_DO_DRAW:
580968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    doDraw();
581968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
582968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                case MSG_DO_SCHEDULE_VSYNC:
583968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    doScheduleVsync();
584968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
5857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                case MSG_DO_SCHEDULE_ANIMATION:
5867ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    doScheduleAnimation();
5872b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown                    break;
5887ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                case MSG_DO_SCHEDULE_DRAW:
5897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    doScheduleDraw();
5902b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown                    break;
591968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
592968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
593968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
594968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
59596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private final class FrameDisplayEventReceiver extends DisplayEventReceiver {
59696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public FrameDisplayEventReceiver(Looper looper) {
59796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            super(looper);
59896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
59996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
60096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
60196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public void onVsync(long timestampNanos, int frame) {
60296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            doAnimation();
60396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
60496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
605968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
606968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private static final class Callback {
607968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public Callback next;
6087ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public long dueTime;
6097ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public Runnable action;
6107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public Object token;
611968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
61296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown}
613