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; 265182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brownimport android.util.TimeUtils; 275182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown 285182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brownimport java.io.PrintWriter; 2996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 3096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown/** 31cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Coordinates the timing of animations, input and drawing. 32cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 33cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The choreographer receives timing pulses (such as vertical synchronization) 34cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * from the display subsystem then schedules work to occur as part of rendering 35cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * the next display frame. 36cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p> 37cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Applications typically interact with the choreographer indirectly using 38cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * higher level abstractions in the animation framework or the view hierarchy. 39cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Here are some examples of things you can do using the higher-level APIs. 40cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 41cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <ul> 42cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post an animation to be processed on a regular time basis synchronized with 43cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * display frame rendering, use {@link android.animation.ValueAnimator#start}.</li> 44cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display 45cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * frame, use {@link View#postOnAnimation}.</li> 46cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a {@link Runnable} to be invoked once at the beginning of the next display 47cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * frame after a delay, use {@link View#postOnAnimationDelayed}.</li> 48cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the 49cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * next display frame, use {@link View#postInvalidateOnAnimation()} or 50cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li> 51cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in 52cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * sync with display frame rendering, do nothing. This already happens automatically. 53cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link View#onDraw} will be called at the appropriate time.</li> 54cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </ul> 55cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 56cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * However, there are a few cases where you might want to use the functions of the 57cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * choreographer directly in your application. Here are some examples. 58cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 59cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <ul> 60cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>If your application does its rendering in a different thread, possibly using GL, 61cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * or does not use the animation framework or view hierarchy at all 62cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * and you want to ensure that it is appropriately synchronized with the display, then use 63cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * {@link Choreographer#postFrameCallback}.</li> 64cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <li>... and that's about it.</li> 65cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </ul> 66cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 67cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Each {@link Looper} thread has its own choreographer. Other threads can 68cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * post callbacks to run on the choreographer but they will run on the {@link Looper} 69cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * to which the choreographer belongs. 70cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 72968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brownpublic final class Choreographer { 7396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final String TAG = "Choreographer"; 7496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean DEBUG = false; 7596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 7696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // The default amount of time in ms between animation frames. 7796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // When vsync is not enabled, we want to have some idea of how long we should 7896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // wait before posting the next animation message. It is important that the 7996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // default value be less than the true inter-frame delay on all devices to avoid 8096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // situations where we might skip frames by waiting too long (we must compensate 8196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // for jitter and hardware variations). Regardless of this value, the animation 8296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // and display loop is ultimately rate-limited by how fast new graphics buffers can 8396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // be dequeued. 8496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final long DEFAULT_FRAME_DELAY = 10; 8596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 8696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // The number of milliseconds between animation frames. 8787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY; 8896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // Thread local storage for the choreographer. 9096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final ThreadLocal<Choreographer> sThreadInstance = 9196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown new ThreadLocal<Choreographer>() { 9296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 9396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown protected Choreographer initialValue() { 9496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Looper looper = Looper.myLooper(); 9596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (looper == null) { 9696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown throw new IllegalStateException("The current thread must have a looper!"); 9796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 9896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return new Choreographer(looper); 9996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 10096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown }; 10196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 102ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown // Enable/disable vsync for animations and drawing. 10396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean USE_VSYNC = SystemProperties.getBoolean( 10496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown "debug.choreographer.vsync", true); 10596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 10620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown // Enable/disable using the frame time instead of returning now. 10720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean( 10820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown "debug.choreographer.frametime", true); 10920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 1104fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown // Set a limit to warn about skipped frames. 1114fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown // Skipped frames imply jank. 1124fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt( 1134fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown "debug.choreographer.skipwarning", 30); 1144fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown 11520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown private static final long NANOS_PER_MS = 1000000; 11620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 117ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private static final int MSG_DO_FRAME = 0; 118ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private static final int MSG_DO_SCHEDULE_VSYNC = 1; 119ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private static final int MSG_DO_SCHEDULE_CALLBACK = 2; 12096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 121cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown // All frame callbacks posted by applications have this token. 122cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown private static final Object FRAME_CALLBACK_TOKEN = new Object() { 123cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public String toString() { return "FRAME_CALLBACK_TOKEN"; } 124cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown }; 125cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 12687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown private final Object mLock = new Object(); 12787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private final Looper mLooper; 129968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private final FrameHandler mHandler; 130cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 131cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown // The display event receiver can only be accessed by the looper thread to which 132cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown // it is attached. We take care to ensure that we post message to the looper 133cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown // if appropriate when interacting with the display event receiver. 1341654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown private final FrameDisplayEventReceiver mDisplayEventReceiver; 135968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 136cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown private CallbackRecord mCallbackPool; 13796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 138ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private final CallbackQueue[] mCallbackQueues; 139968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 140ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private boolean mFrameScheduled; 14120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown private boolean mCallbacksRunning; 14220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown private long mLastFrameTimeNanos; 14359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown private long mFrameIntervalNanos; 144ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 145ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown /** 146ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Callback type: Input callback. Runs first. 147cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 148ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown */ 149ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public static final int CALLBACK_INPUT = 0; 150ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 151ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown /** 152ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Callback type: Animation callback. Runs before traversals. 153cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 154ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown */ 155ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public static final int CALLBACK_ANIMATION = 1; 156ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 157ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown /** 158ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Callback type: Traversal callback. Handles layout and draw. Runs last 159ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * after all other asynchronous messages have been handled. 160cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 161ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown */ 162ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public static final int CALLBACK_TRAVERSAL = 2; 163ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 164ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL; 16596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 16696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private Choreographer(Looper looper) { 16796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLooper = looper; 168968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mHandler = new FrameHandler(looper); 1691654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; 17020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown mLastFrameTimeNanos = Long.MIN_VALUE; 171d32460c5b7bea7b06e345397fdbaca58d9732dcfJeff Brown 172bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); 173ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 174ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; 175ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown for (int i = 0; i <= CALLBACK_LAST; i++) { 176ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mCallbackQueues[i] = new CallbackQueue(); 177ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 17896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 17996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 180bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown private static float getRefreshRate() { 181bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo( 182bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown Display.DEFAULT_DISPLAY); 183bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown return di.refreshRate; 184bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown } 185bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown 18696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 1878bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * Gets the choreographer for the calling thread. Must be called from 1888bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * a thread that already has a {@link android.os.Looper} associated with it. 18996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 19096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return The choreographer for this thread. 19196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @throws IllegalStateException if the thread does not have a looper. 19296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 19396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static Choreographer getInstance() { 19496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sThreadInstance.get(); 19596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 19696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 19796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 198cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The amount of time, in milliseconds, between each frame of the animation. 199cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 200cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * This is a requested time that the animation will attempt to honor, but the actual delay 201cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * between frames may be different, depending on system load and capabilities. This is a static 20296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 20396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 204cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p> 20596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 20696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 207cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 20896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 20996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return the requested time between frames, in milliseconds 210cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 21196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 21296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static long getFrameDelay() { 21396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sFrameDelay; 21496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 21596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 21696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 217cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The amount of time, in milliseconds, between each frame of the animation. 218cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 219cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * This is a requested time that the animation will attempt to honor, but the actual delay 220cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * between frames may be different, depending on system load and capabilities. This is a static 22196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 22296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 223cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p> 22496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 22596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 226cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 22796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 22896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param frameDelay the requested time between frames, in milliseconds 229cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 23096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 23196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static void setFrameDelay(long frameDelay) { 23296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown sFrameDelay = frameDelay; 23396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 23496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 23596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 2367ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * Subtracts typical frame delay time from a delay interval in milliseconds. 237cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 2387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * This method can be used to compensate for animation delay times that have baked 2397ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * in assumptions about the frame delay. For example, it's quite common for code to 2407ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * assume a 60Hz frame time and bake in a 16ms delay. When we call 2417ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * {@link #postAnimationCallbackDelayed} we want to know how long to wait before 2427ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * posting the animation callback but let the animation timer take care of the remaining 2437ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * frame delay time. 244cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p> 2457ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * This method is somewhat conservative about how much of the frame delay it 2467ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * subtracts. It uses the same value returned by {@link #getFrameDelay} which by 2477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * default is 10ms even though many parts of the system assume 16ms. Consequently, 2487ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * we might still wait 6ms before posting an animation callback that we want to run 2497ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * on the next frame, but this is much better than waiting a whole 16ms and likely 2507ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * missing the deadline. 251cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 2527ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * 2537ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param delayMillis The original delay time including an assumed frame delay. 2547ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @return The adjusted delay time with the assumed frame delay subtracted out. 255cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 2567ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown */ 2577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public static long subtractFrameDelay(long delayMillis) { 2587ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long frameDelay = sFrameDelay; 2597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay; 2607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 2617ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 2625182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown void dump(String prefix, PrintWriter writer) { 2635182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown String innerPrefix = prefix + " "; 2645182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown writer.print(prefix); writer.println("Choreographer:"); 2655182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown writer.print(innerPrefix); writer.print("mFrameScheduled="); 2665182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown writer.println(mFrameScheduled); 2675182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown writer.print(innerPrefix); writer.print("mLastFrameTime="); 2685182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown writer.println(TimeUtils.formatUptime(mLastFrameTimeNanos / 1000000)); 2695182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown } 2705182c780a8b42acd46a06d693ab63a0dd78c6d70Jeff Brown 2717ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown /** 272ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Posts a callback to run on the next frame. 273cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 274cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The callback runs once then is automatically removed. 275cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 276968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 277ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param callbackType The callback type. 278ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param action The callback action to run during the next frame. 2797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The callback token, or null if none. 280968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 281ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @see #removeCallbacks 282cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 283968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 284ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public void postCallback(int callbackType, Runnable action, Object token) { 285ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown postCallbackDelayed(callbackType, action, token, 0); 286968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 287968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 288968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown /** 289cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Posts a callback to run on the next frame after the specified delay. 290cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 291cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The callback runs once then is automatically removed. 292cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 2932b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * 294ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param callbackType The callback type. 295ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param action The callback action to run during the next frame after the specified delay. 2967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The callback token, or null if none. 2972b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * @param delayMillis The delay time in milliseconds. 2982b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * 299ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @see #removeCallback 300cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 3012b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown */ 302ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public void postCallbackDelayed(int callbackType, 303ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Runnable action, Object token, long delayMillis) { 3047ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (action == null) { 3057ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown throw new IllegalArgumentException("action must not be null"); 3062b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 307ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (callbackType < 0 || callbackType > CALLBACK_LAST) { 308ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown throw new IllegalArgumentException("callbackType is invalid"); 309ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 3107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 311cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown postCallbackDelayedInternal(callbackType, action, token, delayMillis); 312cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 313cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 314cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown private void postCallbackDelayedInternal(int callbackType, 315cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown Object action, Object token, long delayMillis) { 31643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (DEBUG) { 317ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "PostCallback: type=" + callbackType 318ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown + ", action=" + action + ", token=" + token 31943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown + ", delayMillis=" + delayMillis); 32043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 32143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 3227ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 3237ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long now = SystemClock.uptimeMillis(); 3247ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long dueTime = now + delayMillis; 325ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); 3267ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 3277ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (dueTime <= now) { 328ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown scheduleFrameLocked(now); 3297ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } else { 330ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); 331ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown msg.arg1 = callbackType; 332ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown msg.setAsynchronous(true); 3337ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mHandler.sendMessageAtTime(msg, dueTime); 3347ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 3352b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 3362b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 3372b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown 3382b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown /** 339ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Removes callbacks that have the specified action and token. 340968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 341ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param callbackType The callback type. 3427ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param action The action property of the callbacks to remove, or null to remove 3437ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * callbacks with any action. 3447ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The token property of the callbacks to remove, or null to remove 3457ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * callbacks with any token. 346968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 347ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @see #postCallback 348ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @see #postCallbackDelayed 349cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 350968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 351ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public void removeCallbacks(int callbackType, Runnable action, Object token) { 352ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (callbackType < 0 || callbackType > CALLBACK_LAST) { 353ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown throw new IllegalArgumentException("callbackType is invalid"); 3542b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 3557ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 356cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown removeCallbacksInternal(callbackType, action, token); 357cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 358cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 359cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown private void removeCallbacksInternal(int callbackType, Object action, Object token) { 36043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (DEBUG) { 361ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "RemoveCallbacks: type=" + callbackType 362ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown + ", action=" + action + ", token=" + token); 36343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 36443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 3657ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 366ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mCallbackQueues[callbackType].removeCallbacksLocked(action, token); 367ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (action != null && token == null) { 368ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action); 3697ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 3702b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 3712b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 3722b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown 37320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown /** 374cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Posts a frame callback to run on the next frame. 375cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 376cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The callback runs once then is automatically removed. 377cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 378cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * 379cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @param callback The frame callback to run during the next frame. 380cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * 381cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @see #postFrameCallbackDelayed 382cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @see #removeFrameCallback 383cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown */ 384cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public void postFrameCallback(FrameCallback callback) { 385cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown postFrameCallbackDelayed(callback, 0); 386cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 387cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 388cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown /** 389cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Posts a frame callback to run on the next frame after the specified delay. 390cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 391cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The callback runs once then is automatically removed. 392cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 393cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * 394cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @param callback The frame callback to run during the next frame. 395cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @param delayMillis The delay time in milliseconds. 396cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * 397cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @see #postFrameCallback 398cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @see #removeFrameCallback 399cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown */ 400cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { 401cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown if (callback == null) { 402cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown throw new IllegalArgumentException("callback must not be null"); 403cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 404cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 405cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown postCallbackDelayedInternal(CALLBACK_ANIMATION, 406cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown callback, FRAME_CALLBACK_TOKEN, delayMillis); 407cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 408cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 409cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown /** 410cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Removes a previously posted frame callback. 411cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * 412cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @param callback The frame callback to remove. 41320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 414cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @see #postFrameCallback 415cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @see #postFrameCallbackDelayed 416cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown */ 417cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public void removeFrameCallback(FrameCallback callback) { 418cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown if (callback == null) { 419cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown throw new IllegalArgumentException("callback must not be null"); 420cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 421cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 422cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN); 423cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 424cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 425cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown /** 426cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Gets the time when the current frame started. 427cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 428cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * This method provides the time in nanoseconds when the frame started being rendered. 429cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The frame time provides a stable time base for synchronizing animations 430cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()} 431cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame 432cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * time helps to reduce inter-frame jitter because the frame time is fixed at the time 433cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * the frame was scheduled to start, regardless of when the animations or drawing 434cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * callback actually runs. All callbacks that run as part of rendering a frame will 435cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * observe the same frame time so using the frame time also helps to synchronize effects 436cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * that are performed by different callbacks. 437cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p> 438cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Please note that the framework already takes care to process animations and 439cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * drawing using the frame time as a stable time base. Most applications should 440cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * not need to use the frame time information directly. 441cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p> 44220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * This method should only be called from within a callback. 443cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 44420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 44520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base. 44620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 44720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * @throws IllegalStateException if no frame is in progress. 448cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 44920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown */ 45020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown public long getFrameTime() { 45120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown return getFrameTimeNanos() / NANOS_PER_MS; 45220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 45320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 45420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown /** 45520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * Same as {@link #getFrameTime()} but with nanosecond precision. 45620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 45720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * @return The frame start time, in the {@link System#nanoTime()} time base. 45820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 45920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * @throws IllegalStateException if no frame is in progress. 460cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @hide 46120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown */ 46220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown public long getFrameTimeNanos() { 46320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown synchronized (mLock) { 46420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown if (!mCallbacksRunning) { 46520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown throw new IllegalStateException("This method must only be called as " 46620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown + "part of a callback while a frame is in progress."); 46720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 46820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime(); 46920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 47020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 47120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 472ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private void scheduleFrameLocked(long now) { 473ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (!mFrameScheduled) { 474ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mFrameScheduled = true; 4754a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (USE_VSYNC) { 4764a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 477ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "Scheduling next frame on vsync."); 4784a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 4794a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 4804a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // If running on the Looper thread, then schedule the vsync immediately, 4814a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // otherwise post a message to schedule the vsync from the UI thread 4824a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // as soon as possible. 4834a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (isRunningOnLooperThreadLocked()) { 4847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleVsyncLocked(); 4854a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 486e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); 487e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown msg.setAsynchronous(true); 488e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown mHandler.sendMessageAtFrontOfQueue(msg); 4894a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 4904a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 49120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown final long nextFrameTime = Math.max( 49220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now); 4934a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 494ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); 4954a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 496ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Message msg = mHandler.obtainMessage(MSG_DO_FRAME); 497e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown msg.setAsynchronous(true); 498ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mHandler.sendMessageAtTime(msg, nextFrameTime); 4994a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 5004a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 5014a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 5024a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 503cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown void doFrame(long frameTimeNanos, int frame) { 50459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown final long startNanos; 50587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown synchronized (mLock) { 506ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (!mFrameScheduled) { 50787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown return; // no work to do 50887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 50920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 51020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown startNanos = System.nanoTime(); 511cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown final long jitterNanos = startNanos - frameTimeNanos; 51259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown if (jitterNanos >= mFrameIntervalNanos) { 5134fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown final long skippedFrames = jitterNanos / mFrameIntervalNanos; 5144fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { 515265f1ccc5128319d81eee70ee2d2ae81573efb11Jeff Brown Log.i(TAG, "Skipped " + skippedFrames + " frames! " 5164fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown + "The application may be doing too much work on its main thread."); 5174fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown } 51859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; 51959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown if (DEBUG) { 52059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " 52159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown + "which is more than the frame interval of " 52259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown + (mFrameIntervalNanos * 0.000001f) + " ms! " 5234fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown + "Skipping " + skippedFrames + " frames and setting frame " 5244fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); 52559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown } 526cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown frameTimeNanos = startNanos - lastFrameOffset; 52759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown } 52859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown 529cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown if (frameTimeNanos < mLastFrameTimeNanos) { 53059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown if (DEBUG) { 53159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown Log.d(TAG, "Frame time appears to be going backwards. May be due to a " 5324fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown + "previously skipped frame. Waiting for next vsync."); 53359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown } 53459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown scheduleVsyncLocked(); 53559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown return; 53659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown } 53759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown 53859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown mFrameScheduled = false; 539cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown mLastFrameTimeNanos = frameTimeNanos; 54096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 54196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 542cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); 543cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); 544cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); 545968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 54687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (DEBUG) { 54720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown final long endNanos = System.nanoTime(); 548ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "Frame " + frame + ": Finished, took " 54920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown + (endNanos - startNanos) * 0.000001f + " ms, latency " 550cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown + (startNanos - frameTimeNanos) * 0.000001f + " ms."); 55196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 55296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 55396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 554cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown void doCallbacks(int callbackType, long frameTimeNanos) { 555cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown CallbackRecord callbacks; 55687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown synchronized (mLock) { 557cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown // We use "now" to determine when callbacks become due because it's possible 558cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown // for earlier processing phases in a frame to post callbacks that should run 559cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown // in a following phase, such as an input event that causes an animation to start. 56020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown final long now = SystemClock.uptimeMillis(); 56120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now); 56220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown if (callbacks == null) { 56320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown return; 56420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 56520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown mCallbacksRunning = true; 56696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 56720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown try { 568cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown for (CallbackRecord c = callbacks; c != null; c = c.next) { 569ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (DEBUG) { 570ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "RunCallback: type=" + callbackType 571ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown + ", action=" + c.action + ", token=" + c.token 572ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); 573ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 574cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown c.run(frameTimeNanos); 575968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 57620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } finally { 577ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown synchronized (mLock) { 57820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown mCallbacksRunning = false; 579ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown do { 580cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown final CallbackRecord next = callbacks.next; 581ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown recycleCallbackLocked(callbacks); 582ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown callbacks = next; 583ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } while (callbacks != null); 584ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 58587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 58696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 58796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 588968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doScheduleVsync() { 58958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown synchronized (mLock) { 590ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (mFrameScheduled) { 5917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleVsyncLocked(); 5927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 59358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 59458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 59558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 596ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown void doScheduleCallback(int callbackType) { 5977ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 598ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (!mFrameScheduled) { 599ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown final long now = SystemClock.uptimeMillis(); 600ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) { 601ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown scheduleFrameLocked(now); 602ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 6037ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 60496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 60596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 60696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 6077ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private void scheduleVsyncLocked() { 6087ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mDisplayEventReceiver.scheduleVsync(); 6097ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 6107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 61158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private boolean isRunningOnLooperThreadLocked() { 61258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown return Looper.myLooper() == mLooper; 61358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 61458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 615cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) { 616cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown CallbackRecord callback = mCallbackPool; 617968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callback == null) { 618cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown callback = new CallbackRecord(); 619968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } else { 620968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mCallbackPool = callback.next; 621968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.next = null; 622968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 6237ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.dueTime = dueTime; 6247ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.action = action; 6257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.token = token; 626968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return callback; 627968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 628968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 629cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown private void recycleCallbackLocked(CallbackRecord callback) { 6307ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.action = null; 6317ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.token = null; 632968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.next = mCallbackPool; 633968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mCallbackPool = callback; 634968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 635968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 636cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown /** 637cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Implement this interface to receive a callback when a new display frame is 638cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * being rendered. The callback is invoked on the {@link Looper} thread to 639cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * which the {@link Choreographer} is attached. 640cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown */ 641cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public interface FrameCallback { 642cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown /** 643cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Called when a new display frame is being rendered. 644cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * <p> 645cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * This method provides the time in nanoseconds when the frame started being rendered. 646cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * The frame time provides a stable time base for synchronizing animations 647cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * and drawing. It should be used instead of {@link SystemClock#uptimeMillis()} 648cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame 649cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * time helps to reduce inter-frame jitter because the frame time is fixed at the time 650cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * the frame was scheduled to start, regardless of when the animations or drawing 651cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * callback actually runs. All callbacks that run as part of rendering a frame will 652cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * observe the same frame time so using the frame time also helps to synchronize effects 653cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * that are performed by different callbacks. 654cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p><p> 655cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * Please note that the framework already takes care to process animations and 656cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * drawing using the frame time as a stable time base. Most applications should 657cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * not need to use the frame time information directly. 658cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * </p> 659cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * 660cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * @param frameTimeNanos The time in nanoseconds when the frame started being rendered, 661cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000} 662cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown * to convert it to the {@link SystemClock#uptimeMillis()} time base. 663cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown */ 664cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public void doFrame(long frameTimeNanos); 665cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 666cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 667968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private final class FrameHandler extends Handler { 668968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public FrameHandler(Looper looper) { 669968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown super(looper); 670968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 671968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 672968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown @Override 673968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public void handleMessage(Message msg) { 674968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown switch (msg.what) { 675ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown case MSG_DO_FRAME: 67620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown doFrame(System.nanoTime(), 0); 677968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 678968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_SCHEDULE_VSYNC: 679968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doScheduleVsync(); 680968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 681ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown case MSG_DO_SCHEDULE_CALLBACK: 682ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown doScheduleCallback(msg.arg1); 6832b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown break; 684968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 685968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 686968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 687968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 688b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown private final class FrameDisplayEventReceiver extends DisplayEventReceiver 689b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown implements Runnable { 6904fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown private boolean mHavePendingVsync; 691b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown private long mTimestampNanos; 692b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown private int mFrame; 693b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown 69496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public FrameDisplayEventReceiver(Looper looper) { 69596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown super(looper); 69696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 69796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 69896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 699e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { 700e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown // Ignore vsync from secondary display. 701e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown // This can be problematic because the call to scheduleVsync() is a one-shot. 702e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown // We need to ensure that we will still receive the vsync from the primary 703e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown // display which is the one we really care about. Ideally we should schedule 704e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown // vsync for a particular display. 705e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown // At this time Surface Flinger won't send us vsyncs for secondary displays 706e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown // but that could change in the future so let's log a message to help us remember 707e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown // that we need to fix this. 7083866f0d581ceaa165710feeee9f37fe1b0d7067dMathias Agopian if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { 709e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown Log.d(TAG, "Received vsync from secondary display, but we don't support " 710e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown + "this case yet. Choreographer needs a way to explicitly request " 711e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown + "vsync for a specific display to ensure it doesn't lose track " 712e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown + "of its scheduled vsync."); 713e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown scheduleVsync(); 714e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown return; 715e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown } 716e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown 717b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // Post the vsync event to the Handler. 718b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // The idea is to prevent incoming vsync events from completely starving 719b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // the message queue. If there are no messages in the queue with timestamps 720b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // earlier than the frame time, then the vsync event will be processed immediately. 721b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // Otherwise, messages that predate the vsync event will be handled first. 7224fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown long now = System.nanoTime(); 7234fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown if (timestampNanos > now) { 7244fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f) 7254fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown + " ms in the future! Check that graphics HAL is generating vsync " 7264fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown + "timestamps using the correct timebase."); 7274fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown timestampNanos = now; 7284fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown } 7294fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown 730ba726113e525823f2594507d098f2d99426655f6Jeff Brown if (mHavePendingVsync) { 731ba726113e525823f2594507d098f2d99426655f6Jeff Brown Log.w(TAG, "Already have a pending vsync event. There should only be " 732ba726113e525823f2594507d098f2d99426655f6Jeff Brown + "one at a time."); 733ba726113e525823f2594507d098f2d99426655f6Jeff Brown } else { 734ba726113e525823f2594507d098f2d99426655f6Jeff Brown mHavePendingVsync = true; 735ba726113e525823f2594507d098f2d99426655f6Jeff Brown } 7364fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown 737b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown mTimestampNanos = timestampNanos; 738b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown mFrame = frame; 739b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown Message msg = Message.obtain(mHandler, this); 740b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown msg.setAsynchronous(true); 741b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS); 742b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown } 743b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown 744b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown @Override 745b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown public void run() { 7464fdf9c6e2a177845bb4cc20f69b83555de209144Jeff Brown mHavePendingVsync = false; 747b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown doFrame(mTimestampNanos, mFrame); 74896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 74996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 750968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 751cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown private static final class CallbackRecord { 752cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public CallbackRecord next; 7537ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public long dueTime; 754cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public Object action; // Runnable or FrameCallback 7557ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public Object token; 756cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown 757cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public void run(long frameTimeNanos) { 758cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown if (token == FRAME_CALLBACK_TOKEN) { 759cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown ((FrameCallback)action).doFrame(frameTimeNanos); 760cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } else { 761cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown ((Runnable)action).run(); 762cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 763cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown } 764968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 76543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 76643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown private final class CallbackQueue { 767cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown private CallbackRecord mHead; 76843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 76943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown public boolean hasDueCallbacksLocked(long now) { 77043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return mHead != null && mHead.dueTime <= now; 77143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 77243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 773cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public CallbackRecord extractDueCallbacksLocked(long now) { 774cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown CallbackRecord callbacks = mHead; 77543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (callbacks == null || callbacks.dueTime > now) { 77643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return null; 77743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 77843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 779cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown CallbackRecord last = callbacks; 780cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown CallbackRecord next = last.next; 78143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown while (next != null) { 78243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (next.dueTime > now) { 78343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown last.next = null; 78443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown break; 78543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 78643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown last = next; 78743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown next = next.next; 78843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 78943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown mHead = next; 79043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return callbacks; 79143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 79243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 793cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public void addCallbackLocked(long dueTime, Object action, Object token) { 794cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown CallbackRecord callback = obtainCallbackLocked(dueTime, action, token); 795cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown CallbackRecord entry = mHead; 79643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (entry == null) { 79743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown mHead = callback; 79843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return; 79943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 80043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (dueTime < entry.dueTime) { 80143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown callback.next = entry; 80243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown mHead = callback; 80343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return; 80443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 80543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown while (entry.next != null) { 80643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (dueTime < entry.next.dueTime) { 80743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown callback.next = entry.next; 80843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown break; 80943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 81043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown entry = entry.next; 81143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 81243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown entry.next = callback; 81343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 81443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 815cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown public void removeCallbacksLocked(Object action, Object token) { 816cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown CallbackRecord predecessor = null; 817cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown for (CallbackRecord callback = mHead; callback != null;) { 818cae804901eb5761e42d5bac7cdd6f15d37e3ceb3Jeff Brown final CallbackRecord next = callback.next; 81943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if ((action == null || callback.action == action) 82043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown && (token == null || callback.token == token)) { 82143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (predecessor != null) { 82243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown predecessor.next = next; 82343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } else { 82443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown mHead = next; 82543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 82643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown recycleCallbackLocked(callback); 82743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } else { 82843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown predecessor = callback; 82943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 83043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown callback = next; 83143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 83243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 83343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 83496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown} 835