Choreographer.java revision b080660dfd69ea6f0a034946b2ff8d94e97a2537
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
68ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    // Enable/disable vsync for animations and drawing.
6996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean USE_VSYNC = SystemProperties.getBoolean(
7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            "debug.choreographer.vsync", true);
7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
7220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    // Enable/disable using the frame time instead of returning now.
7320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
7420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            "debug.choreographer.frametime", true);
7520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
7620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private static final long NANOS_PER_MS = 1000000;
7720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
78ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_FRAME = 0;
79ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_SCHEDULE_VSYNC = 1;
80ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
8196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
8287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private final Object mLock = new Object();
8387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
8496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private final Looper mLooper;
85968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private final FrameHandler mHandler;
861654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown    private final FrameDisplayEventReceiver mDisplayEventReceiver;
87968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
88968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private Callback mCallbackPool;
8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
90ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private final CallbackQueue[] mCallbackQueues;
91968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
92ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private boolean mFrameScheduled;
9320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private boolean mCallbacksRunning;
9420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private long mLastFrameTimeNanos;
9559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown    private long mFrameIntervalNanos;
96ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
97ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
98ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Input callback.  Runs first.
99ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
100ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_INPUT = 0;
101ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
102ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
103ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Animation callback.  Runs before traversals.
104ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
105ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_ANIMATION = 1;
106ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
107ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
108ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Traversal callback.  Handles layout and draw.  Runs last
109ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * after all other asynchronous messages have been handled.
110ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
111ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_TRAVERSAL = 2;
112ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
113ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL;
11496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
11596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private Choreographer(Looper looper) {
11696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLooper = looper;
117968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        mHandler = new FrameHandler(looper);
1181654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown        mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
11920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        mLastFrameTimeNanos = Long.MIN_VALUE;
12059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown        mFrameIntervalNanos = (long)(1000000000 /
12159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                new Display(Display.DEFAULT_DISPLAY, null).getRefreshRate());
122ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
123ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
124ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        for (int i = 0; i <= CALLBACK_LAST; i++) {
125ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[i] = new CallbackQueue();
126ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        }
12796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
12996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
1308bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * Gets the choreographer for the calling thread.  Must be called from
1318bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * a thread that already has a {@link android.os.Looper} associated with it.
13296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
13396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return The choreographer for this thread.
13496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @throws IllegalStateException if the thread does not have a looper.
13596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
13696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static Choreographer getInstance() {
13796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sThreadInstance.get();
13896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
13996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
14096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
14196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The amount of time, in milliseconds, between each frame of the animation. This is a
14296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * requested time that the animation will attempt to honor, but the actual delay between
14396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * frames may be different, depending on system load and capabilities. This is a static
14496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
14596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
14696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
14796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
14896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
14996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
15096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return the requested time between frames, in milliseconds
15196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
15296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static long getFrameDelay() {
15396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sFrameDelay;
15496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
15596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
15696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
15796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The amount of time, in milliseconds, between each frame of the animation. This is a
15896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * requested time that the animation will attempt to honor, but the actual delay between
15996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * frames may be different, depending on system load and capabilities. This is a static
16096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
16196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
16296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
16396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
16496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
16596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
16696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param frameDelay the requested time between frames, in milliseconds
16796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
16896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static void setFrameDelay(long frameDelay) {
16996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        sFrameDelay = frameDelay;
17096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
17196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
17296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
1737ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * Subtracts typical frame delay time from a delay interval in milliseconds.
1747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     *
1757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * This method can be used to compensate for animation delay times that have baked
1767ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * in assumptions about the frame delay.  For example, it's quite common for code to
1777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * assume a 60Hz frame time and bake in a 16ms delay.  When we call
1787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
1797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * posting the animation callback but let the animation timer take care of the remaining
1807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * frame delay time.
1817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     *
1827ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * This method is somewhat conservative about how much of the frame delay it
1837ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
1847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * default is 10ms even though many parts of the system assume 16ms.  Consequently,
1857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * we might still wait 6ms before posting an animation callback that we want to run
1867ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * on the next frame, but this is much better than waiting a whole 16ms and likely
1877ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * missing the deadline.
1887ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     *
1897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param delayMillis The original delay time including an assumed frame delay.
1907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @return The adjusted delay time with the assumed frame delay subtracted out.
1917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     */
1927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public static long subtractFrameDelay(long delayMillis) {
1937ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        final long frameDelay = sFrameDelay;
1947ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
1957ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
1967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
1977ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    /**
198ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Posts a callback to run on the next frame.
199968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     * The callback only runs once and then is automatically removed.
200968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
201ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
202ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param action The callback action to run during the next frame.
2037ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
204968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
205ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #removeCallbacks
206968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
207ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void postCallback(int callbackType, Runnable action, Object token) {
208ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        postCallbackDelayed(callbackType, action, token, 0);
209968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
210968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
211968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    /**
212ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Posts a callback to run on the next frame following the specified delay.
2132b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * The callback only runs once and then is automatically removed.
2142b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
215ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
216ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param action The callback action to run during the next frame after the specified delay.
2177ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
2182b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @param delayMillis The delay time in milliseconds.
2192b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
220ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #removeCallback
2212b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     */
222ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void postCallbackDelayed(int callbackType,
223ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Runnable action, Object token, long delayMillis) {
2247ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        if (action == null) {
2257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            throw new IllegalArgumentException("action must not be null");
2262b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
227ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
228ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            throw new IllegalArgumentException("callbackType is invalid");
229ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        }
2307ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
23143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        if (DEBUG) {
232ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "PostCallback: type=" + callbackType
233ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    + ", action=" + action + ", token=" + token
23443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    + ", delayMillis=" + delayMillis);
23543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
23643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
2377ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
2387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long now = SystemClock.uptimeMillis();
2397ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long dueTime = now + delayMillis;
240ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
2417ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
2427ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (dueTime <= now) {
243ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                scheduleFrameLocked(now);
2447ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            } else {
245ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
246ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                msg.arg1 = callbackType;
247ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                msg.setAsynchronous(true);
2487ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                mHandler.sendMessageAtTime(msg, dueTime);
2497ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
2502b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
2512b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    }
2522b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown
2532b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    /**
254ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Removes callbacks that have the specified action and token.
255968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
256ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
2577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The action property of the callbacks to remove, or null to remove
2587ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any action.
2597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The token property of the callbacks to remove, or null to remove
2607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any token.
261968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
262ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #postCallback
263ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #postCallbackDelayed
264968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
265ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void removeCallbacks(int callbackType, Runnable action, Object token) {
266ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
267ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            throw new IllegalArgumentException("callbackType is invalid");
2682b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
2697ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
27043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        if (DEBUG) {
271ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "RemoveCallbacks: type=" + callbackType
272ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    + ", action=" + action + ", token=" + token);
27343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
27443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
2757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
276ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
277ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (action != null && token == null) {
278ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
2797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
2802b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
2812b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    }
2822b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown
28320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    /**
28420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * Gets the time when the current frame started.  The frame time should be used
28520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * instead of {@link SystemClock#uptimeMillis()} to synchronize animations.
28620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * This helps to reduce inter-frame jitter because the frame time is fixed at the
28720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * time the frame was scheduled to start, regardless of when the animations or
28820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * drawing code actually ran.
28920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
29020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * This method should only be called from within a callback.
29120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
29220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
29320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
29420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @throws IllegalStateException if no frame is in progress.
29520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     */
29620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    public long getFrameTime() {
29720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        return getFrameTimeNanos() / NANOS_PER_MS;
29820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    }
29920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
30020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    /**
30120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * Same as {@link #getFrameTime()} but with nanosecond precision.
30220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
30320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @return The frame start time, in the {@link System#nanoTime()} time base.
30420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
30520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @throws IllegalStateException if no frame is in progress.
30620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     */
30720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    public long getFrameTimeNanos() {
30820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        synchronized (mLock) {
30920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            if (!mCallbacksRunning) {
31020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                throw new IllegalStateException("This method must only be called as "
31120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                        + "part of a callback while a frame is in progress.");
31220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            }
31320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
31420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        }
31520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    }
31620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
317ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private void scheduleFrameLocked(long now) {
318ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (!mFrameScheduled) {
319ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mFrameScheduled = true;
3204a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            if (USE_VSYNC) {
3214a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
322ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "Scheduling next frame on vsync.");
3234a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
3244a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
3254a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // If running on the Looper thread, then schedule the vsync immediately,
3264a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // otherwise post a message to schedule the vsync from the UI thread
3274a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // as soon as possible.
3284a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (isRunningOnLooperThreadLocked()) {
3297ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    scheduleVsyncLocked();
3304a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                } else {
331e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
332e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    msg.setAsynchronous(true);
333e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    mHandler.sendMessageAtFrontOfQueue(msg);
3344a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
3354a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            } else {
33620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                final long nextFrameTime = Math.max(
33720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                        mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
3384a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
339ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
3404a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
341ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
342e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                msg.setAsynchronous(true);
343ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                mHandler.sendMessageAtTime(msg, nextFrameTime);
3444a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            }
3454a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown        }
3464a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown    }
3474a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
34820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    void doFrame(long timestampNanos, int frame) {
34959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown        final long startNanos;
35087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
351ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (!mFrameScheduled) {
35287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                return; // no work to do
35387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            }
35420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
35520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            startNanos = System.nanoTime();
35659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            final long jitterNanos = startNanos - timestampNanos;
35759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            if (jitterNanos >= mFrameIntervalNanos) {
35859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
35959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                if (DEBUG) {
36059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                    Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
36159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + "which is more than the frame interval of "
36259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + (mFrameIntervalNanos * 0.000001f) + " ms!  "
36359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + "Setting frame time to " + (lastFrameOffset * 0.000001f)
36459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + " ms in the past.");
36559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                }
36659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                timestampNanos = startNanos - lastFrameOffset;
36759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            }
36859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown
36959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            if (timestampNanos < mLastFrameTimeNanos) {
37059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                if (DEBUG) {
37159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                    Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
37259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + "previously skipped frame.  Waiting for next vsync");
37359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                }
37459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                scheduleVsyncLocked();
37559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                return;
37659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            }
37759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown
37859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            mFrameScheduled = false;
37959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            mLastFrameTimeNanos = timestampNanos;
38096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
38196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
382ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        doCallbacks(Choreographer.CALLBACK_INPUT);
383ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        doCallbacks(Choreographer.CALLBACK_ANIMATION);
384ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        doCallbacks(Choreographer.CALLBACK_TRAVERSAL);
385968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
38687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (DEBUG) {
38720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            final long endNanos = System.nanoTime();
388ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "Frame " + frame + ": Finished, took "
38920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                    + (endNanos - startNanos) * 0.000001f + " ms, latency "
39020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                    + (startNanos - timestampNanos) * 0.000001f + " ms.");
39196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
39296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
39396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
394ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    void doCallbacks(int callbackType) {
3957ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        Callback callbacks;
39687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
39720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            final long now = SystemClock.uptimeMillis();
39820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
39920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            if (callbacks == null) {
40020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                return;
40120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            }
40220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            mCallbacksRunning = true;
40396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
40420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        try {
405ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            for (Callback c = callbacks; c != null; c = c.next) {
406ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                if (DEBUG) {
407ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "RunCallback: type=" + callbackType
408ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                            + ", action=" + c.action + ", token=" + c.token
409ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
410ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                }
411ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                c.action.run();
412968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
41320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        } finally {
414ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            synchronized (mLock) {
41520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                mCallbacksRunning = false;
416ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                do {
417ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    final Callback next = callbacks.next;
418ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    recycleCallbackLocked(callbacks);
419ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    callbacks = next;
420ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                } while (callbacks != null);
421ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            }
42287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
42396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
42496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
425968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    void doScheduleVsync() {
42658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        synchronized (mLock) {
427ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (mFrameScheduled) {
4287ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleVsyncLocked();
4297ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
43058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        }
43158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
43258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
433ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    void doScheduleCallback(int callbackType) {
4347ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
435ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (!mFrameScheduled) {
436ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                final long now = SystemClock.uptimeMillis();
437ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
438ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    scheduleFrameLocked(now);
439ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                }
4407ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
44196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
44296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
44396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
4447ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private void scheduleVsyncLocked() {
4457ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        mDisplayEventReceiver.scheduleVsync();
4467ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
4477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
44858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private boolean isRunningOnLooperThreadLocked() {
44958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        return Looper.myLooper() == mLooper;
45058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
45158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
4527ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private Callback obtainCallbackLocked(long dueTime, Runnable action, Object token) {
453968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        Callback callback = mCallbackPool;
454968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        if (callback == null) {
455968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            callback = new Callback();
456968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        } else {
457968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            mCallbackPool = callback.next;
458968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            callback.next = null;
459968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
4607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.dueTime = dueTime;
4617ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.action = action;
4627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.token = token;
463968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        return callback;
464968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
465968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
466968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private void recycleCallbackLocked(Callback callback) {
4677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.action = null;
4687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.token = null;
469968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        callback.next = mCallbackPool;
470968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        mCallbackPool = callback;
471968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
472968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
473968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private final class FrameHandler extends Handler {
474968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public FrameHandler(Looper looper) {
475968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            super(looper);
476968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
477968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
478968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        @Override
479968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public void handleMessage(Message msg) {
480968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            switch (msg.what) {
481ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                case MSG_DO_FRAME:
48220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                    doFrame(System.nanoTime(), 0);
483968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
484968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                case MSG_DO_SCHEDULE_VSYNC:
485968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    doScheduleVsync();
486968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
487ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                case MSG_DO_SCHEDULE_CALLBACK:
488ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    doScheduleCallback(msg.arg1);
4892b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown                    break;
490968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
491968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
492968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
493968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
494b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
495b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            implements Runnable {
496b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        private long mTimestampNanos;
497b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        private int mFrame;
498b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown
49996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public FrameDisplayEventReceiver(Looper looper) {
50096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            super(looper);
50196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
50296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
50396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
50496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public void onVsync(long timestampNanos, int frame) {
505b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // Post the vsync event to the Handler.
506b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // The idea is to prevent incoming vsync events from completely starving
507b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // the message queue.  If there are no messages in the queue with timestamps
508b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // earlier than the frame time, then the vsync event will be processed immediately.
509b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // Otherwise, messages that predate the vsync event will be handled first.
510b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mTimestampNanos = timestampNanos;
511b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mFrame = frame;
512b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            Message msg = Message.obtain(mHandler, this);
513b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            msg.setAsynchronous(true);
514b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
515b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        }
516b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown
517b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        @Override
518b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        public void run() {
519b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            doFrame(mTimestampNanos, mFrame);
52096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
52196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
522968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
523968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private static final class Callback {
524968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public Callback next;
5257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public long dueTime;
5267ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public Runnable action;
5277ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public Object token;
528968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
52943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
53043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown    private final class CallbackQueue {
53143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        private Callback mHead;
53243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
53343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        public boolean hasDueCallbacksLocked(long now) {
53443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            return mHead != null && mHead.dueTime <= now;
53543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
53643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
53743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        public Callback extractDueCallbacksLocked(long now) {
53843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            Callback callbacks = mHead;
53943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (callbacks == null || callbacks.dueTime > now) {
54043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return null;
54143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
54243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
54343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            Callback last = callbacks;
54443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            Callback next = last.next;
54543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            while (next != null) {
54643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if (next.dueTime > now) {
54743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    last.next = null;
54843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    break;
54943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
55043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                last = next;
55143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                next = next.next;
55243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
55343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            mHead = next;
55443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            return callbacks;
55543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
55643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
55743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        public void addCallbackLocked(long dueTime, Runnable action, Object token) {
55843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            Callback callback = obtainCallbackLocked(dueTime, action, token);
55943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            Callback entry = mHead;
56043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (entry == null) {
56143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                mHead = callback;
56243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return;
56343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
56443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (dueTime < entry.dueTime) {
56543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                callback.next = entry;
56643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                mHead = callback;
56743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return;
56843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
56943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            while (entry.next != null) {
57043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if (dueTime < entry.next.dueTime) {
57143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    callback.next = entry.next;
57243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    break;
57343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
57443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                entry = entry.next;
57543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
57643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            entry.next = callback;
57743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
57843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
57943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        public void removeCallbacksLocked(Runnable action, Object token) {
58043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            Callback predecessor = null;
58143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            for (Callback callback = mHead; callback != null;) {
58243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                final Callback next = callback.next;
58343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if ((action == null || callback.action == action)
58443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        && (token == null || callback.token == token)) {
58543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    if (predecessor != null) {
58643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        predecessor.next = next;
58743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    } else {
58843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        mHead = next;
58943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    }
59043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    recycleCallbackLocked(callback);
59143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                } else {
59243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    predecessor = callback;
59343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
59443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                callback = next;
59543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
59643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
59743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown    }
59896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown}
599