Choreographer.java revision 3866f0d581ceaa165710feeee9f37fe1b0d7067d
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
19bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brownimport android.hardware.display.DisplayManagerGlobal;
2096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Handler;
2196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Looper;
2296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Message;
2396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.SystemClock;
2496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.SystemProperties;
2596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.util.Log;
2696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
2796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown/**
28cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Coordinates the timing of animations, input and drawing.
29cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p>
30cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The choreographer receives timing pulses (such as vertical synchronization)
31cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * from the display subsystem then schedules work to occur as part of rendering
32cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * the next display frame.
33cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p>
34cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Applications typically interact with the choreographer indirectly using
35cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * higher level abstractions in the animation framework or the view hierarchy.
36cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Here are some examples of things you can do using the higher-level APIs.
37cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p>
38cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <ul>
39cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post an animation to be processed on a regular time basis synchronized with
40cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
41cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
42cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * frame, use {@link View#postOnAnimation}.</li>
43cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
44cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
45cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
46cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * next display frame, use {@link View#postInvalidateOnAnimation()} or
47cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
48cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
49cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * sync with display frame rendering, do nothing.  This already happens automatically.
50cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link View#onDraw} will be called at the appropriate time.</li>
51cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </ul>
52cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p>
53cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * However, there are a few cases where you might want to use the functions of the
54cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * choreographer directly in your application.  Here are some examples.
55cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p>
56cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <ul>
57cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>If your application does its rendering in a different thread, possibly using GL,
58cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * or does not use the animation framework or view hierarchy at all
59cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * and you want to ensure that it is appropriately synchronized with the display, then use
60cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link Choreographer#postFrameCallback}.</li>
61cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>... and that's about it.</li>
62cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </ul>
63cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p>
64cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Each {@link Looper} thread has its own choreographer.  Other threads can
65cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * post callbacks to run on the choreographer but they will run on the {@link Looper}
66cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * to which the choreographer belongs.
67cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p>
6896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */
69968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brownpublic final class Choreographer {
7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final String TAG = "Choreographer";
7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean DEBUG = false;
7296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
7396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // The default amount of time in ms between animation frames.
7496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // When vsync is not enabled, we want to have some idea of how long we should
7596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // wait before posting the next animation message.  It is important that the
7696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // default value be less than the true inter-frame delay on all devices to avoid
7796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // situations where we might skip frames by waiting too long (we must compensate
7896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // for jitter and hardware variations).  Regardless of this value, the animation
7996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // and display loop is ultimately rate-limited by how fast new graphics buffers can
8096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // be dequeued.
8196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final long DEFAULT_FRAME_DELAY = 10;
8296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
8396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // The number of milliseconds between animation frames.
8487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
8596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
8696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // Thread local storage for the choreographer.
8796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final ThreadLocal<Choreographer> sThreadInstance =
8896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            new ThreadLocal<Choreographer>() {
8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
9096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        protected Choreographer initialValue() {
9196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            Looper looper = Looper.myLooper();
9296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (looper == null) {
9396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                throw new IllegalStateException("The current thread must have a looper!");
9496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
9596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            return new Choreographer(looper);
9696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
9796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    };
9896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
99ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    // Enable/disable vsync for animations and drawing.
10096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean USE_VSYNC = SystemProperties.getBoolean(
10196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            "debug.choreographer.vsync", true);
10296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
10320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    // Enable/disable using the frame time instead of returning now.
10420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
10520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            "debug.choreographer.frametime", true);
10620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
1074fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown    // Set a limit to warn about skipped frames.
1084fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown    // Skipped frames imply jank.
1094fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown    private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
1104fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown            "debug.choreographer.skipwarning", 30);
1114fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown
11220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private static final long NANOS_PER_MS = 1000000;
11320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
114ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_FRAME = 0;
115ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_SCHEDULE_VSYNC = 1;
116ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
11796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
118cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    // All frame callbacks posted by applications have this token.
119cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private static final Object FRAME_CALLBACK_TOKEN = new Object() {
120cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public String toString() { return "FRAME_CALLBACK_TOKEN"; }
121cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    };
122cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
12387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private final Object mLock = new Object();
12487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
12596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private final Looper mLooper;
126968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private final FrameHandler mHandler;
127cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
128cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    // The display event receiver can only be accessed by the looper thread to which
129cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    // it is attached.  We take care to ensure that we post message to the looper
130cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    // if appropriate when interacting with the display event receiver.
1311654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown    private final FrameDisplayEventReceiver mDisplayEventReceiver;
132968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
133cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private CallbackRecord mCallbackPool;
13496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
135ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private final CallbackQueue[] mCallbackQueues;
136968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
137ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private boolean mFrameScheduled;
13820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private boolean mCallbacksRunning;
13920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private long mLastFrameTimeNanos;
14059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown    private long mFrameIntervalNanos;
141ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
142ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
143ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Input callback.  Runs first.
144cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
145ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
146ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_INPUT = 0;
147ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
148ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
149ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Animation callback.  Runs before traversals.
150cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
151ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
152ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_ANIMATION = 1;
153ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
154ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
155ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Traversal callback.  Handles layout and draw.  Runs last
156ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * after all other asynchronous messages have been handled.
157cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
158ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
159ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_TRAVERSAL = 2;
160ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
161ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL;
16296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
16396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private Choreographer(Looper looper) {
16496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLooper = looper;
165968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        mHandler = new FrameHandler(looper);
1661654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown        mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
16720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        mLastFrameTimeNanos = Long.MIN_VALUE;
168d32460c5b7bea7b06e345397fdbaca58d9732dcfJeff Brown
169bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
170ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
171ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
172ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        for (int i = 0; i <= CALLBACK_LAST; i++) {
173ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[i] = new CallbackQueue();
174ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        }
17596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
17696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
177bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static float getRefreshRate() {
178bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(
179bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown                Display.DEFAULT_DISPLAY);
180bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown        return di.refreshRate;
181bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    }
182bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown
18396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
1848bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * Gets the choreographer for the calling thread.  Must be called from
1858bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * a thread that already has a {@link android.os.Looper} associated with it.
18696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
18796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return The choreographer for this thread.
18896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @throws IllegalStateException if the thread does not have a looper.
18996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
19096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static Choreographer getInstance() {
19196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sThreadInstance.get();
19296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
19396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
19496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
195cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The amount of time, in milliseconds, between each frame of the animation.
196cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
197cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * This is a requested time that the animation will attempt to honor, but the actual delay
198cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * between frames may be different, depending on system load and capabilities. This is a static
19996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
20096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
201cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
20296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
20396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
204cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
20596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
20696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return the requested time between frames, in milliseconds
207cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
20896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
20996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static long getFrameDelay() {
21096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sFrameDelay;
21196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
21296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
21396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
214cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The amount of time, in milliseconds, between each frame of the animation.
215cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
216cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * This is a requested time that the animation will attempt to honor, but the actual delay
217cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * between frames may be different, depending on system load and capabilities. This is a static
21896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
21996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
220cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
22196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
22296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
223cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
22496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
22596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param frameDelay the requested time between frames, in milliseconds
226cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
22796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
22896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static void setFrameDelay(long frameDelay) {
22996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        sFrameDelay = frameDelay;
23096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
23196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
23296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
2337ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * Subtracts typical frame delay time from a delay interval in milliseconds.
234cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
2357ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * This method can be used to compensate for animation delay times that have baked
2367ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * in assumptions about the frame delay.  For example, it's quite common for code to
2377ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * assume a 60Hz frame time and bake in a 16ms delay.  When we call
2387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
2397ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * posting the animation callback but let the animation timer take care of the remaining
2407ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * frame delay time.
241cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
2427ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * This method is somewhat conservative about how much of the frame delay it
2437ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
2447ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * default is 10ms even though many parts of the system assume 16ms.  Consequently,
2457ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * we might still wait 6ms before posting an animation callback that we want to run
2467ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * on the next frame, but this is much better than waiting a whole 16ms and likely
2477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * missing the deadline.
248cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
2497ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     *
2507ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param delayMillis The original delay time including an assumed frame delay.
2517ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @return The adjusted delay time with the assumed frame delay subtracted out.
252cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
2537ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     */
2547ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public static long subtractFrameDelay(long delayMillis) {
2557ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        final long frameDelay = sFrameDelay;
2567ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
2577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
2587ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
2597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    /**
260ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Posts a callback to run on the next frame.
261cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
262cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The callback runs once then is automatically removed.
263cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
264968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
265ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
266ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param action The callback action to run during the next frame.
2677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
268968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
269ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #removeCallbacks
270cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
271968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
272ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void postCallback(int callbackType, Runnable action, Object token) {
273ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        postCallbackDelayed(callbackType, action, token, 0);
274968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
275968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
276968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    /**
277cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Posts a callback to run on the next frame after the specified delay.
278cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
279cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The callback runs once then is automatically removed.
280cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
2812b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
282ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
283ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param action The callback action to run during the next frame after the specified delay.
2847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
2852b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @param delayMillis The delay time in milliseconds.
2862b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
287ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #removeCallback
288cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
2892b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     */
290ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void postCallbackDelayed(int callbackType,
291ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Runnable action, Object token, long delayMillis) {
2927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        if (action == null) {
2937ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            throw new IllegalArgumentException("action must not be null");
2942b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
295ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
296ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            throw new IllegalArgumentException("callbackType is invalid");
297ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        }
2987ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
299cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        postCallbackDelayedInternal(callbackType, action, token, delayMillis);
300cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
301cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
302cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private void postCallbackDelayedInternal(int callbackType,
303cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            Object action, Object token, long delayMillis) {
30443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        if (DEBUG) {
305ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "PostCallback: type=" + callbackType
306ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    + ", action=" + action + ", token=" + token
30743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    + ", delayMillis=" + delayMillis);
30843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
30943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
3107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
3117ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long now = SystemClock.uptimeMillis();
3127ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long dueTime = now + delayMillis;
313ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
3147ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
3157ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (dueTime <= now) {
316ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                scheduleFrameLocked(now);
3177ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            } else {
318ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
319ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                msg.arg1 = callbackType;
320ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                msg.setAsynchronous(true);
3217ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                mHandler.sendMessageAtTime(msg, dueTime);
3227ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
3232b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
3242b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    }
3252b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown
3262b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    /**
327ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Removes callbacks that have the specified action and token.
328968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
329ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
3307ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The action property of the callbacks to remove, or null to remove
3317ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any action.
3327ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The token property of the callbacks to remove, or null to remove
3337ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any token.
334968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
335ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #postCallback
336ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #postCallbackDelayed
337cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
338968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
339ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void removeCallbacks(int callbackType, Runnable action, Object token) {
340ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
341ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            throw new IllegalArgumentException("callbackType is invalid");
3422b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
3437ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
344cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        removeCallbacksInternal(callbackType, action, token);
345cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
346cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
347cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private void removeCallbacksInternal(int callbackType, Object action, Object token) {
34843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        if (DEBUG) {
349ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "RemoveCallbacks: type=" + callbackType
350ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    + ", action=" + action + ", token=" + token);
35143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
35243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
3537ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
354ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
355ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (action != null && token == null) {
356ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
3577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
3582b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
3592b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    }
3602b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown
36120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    /**
362cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Posts a frame callback to run on the next frame.
363cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
364cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The callback runs once then is automatically removed.
365cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
366cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
367cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @param callback The frame callback to run during the next frame.
368cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
369cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #postFrameCallbackDelayed
370cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #removeFrameCallback
371cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     */
372cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    public void postFrameCallback(FrameCallback callback) {
373cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        postFrameCallbackDelayed(callback, 0);
374cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
375cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
376cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    /**
377cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Posts a frame callback to run on the next frame after the specified delay.
378cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
379cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The callback runs once then is automatically removed.
380cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
381cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
382cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @param callback The frame callback to run during the next frame.
383cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @param delayMillis The delay time in milliseconds.
384cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
385cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #postFrameCallback
386cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #removeFrameCallback
387cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     */
388cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
389cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        if (callback == null) {
390cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            throw new IllegalArgumentException("callback must not be null");
391cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        }
392cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
393cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        postCallbackDelayedInternal(CALLBACK_ANIMATION,
394cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                callback, FRAME_CALLBACK_TOKEN, delayMillis);
395cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
396cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
397cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    /**
398cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Removes a previously posted frame callback.
399cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
400cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @param callback The frame callback to remove.
40120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
402cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #postFrameCallback
403cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #postFrameCallbackDelayed
404cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     */
405cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    public void removeFrameCallback(FrameCallback callback) {
406cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        if (callback == null) {
407cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            throw new IllegalArgumentException("callback must not be null");
408cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        }
409cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
410cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
411cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
412cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
413cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    /**
414cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Gets the time when the current frame started.
415cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
416cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * This method provides the time in nanoseconds when the frame started being rendered.
417cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The frame time provides a stable time base for synchronizing animations
418cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
419cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
420cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * time helps to reduce inter-frame jitter because the frame time is fixed at the time
421cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * the frame was scheduled to start, regardless of when the animations or drawing
422cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * callback actually runs.  All callbacks that run as part of rendering a frame will
423cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * observe the same frame time so using the frame time also helps to synchronize effects
424cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * that are performed by different callbacks.
425cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
426cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Please note that the framework already takes care to process animations and
427cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * drawing using the frame time as a stable time base.  Most applications should
428cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * not need to use the frame time information directly.
429cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
43020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * This method should only be called from within a callback.
431cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
43220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
43320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
43420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
43520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @throws IllegalStateException if no frame is in progress.
436cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
43720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     */
43820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    public long getFrameTime() {
43920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        return getFrameTimeNanos() / NANOS_PER_MS;
44020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    }
44120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
44220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    /**
44320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * Same as {@link #getFrameTime()} but with nanosecond precision.
44420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
44520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @return The frame start time, in the {@link System#nanoTime()} time base.
44620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
44720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @throws IllegalStateException if no frame is in progress.
448cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
44920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     */
45020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    public long getFrameTimeNanos() {
45120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        synchronized (mLock) {
45220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            if (!mCallbacksRunning) {
45320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                throw new IllegalStateException("This method must only be called as "
45420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                        + "part of a callback while a frame is in progress.");
45520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            }
45620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
45720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        }
45820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    }
45920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
460ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private void scheduleFrameLocked(long now) {
461ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (!mFrameScheduled) {
462ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mFrameScheduled = true;
4634a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            if (USE_VSYNC) {
4644a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
465ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "Scheduling next frame on vsync.");
4664a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
4674a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
4684a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // If running on the Looper thread, then schedule the vsync immediately,
4694a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // otherwise post a message to schedule the vsync from the UI thread
4704a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // as soon as possible.
4714a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (isRunningOnLooperThreadLocked()) {
4727ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    scheduleVsyncLocked();
4734a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                } else {
474e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
475e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    msg.setAsynchronous(true);
476e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    mHandler.sendMessageAtFrontOfQueue(msg);
4774a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
4784a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            } else {
47920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                final long nextFrameTime = Math.max(
48020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                        mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
4814a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
482ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
4834a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
484ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
485e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                msg.setAsynchronous(true);
486ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                mHandler.sendMessageAtTime(msg, nextFrameTime);
4874a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            }
4884a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown        }
4894a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown    }
4904a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
491cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    void doFrame(long frameTimeNanos, int frame) {
49259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown        final long startNanos;
49387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
494ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (!mFrameScheduled) {
49587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                return; // no work to do
49687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            }
49720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
49820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            startNanos = System.nanoTime();
499cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            final long jitterNanos = startNanos - frameTimeNanos;
50059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            if (jitterNanos >= mFrameIntervalNanos) {
5014fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                final long skippedFrames = jitterNanos / mFrameIntervalNanos;
5024fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
503265f1ccc5128319d81eee70ee2d2ae81573efb11Jeff Brown                    Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
5044fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                            + "The application may be doing too much work on its main thread.");
5054fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                }
50659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
50759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                if (DEBUG) {
50859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                    Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
50959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + "which is more than the frame interval of "
51059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + (mFrameIntervalNanos * 0.000001f) + " ms!  "
5114fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                            + "Skipping " + skippedFrames + " frames and setting frame "
5124fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                            + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
51359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                }
514cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                frameTimeNanos = startNanos - lastFrameOffset;
51559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            }
51659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown
517cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            if (frameTimeNanos < mLastFrameTimeNanos) {
51859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                if (DEBUG) {
51959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                    Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
5204fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                            + "previously skipped frame.  Waiting for next vsync.");
52159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                }
52259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                scheduleVsyncLocked();
52359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                return;
52459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            }
52559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown
52659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            mFrameScheduled = false;
527cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            mLastFrameTimeNanos = frameTimeNanos;
52896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
52996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
530cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
531cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
532cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
533968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
53487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (DEBUG) {
53520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            final long endNanos = System.nanoTime();
536ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "Frame " + frame + ": Finished, took "
53720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                    + (endNanos - startNanos) * 0.000001f + " ms, latency "
538cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                    + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
53996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
54096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
54196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
542cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    void doCallbacks(int callbackType, long frameTimeNanos) {
543cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        CallbackRecord callbacks;
54487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
545cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            // We use "now" to determine when callbacks become due because it's possible
546cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            // for earlier processing phases in a frame to post callbacks that should run
547cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            // in a following phase, such as an input event that causes an animation to start.
54820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            final long now = SystemClock.uptimeMillis();
54920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
55020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            if (callbacks == null) {
55120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                return;
55220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            }
55320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            mCallbacksRunning = true;
55496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
55520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        try {
556cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            for (CallbackRecord c = callbacks; c != null; c = c.next) {
557ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                if (DEBUG) {
558ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "RunCallback: type=" + callbackType
559ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                            + ", action=" + c.action + ", token=" + c.token
560ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
561ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                }
562cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                c.run(frameTimeNanos);
563968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
56420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        } finally {
565ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            synchronized (mLock) {
56620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                mCallbacksRunning = false;
567ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                do {
568cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                    final CallbackRecord next = callbacks.next;
569ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    recycleCallbackLocked(callbacks);
570ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    callbacks = next;
571ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                } while (callbacks != null);
572ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            }
57387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
57496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
57596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
576968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    void doScheduleVsync() {
57758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        synchronized (mLock) {
578ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (mFrameScheduled) {
5797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleVsyncLocked();
5807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
58158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        }
58258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
58358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
584ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    void doScheduleCallback(int callbackType) {
5857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
586ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (!mFrameScheduled) {
587ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                final long now = SystemClock.uptimeMillis();
588ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
589ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    scheduleFrameLocked(now);
590ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                }
5917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
59296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
59396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
59496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
5957ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private void scheduleVsyncLocked() {
5967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        mDisplayEventReceiver.scheduleVsync();
5977ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
5987ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
59958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private boolean isRunningOnLooperThreadLocked() {
60058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        return Looper.myLooper() == mLooper;
60158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
60258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
603cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
604cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        CallbackRecord callback = mCallbackPool;
605968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        if (callback == null) {
606cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            callback = new CallbackRecord();
607968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        } else {
608968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            mCallbackPool = callback.next;
609968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            callback.next = null;
610968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
6117ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.dueTime = dueTime;
6127ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.action = action;
6137ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.token = token;
614968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        return callback;
615968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
616968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
617cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private void recycleCallbackLocked(CallbackRecord callback) {
6187ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.action = null;
6197ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.token = null;
620968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        callback.next = mCallbackPool;
621968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        mCallbackPool = callback;
622968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
623968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
624cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    /**
625cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Implement this interface to receive a callback when a new display frame is
626cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * being rendered.  The callback is invoked on the {@link Looper} thread to
627cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * which the {@link Choreographer} is attached.
628cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     */
629cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    public interface FrameCallback {
630cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        /**
631cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * Called when a new display frame is being rendered.
632cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * <p>
633cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * This method provides the time in nanoseconds when the frame started being rendered.
634cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * The frame time provides a stable time base for synchronizing animations
635cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
636cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
637cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * time helps to reduce inter-frame jitter because the frame time is fixed at the time
638cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * the frame was scheduled to start, regardless of when the animations or drawing
639cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * callback actually runs.  All callbacks that run as part of rendering a frame will
640cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * observe the same frame time so using the frame time also helps to synchronize effects
641cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * that are performed by different callbacks.
642cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * </p><p>
643cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * Please note that the framework already takes care to process animations and
644cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * drawing using the frame time as a stable time base.  Most applications should
645cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * not need to use the frame time information directly.
646cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * </p>
647cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         *
648cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
649cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
650cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * to convert it to the {@link SystemClock#uptimeMillis()} time base.
651cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         */
652cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public void doFrame(long frameTimeNanos);
653cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
654cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
655968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private final class FrameHandler extends Handler {
656968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public FrameHandler(Looper looper) {
657968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            super(looper);
658968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
659968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
660968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        @Override
661968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public void handleMessage(Message msg) {
662968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            switch (msg.what) {
663ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                case MSG_DO_FRAME:
66420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                    doFrame(System.nanoTime(), 0);
665968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
666968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                case MSG_DO_SCHEDULE_VSYNC:
667968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    doScheduleVsync();
668968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
669ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                case MSG_DO_SCHEDULE_CALLBACK:
670ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    doScheduleCallback(msg.arg1);
6712b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown                    break;
672968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
673968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
674968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
675968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
676b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
677b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            implements Runnable {
6784fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown        private boolean mHavePendingVsync;
679b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        private long mTimestampNanos;
680b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        private int mFrame;
681b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown
68296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public FrameDisplayEventReceiver(Looper looper) {
68396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            super(looper);
68496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
68596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
68696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
687e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
688e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            // Ignore vsync from secondary display.
689e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            // This can be problematic because the call to scheduleVsync() is a one-shot.
690e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            // We need to ensure that we will still receive the vsync from the primary
691e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            // display which is the one we really care about.  Ideally we should schedule
692e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            // vsync for a particular display.
693e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            // At this time Surface Flinger won't send us vsyncs for secondary displays
694e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            // but that could change in the future so let's log a message to help us remember
695e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            // that we need to fix this.
6963866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian            if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
697e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                Log.d(TAG, "Received vsync from secondary display, but we don't support "
698e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                        + "this case yet.  Choreographer needs a way to explicitly request "
699e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                        + "vsync for a specific display to ensure it doesn't lose track "
700e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                        + "of its scheduled vsync.");
701e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                scheduleVsync();
702e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                return;
703e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            }
704e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
705b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // Post the vsync event to the Handler.
706b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // The idea is to prevent incoming vsync events from completely starving
707b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // the message queue.  If there are no messages in the queue with timestamps
708b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // earlier than the frame time, then the vsync event will be processed immediately.
709b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // Otherwise, messages that predate the vsync event will be handled first.
7104fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown            long now = System.nanoTime();
7114fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown            if (timestampNanos > now) {
7124fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
7134fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                        + " ms in the future!  Check that graphics HAL is generating vsync "
7144fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                        + "timestamps using the correct timebase.");
7154fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown                timestampNanos = now;
7164fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown            }
7174fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown
718ba726113e525823f2594507d098f2d99426655f6Jeff Brown            if (mHavePendingVsync) {
719ba726113e525823f2594507d098f2d99426655f6Jeff Brown                Log.w(TAG, "Already have a pending vsync event.  There should only be "
720ba726113e525823f2594507d098f2d99426655f6Jeff Brown                        + "one at a time.");
721ba726113e525823f2594507d098f2d99426655f6Jeff Brown            } else {
722ba726113e525823f2594507d098f2d99426655f6Jeff Brown                mHavePendingVsync = true;
723ba726113e525823f2594507d098f2d99426655f6Jeff Brown            }
7244fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown
725b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mTimestampNanos = timestampNanos;
726b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mFrame = frame;
727b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            Message msg = Message.obtain(mHandler, this);
728b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            msg.setAsynchronous(true);
729b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
730b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        }
731b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown
732b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        @Override
733b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        public void run() {
7344fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown            mHavePendingVsync = false;
735b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            doFrame(mTimestampNanos, mFrame);
73696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
73796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
738968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
739cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private static final class CallbackRecord {
740cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public CallbackRecord next;
7417ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public long dueTime;
742cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public Object action; // Runnable or FrameCallback
7437ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public Object token;
744cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
745cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public void run(long frameTimeNanos) {
746cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            if (token == FRAME_CALLBACK_TOKEN) {
747cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                ((FrameCallback)action).doFrame(frameTimeNanos);
748cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            } else {
749cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                ((Runnable)action).run();
750cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            }
751cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        }
752968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
75343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
75443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown    private final class CallbackQueue {
755cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        private CallbackRecord mHead;
75643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
75743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        public boolean hasDueCallbacksLocked(long now) {
75843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            return mHead != null && mHead.dueTime <= now;
75943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
76043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
761cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public CallbackRecord extractDueCallbacksLocked(long now) {
762cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord callbacks = mHead;
76343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (callbacks == null || callbacks.dueTime > now) {
76443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return null;
76543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
76643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
767cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord last = callbacks;
768cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord next = last.next;
76943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            while (next != null) {
77043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if (next.dueTime > now) {
77143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    last.next = null;
77243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    break;
77343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
77443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                last = next;
77543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                next = next.next;
77643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
77743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            mHead = next;
77843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            return callbacks;
77943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
78043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
781cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public void addCallbackLocked(long dueTime, Object action, Object token) {
782cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
783cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord entry = mHead;
78443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (entry == null) {
78543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                mHead = callback;
78643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return;
78743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
78843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (dueTime < entry.dueTime) {
78943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                callback.next = entry;
79043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                mHead = callback;
79143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return;
79243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
79343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            while (entry.next != null) {
79443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if (dueTime < entry.next.dueTime) {
79543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    callback.next = entry.next;
79643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    break;
79743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
79843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                entry = entry.next;
79943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
80043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            entry.next = callback;
80143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
80243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
803cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public void removeCallbacksLocked(Object action, Object token) {
804cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord predecessor = null;
805cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            for (CallbackRecord callback = mHead; callback != null;) {
806cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                final CallbackRecord next = callback.next;
80743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if ((action == null || callback.action == action)
80843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        && (token == null || callback.token == token)) {
80943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    if (predecessor != null) {
81043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        predecessor.next = next;
81143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    } else {
81243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        mHead = next;
81343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    }
81443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    recycleCallbackLocked(callback);
81543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                } else {
81643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    predecessor = callback;
81743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
81843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                callback = next;
81943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
82043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
82143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown    }
82296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown}
823