Choreographer.java revision cae804901eb5761e42d5bac7cdd6f15d37e3ceb3
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/**
27cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Coordinates the timing of animations, input and drawing.
28cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p>
29cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The choreographer receives timing pulses (such as vertical synchronization)
30cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * from the display subsystem then schedules work to occur as part of rendering
31cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * the next display frame.
32cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p>
33cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Applications typically interact with the choreographer indirectly using
34cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * higher level abstractions in the animation framework or the view hierarchy.
35cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Here are some examples of things you can do using the higher-level APIs.
36cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p>
37cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <ul>
38cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post an animation to be processed on a regular time basis synchronized with
39cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>
40cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
41cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * frame, use {@link View#postOnAnimation}.</li>
42cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display
43cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * frame after a delay, use {@link View#postOnAnimationDelayed}.</li>
44cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the
45cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * next display frame, use {@link View#postInvalidateOnAnimation()} or
46cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>
47cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in
48cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * sync with display frame rendering, do nothing.  This already happens automatically.
49cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link View#onDraw} will be called at the appropriate time.</li>
50cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </ul>
51cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p>
52cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * However, there are a few cases where you might want to use the functions of the
53cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * choreographer directly in your application.  Here are some examples.
54cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p>
55cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <ul>
56cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>If your application does its rendering in a different thread, possibly using GL,
57cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * or does not use the animation framework or view hierarchy at all
58cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * and you want to ensure that it is appropriately synchronized with the display, then use
59cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link Choreographer#postFrameCallback}.</li>
60cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>... and that's about it.</li>
61cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </ul>
62cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p>
63cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Each {@link Looper} thread has its own choreographer.  Other threads can
64cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * post callbacks to run on the choreographer but they will run on the {@link Looper}
65cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * to which the choreographer belongs.
66cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p>
6796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */
68968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brownpublic final class Choreographer {
6996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final String TAG = "Choreographer";
7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean DEBUG = false;
7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
7296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // The default amount of time in ms between animation frames.
7396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // When vsync is not enabled, we want to have some idea of how long we should
7496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // wait before posting the next animation message.  It is important that the
7596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // default value be less than the true inter-frame delay on all devices to avoid
7696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // situations where we might skip frames by waiting too long (we must compensate
7796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // for jitter and hardware variations).  Regardless of this value, the animation
7896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // and display loop is ultimately rate-limited by how fast new graphics buffers can
7996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // be dequeued.
8096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final long DEFAULT_FRAME_DELAY = 10;
8196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
8296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // The number of milliseconds between animation frames.
8387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
8496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
8596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // Thread local storage for the choreographer.
8696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final ThreadLocal<Choreographer> sThreadInstance =
8796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            new ThreadLocal<Choreographer>() {
8896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        protected Choreographer initialValue() {
9096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            Looper looper = Looper.myLooper();
9196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (looper == null) {
9296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                throw new IllegalStateException("The current thread must have a looper!");
9396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
9496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            return new Choreographer(looper);
9596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
9696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    };
9796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
98ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    // Enable/disable vsync for animations and drawing.
9996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean USE_VSYNC = SystemProperties.getBoolean(
10096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            "debug.choreographer.vsync", true);
10196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
10220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    // Enable/disable using the frame time instead of returning now.
10320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean(
10420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            "debug.choreographer.frametime", true);
10520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
10620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private static final long NANOS_PER_MS = 1000000;
10720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
108ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_FRAME = 0;
109ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_SCHEDULE_VSYNC = 1;
110ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
11196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
112cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    // All frame callbacks posted by applications have this token.
113cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private static final Object FRAME_CALLBACK_TOKEN = new Object() {
114cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public String toString() { return "FRAME_CALLBACK_TOKEN"; }
115cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    };
116cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
11787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private final Object mLock = new Object();
11887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
11996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private final Looper mLooper;
120968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private final FrameHandler mHandler;
121cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
122cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    // The display event receiver can only be accessed by the looper thread to which
123cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    // it is attached.  We take care to ensure that we post message to the looper
124cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    // if appropriate when interacting with the display event receiver.
1251654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown    private final FrameDisplayEventReceiver mDisplayEventReceiver;
126968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
127cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private CallbackRecord mCallbackPool;
12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
129ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private final CallbackQueue[] mCallbackQueues;
130968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
131ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private boolean mFrameScheduled;
13220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private boolean mCallbacksRunning;
13320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    private long mLastFrameTimeNanos;
13459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown    private long mFrameIntervalNanos;
135ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
136ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
137ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Input callback.  Runs first.
138cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
139ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
140ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_INPUT = 0;
141ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
142ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
143ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Animation callback.  Runs before traversals.
144cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
145ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
146ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_ANIMATION = 1;
147ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
148ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    /**
149ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Callback type: Traversal callback.  Handles layout and draw.  Runs last
150ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * after all other asynchronous messages have been handled.
151cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
152ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     */
153ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public static final int CALLBACK_TRAVERSAL = 2;
154ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
155ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL;
15696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
15796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private Choreographer(Looper looper) {
15896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLooper = looper;
159968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        mHandler = new FrameHandler(looper);
1601654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown        mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
16120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        mLastFrameTimeNanos = Long.MIN_VALUE;
16259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown        mFrameIntervalNanos = (long)(1000000000 /
16359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                new Display(Display.DEFAULT_DISPLAY, null).getRefreshRate());
164ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown
165ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
166ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        for (int i = 0; i <= CALLBACK_LAST; i++) {
167ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[i] = new CallbackQueue();
168ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        }
16996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
17096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
17196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
1728bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * Gets the choreographer for the calling thread.  Must be called from
1738bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * a thread that already has a {@link android.os.Looper} associated with it.
17496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
17596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return The choreographer for this thread.
17696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @throws IllegalStateException if the thread does not have a looper.
17796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
17896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static Choreographer getInstance() {
17996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sThreadInstance.get();
18096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
18196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
18296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
183cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The amount of time, in milliseconds, between each frame of the animation.
184cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
185cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * This is a requested time that the animation will attempt to honor, but the actual delay
186cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * between frames may be different, depending on system load and capabilities. This is a static
18796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
18896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
189cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
19096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
19196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
192cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
19396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
19496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return the requested time between frames, in milliseconds
195cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
19696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
19796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static long getFrameDelay() {
19896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sFrameDelay;
19996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
20096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
20196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
202cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The amount of time, in milliseconds, between each frame of the animation.
203cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
204cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * This is a requested time that the animation will attempt to honor, but the actual delay
205cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * between frames may be different, depending on system load and capabilities. This is a static
20696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
20796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
208cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
20996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
21096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
211cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
21296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
21396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param frameDelay the requested time between frames, in milliseconds
214cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
21596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
21696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static void setFrameDelay(long frameDelay) {
21796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        sFrameDelay = frameDelay;
21896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
21996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
22096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
2217ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * Subtracts typical frame delay time from a delay interval in milliseconds.
222cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
2237ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * This method can be used to compensate for animation delay times that have baked
2247ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * in assumptions about the frame delay.  For example, it's quite common for code to
2257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * assume a 60Hz frame time and bake in a 16ms delay.  When we call
2267ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * {@link #postAnimationCallbackDelayed} we want to know how long to wait before
2277ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * posting the animation callback but let the animation timer take care of the remaining
2287ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * frame delay time.
229cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
2307ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * This method is somewhat conservative about how much of the frame delay it
2317ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * subtracts.  It uses the same value returned by {@link #getFrameDelay} which by
2327ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * default is 10ms even though many parts of the system assume 16ms.  Consequently,
2337ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * we might still wait 6ms before posting an animation callback that we want to run
2347ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * on the next frame, but this is much better than waiting a whole 16ms and likely
2357ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * missing the deadline.
236cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
2377ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     *
2387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param delayMillis The original delay time including an assumed frame delay.
2397ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @return The adjusted delay time with the assumed frame delay subtracted out.
240cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
2417ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     */
2427ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    public static long subtractFrameDelay(long delayMillis) {
2437ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        final long frameDelay = sFrameDelay;
2447ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
2457ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
2467ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
2477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    /**
248ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Posts a callback to run on the next frame.
249cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
250cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The callback runs once then is automatically removed.
251cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
252968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
253ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
254ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param action The callback action to run during the next frame.
2557ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
256968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
257ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #removeCallbacks
258cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
259968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
260ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void postCallback(int callbackType, Runnable action, Object token) {
261ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        postCallbackDelayed(callbackType, action, token, 0);
262968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
263968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
264968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    /**
265cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Posts a callback to run on the next frame after the specified delay.
266cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
267cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The callback runs once then is automatically removed.
268cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
2692b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
270ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
271ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param action The callback action to run during the next frame after the specified delay.
2727ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The callback token, or null if none.
2732b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     * @param delayMillis The delay time in milliseconds.
2742b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     *
275ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #removeCallback
276cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
2772b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown     */
278ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void postCallbackDelayed(int callbackType,
279ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Runnable action, Object token, long delayMillis) {
2807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        if (action == null) {
2817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            throw new IllegalArgumentException("action must not be null");
2822b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
283ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
284ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            throw new IllegalArgumentException("callbackType is invalid");
285ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        }
2867ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
287cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        postCallbackDelayedInternal(callbackType, action, token, delayMillis);
288cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
289cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
290cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private void postCallbackDelayedInternal(int callbackType,
291cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            Object action, Object token, long delayMillis) {
29243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        if (DEBUG) {
293ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "PostCallback: type=" + callbackType
294ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    + ", action=" + action + ", token=" + token
29543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    + ", delayMillis=" + delayMillis);
29643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
29743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
2987ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
2997ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long now = SystemClock.uptimeMillis();
3007ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            final long dueTime = now + delayMillis;
301ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
3027ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
3037ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            if (dueTime <= now) {
304ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                scheduleFrameLocked(now);
3057ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            } else {
306ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
307ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                msg.arg1 = callbackType;
308ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                msg.setAsynchronous(true);
3097ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                mHandler.sendMessageAtTime(msg, dueTime);
3107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
3112b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
3122b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    }
3132b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown
3142b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    /**
315ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * Removes callbacks that have the specified action and token.
316968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
317ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @param callbackType The callback type.
3187ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param action The action property of the callbacks to remove, or null to remove
3197ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any action.
3207ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * @param token The token property of the callbacks to remove, or null to remove
3217ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown     * callbacks with any token.
322968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     *
323ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #postCallback
324ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown     * @see #postCallbackDelayed
325cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
326968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown     */
327ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    public void removeCallbacks(int callbackType, Runnable action, Object token) {
328ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
329ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            throw new IllegalArgumentException("callbackType is invalid");
3302b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
3317ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
332cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        removeCallbacksInternal(callbackType, action, token);
333cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
334cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
335cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private void removeCallbacksInternal(int callbackType, Object action, Object token) {
33643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        if (DEBUG) {
337ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "RemoveCallbacks: type=" + callbackType
338ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    + ", action=" + action + ", token=" + token);
33943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
34043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
3417ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
342ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mCallbackQueues[callbackType].removeCallbacksLocked(action, token);
343ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (action != null && token == null) {
344ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);
3457ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
3462b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown        }
3472b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown    }
3482b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown
34920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    /**
350cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Posts a frame callback to run on the next frame.
351cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
352cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The callback runs once then is automatically removed.
353cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
354cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
355cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @param callback The frame callback to run during the next frame.
356cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
357cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #postFrameCallbackDelayed
358cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #removeFrameCallback
359cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     */
360cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    public void postFrameCallback(FrameCallback callback) {
361cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        postFrameCallbackDelayed(callback, 0);
362cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
363cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
364cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    /**
365cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Posts a frame callback to run on the next frame after the specified delay.
366cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
367cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The callback runs once then is automatically removed.
368cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
369cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
370cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @param callback The frame callback to run during the next frame.
371cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @param delayMillis The delay time in milliseconds.
372cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
373cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #postFrameCallback
374cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #removeFrameCallback
375cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     */
376cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
377cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        if (callback == null) {
378cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            throw new IllegalArgumentException("callback must not be null");
379cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        }
380cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
381cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        postCallbackDelayedInternal(CALLBACK_ANIMATION,
382cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                callback, FRAME_CALLBACK_TOKEN, delayMillis);
383cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
384cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
385cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    /**
386cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Removes a previously posted frame callback.
387cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     *
388cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @param callback The frame callback to remove.
38920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
390cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #postFrameCallback
391cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @see #postFrameCallbackDelayed
392cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     */
393cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    public void removeFrameCallback(FrameCallback callback) {
394cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        if (callback == null) {
395cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            throw new IllegalArgumentException("callback must not be null");
396cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        }
397cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
398cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);
399cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
400cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
401cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    /**
402cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Gets the time when the current frame started.
403cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * <p>
404cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * This method provides the time in nanoseconds when the frame started being rendered.
405cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * The frame time provides a stable time base for synchronizing animations
406cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
407cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
408cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * time helps to reduce inter-frame jitter because the frame time is fixed at the time
409cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * the frame was scheduled to start, regardless of when the animations or drawing
410cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * callback actually runs.  All callbacks that run as part of rendering a frame will
411cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * observe the same frame time so using the frame time also helps to synchronize effects
412cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * that are performed by different callbacks.
413cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
414cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Please note that the framework already takes care to process animations and
415cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * drawing using the frame time as a stable time base.  Most applications should
416cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * not need to use the frame time information directly.
417cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p><p>
41820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * This method should only be called from within a callback.
419cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * </p>
42020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
42120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base.
42220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
42320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @throws IllegalStateException if no frame is in progress.
424cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
42520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     */
42620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    public long getFrameTime() {
42720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        return getFrameTimeNanos() / NANOS_PER_MS;
42820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    }
42920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
43020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    /**
43120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * Same as {@link #getFrameTime()} but with nanosecond precision.
43220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
43320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @return The frame start time, in the {@link System#nanoTime()} time base.
43420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     *
43520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     * @throws IllegalStateException if no frame is in progress.
436cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * @hide
43720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown     */
43820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    public long getFrameTimeNanos() {
43920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        synchronized (mLock) {
44020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            if (!mCallbacksRunning) {
44120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                throw new IllegalStateException("This method must only be called as "
44220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                        + "part of a callback while a frame is in progress.");
44320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            }
44420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime();
44520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        }
44620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown    }
44720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
448ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    private void scheduleFrameLocked(long now) {
449ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown        if (!mFrameScheduled) {
450ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            mFrameScheduled = true;
4514a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            if (USE_VSYNC) {
4524a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
453ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "Scheduling next frame on vsync.");
4544a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
4554a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
4564a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // If running on the Looper thread, then schedule the vsync immediately,
4574a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // otherwise post a message to schedule the vsync from the UI thread
4584a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                // as soon as possible.
4594a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (isRunningOnLooperThreadLocked()) {
4607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                    scheduleVsyncLocked();
4614a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                } else {
462e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
463e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    msg.setAsynchronous(true);
464e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                    mHandler.sendMessageAtFrontOfQueue(msg);
4654a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
4664a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            } else {
46720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                final long nextFrameTime = Math.max(
46820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                        mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
4694a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                if (DEBUG) {
470ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
4714a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown                }
472ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
473e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown                msg.setAsynchronous(true);
474ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                mHandler.sendMessageAtTime(msg, nextFrameTime);
4754a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown            }
4764a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown        }
4774a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown    }
4784a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown
479cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    void doFrame(long frameTimeNanos, int frame) {
48059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown        final long startNanos;
48187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
482ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (!mFrameScheduled) {
48387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                return; // no work to do
48487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            }
48520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown
48620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            startNanos = System.nanoTime();
487cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            final long jitterNanos = startNanos - frameTimeNanos;
48859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            if (jitterNanos >= mFrameIntervalNanos) {
48959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
49059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                if (DEBUG) {
49159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                    Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
49259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + "which is more than the frame interval of "
49359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + (mFrameIntervalNanos * 0.000001f) + " ms!  "
49459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + "Setting frame time to " + (lastFrameOffset * 0.000001f)
49559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + " ms in the past.");
49659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                }
497cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                frameTimeNanos = startNanos - lastFrameOffset;
49859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            }
49959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown
500cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            if (frameTimeNanos < mLastFrameTimeNanos) {
50159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                if (DEBUG) {
50259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                    Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
50359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                            + "previously skipped frame.  Waiting for next vsync");
50459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                }
50559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                scheduleVsyncLocked();
50659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown                return;
50759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            }
50859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown
50959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown            mFrameScheduled = false;
510cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            mLastFrameTimeNanos = frameTimeNanos;
51196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
51296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
513cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
514cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
515cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
516968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
51787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (DEBUG) {
51820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            final long endNanos = System.nanoTime();
519ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            Log.d(TAG, "Frame " + frame + ": Finished, took "
52020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                    + (endNanos - startNanos) * 0.000001f + " ms, latency "
521cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                    + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
52296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
52396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
52496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
525cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    void doCallbacks(int callbackType, long frameTimeNanos) {
526cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        CallbackRecord callbacks;
52787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
528cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            // We use "now" to determine when callbacks become due because it's possible
529cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            // for earlier processing phases in a frame to post callbacks that should run
530cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            // in a following phase, such as an input event that causes an animation to start.
53120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            final long now = SystemClock.uptimeMillis();
53220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
53320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            if (callbacks == null) {
53420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                return;
53520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            }
53620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown            mCallbacksRunning = true;
53796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
53820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        try {
539cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            for (CallbackRecord c = callbacks; c != null; c = c.next) {
540ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                if (DEBUG) {
541ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    Log.d(TAG, "RunCallback: type=" + callbackType
542ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                            + ", action=" + c.action + ", token=" + c.token
543ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
544ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                }
545cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                c.run(frameTimeNanos);
546968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
54720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown        } finally {
548ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            synchronized (mLock) {
54920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                mCallbacksRunning = false;
550ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                do {
551cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                    final CallbackRecord next = callbacks.next;
552ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    recycleCallbackLocked(callbacks);
553ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    callbacks = next;
554ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                } while (callbacks != null);
555ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            }
55687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
55796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
55896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
559968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    void doScheduleVsync() {
56058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        synchronized (mLock) {
561ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (mFrameScheduled) {
5627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown                scheduleVsyncLocked();
5637ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
56458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        }
56558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
56658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
567ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown    void doScheduleCallback(int callbackType) {
5687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        synchronized (mLock) {
569ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown            if (!mFrameScheduled) {
570ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                final long now = SystemClock.uptimeMillis();
571ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
572ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    scheduleFrameLocked(now);
573ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                }
5747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown            }
57596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
57696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
57796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
5787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    private void scheduleVsyncLocked() {
5797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        mDisplayEventReceiver.scheduleVsync();
5807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown    }
5817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown
58258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private boolean isRunningOnLooperThreadLocked() {
58358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        return Looper.myLooper() == mLooper;
58458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
58558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
586cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {
587cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        CallbackRecord callback = mCallbackPool;
588968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        if (callback == null) {
589cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            callback = new CallbackRecord();
590968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        } else {
591968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            mCallbackPool = callback.next;
592968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            callback.next = null;
593968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
5947ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.dueTime = dueTime;
5957ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.action = action;
5967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.token = token;
597968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        return callback;
598968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
599968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
600cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private void recycleCallbackLocked(CallbackRecord callback) {
6017ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.action = null;
6027ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        callback.token = null;
603968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        callback.next = mCallbackPool;
604968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        mCallbackPool = callback;
605968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
606968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
607cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    /**
608cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * Implement this interface to receive a callback when a new display frame is
609cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * being rendered.  The callback is invoked on the {@link Looper} thread to
610cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     * which the {@link Choreographer} is attached.
611cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown     */
612cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    public interface FrameCallback {
613cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        /**
614cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * Called when a new display frame is being rendered.
615cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * <p>
616cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * This method provides the time in nanoseconds when the frame started being rendered.
617cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * The frame time provides a stable time base for synchronizing animations
618cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
619cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
620cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * time helps to reduce inter-frame jitter because the frame time is fixed at the time
621cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * the frame was scheduled to start, regardless of when the animations or drawing
622cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * callback actually runs.  All callbacks that run as part of rendering a frame will
623cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * observe the same frame time so using the frame time also helps to synchronize effects
624cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * that are performed by different callbacks.
625cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * </p><p>
626cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * Please note that the framework already takes care to process animations and
627cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * drawing using the frame time as a stable time base.  Most applications should
628cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * not need to use the frame time information directly.
629cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * </p>
630cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         *
631cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
632cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
633cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         * to convert it to the {@link SystemClock#uptimeMillis()} time base.
634cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown         */
635cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public void doFrame(long frameTimeNanos);
636cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    }
637cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
638968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    private final class FrameHandler extends Handler {
639968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public FrameHandler(Looper looper) {
640968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            super(looper);
641968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
642968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
643968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        @Override
644968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        public void handleMessage(Message msg) {
645968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            switch (msg.what) {
646ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                case MSG_DO_FRAME:
64720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown                    doFrame(System.nanoTime(), 0);
648968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
649968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                case MSG_DO_SCHEDULE_VSYNC:
650968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    doScheduleVsync();
651968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown                    break;
652ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                case MSG_DO_SCHEDULE_CALLBACK:
653ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown                    doScheduleCallback(msg.arg1);
6542b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown                    break;
655968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown            }
656968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown        }
657968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
658968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
659b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
660b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            implements Runnable {
661b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        private long mTimestampNanos;
662b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        private int mFrame;
663b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown
66496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public FrameDisplayEventReceiver(Looper looper) {
66596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            super(looper);
66696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
66796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
66896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
66996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public void onVsync(long timestampNanos, int frame) {
670b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // Post the vsync event to the Handler.
671b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // The idea is to prevent incoming vsync events from completely starving
672b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // the message queue.  If there are no messages in the queue with timestamps
673b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // earlier than the frame time, then the vsync event will be processed immediately.
674b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            // Otherwise, messages that predate the vsync event will be handled first.
675b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mTimestampNanos = timestampNanos;
676b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mFrame = frame;
677b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            Message msg = Message.obtain(mHandler, this);
678b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            msg.setAsynchronous(true);
679b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
680b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        }
681b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown
682b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        @Override
683b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown        public void run() {
684b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown            doFrame(mTimestampNanos, mFrame);
68596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
68696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
687968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown
688cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown    private static final class CallbackRecord {
689cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public CallbackRecord next;
6907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public long dueTime;
691cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public Object action; // Runnable or FrameCallback
6927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown        public Object token;
693cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown
694cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public void run(long frameTimeNanos) {
695cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            if (token == FRAME_CALLBACK_TOKEN) {
696cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                ((FrameCallback)action).doFrame(frameTimeNanos);
697cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            } else {
698cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                ((Runnable)action).run();
699cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            }
700cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        }
701968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown    }
70243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
70343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown    private final class CallbackQueue {
704cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        private CallbackRecord mHead;
70543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
70643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        public boolean hasDueCallbacksLocked(long now) {
70743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            return mHead != null && mHead.dueTime <= now;
70843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
70943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
710cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public CallbackRecord extractDueCallbacksLocked(long now) {
711cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord callbacks = mHead;
71243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (callbacks == null || callbacks.dueTime > now) {
71343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return null;
71443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
71543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
716cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord last = callbacks;
717cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord next = last.next;
71843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            while (next != null) {
71943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if (next.dueTime > now) {
72043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    last.next = null;
72143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    break;
72243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
72343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                last = next;
72443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                next = next.next;
72543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
72643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            mHead = next;
72743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            return callbacks;
72843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
72943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
730cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public void addCallbackLocked(long dueTime, Object action, Object token) {
731cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
732cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord entry = mHead;
73343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (entry == null) {
73443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                mHead = callback;
73543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return;
73643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
73743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            if (dueTime < entry.dueTime) {
73843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                callback.next = entry;
73943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                mHead = callback;
74043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                return;
74143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
74243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            while (entry.next != null) {
74343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if (dueTime < entry.next.dueTime) {
74443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    callback.next = entry.next;
74543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    break;
74643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
74743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                entry = entry.next;
74843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
74943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            entry.next = callback;
75043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
75143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown
752cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown        public void removeCallbacksLocked(Object action, Object token) {
753cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            CallbackRecord predecessor = null;
754cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown            for (CallbackRecord callback = mHead; callback != null;) {
755cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown                final CallbackRecord next = callback.next;
75643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                if ((action == null || callback.action == action)
75743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        && (token == null || callback.token == token)) {
75843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    if (predecessor != null) {
75943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        predecessor.next = next;
76043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    } else {
76143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                        mHead = next;
76243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    }
76343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    recycleCallbackLocked(callback);
76443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                } else {
76543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                    predecessor = callback;
76643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                }
76743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown                callback = next;
76843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown            }
76943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown        }
77043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown    }
77196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown}
772