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