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