Choreographer.java revision b080660dfd69ea6f0a034946b2ff8d94e97a2537
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/** 278bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * Coordinates animations and drawing for UI on a particular thread. 2887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown * 294a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * This object is thread-safe. Other threads can post callbacks to run at a later time 304a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * on the UI thread. 3187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown * 3258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver} 3358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * can only be accessed from the UI thread so operations that touch the event receiver 3458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * are posted to the UI thread if needed. 3558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * 3696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @hide 3796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 38968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brownpublic final class Choreographer { 3996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final String TAG = "Choreographer"; 4096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean DEBUG = false; 4196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 4296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // The default amount of time in ms between animation frames. 4396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // When vsync is not enabled, we want to have some idea of how long we should 4496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // wait before posting the next animation message. It is important that the 4596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // default value be less than the true inter-frame delay on all devices to avoid 4696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // situations where we might skip frames by waiting too long (we must compensate 4796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // for jitter and hardware variations). Regardless of this value, the animation 4896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // and display loop is ultimately rate-limited by how fast new graphics buffers can 4996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // be dequeued. 5096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final long DEFAULT_FRAME_DELAY = 10; 5196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 5296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // The number of milliseconds between animation frames. 5387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY; 5496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 5596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // Thread local storage for the choreographer. 5696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final ThreadLocal<Choreographer> sThreadInstance = 5796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown new ThreadLocal<Choreographer>() { 5896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 5996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown protected Choreographer initialValue() { 6096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Looper looper = Looper.myLooper(); 6196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (looper == null) { 6296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown throw new IllegalStateException("The current thread must have a looper!"); 6396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 6496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return new Choreographer(looper); 6596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 6696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown }; 6796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 68ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown // Enable/disable vsync for animations and drawing. 6996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean USE_VSYNC = SystemProperties.getBoolean( 7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown "debug.choreographer.vsync", true); 7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 7220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown // Enable/disable using the frame time instead of returning now. 7320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean( 7420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown "debug.choreographer.frametime", true); 7520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 7620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown private static final long NANOS_PER_MS = 1000000; 7720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 78ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private static final int MSG_DO_FRAME = 0; 79ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private static final int MSG_DO_SCHEDULE_VSYNC = 1; 80ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private static final int MSG_DO_SCHEDULE_CALLBACK = 2; 8196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 8287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown private final Object mLock = new Object(); 8387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 8496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private final Looper mLooper; 85968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private final FrameHandler mHandler; 861654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown private final FrameDisplayEventReceiver mDisplayEventReceiver; 87968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 88968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private Callback mCallbackPool; 8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 90ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private final CallbackQueue[] mCallbackQueues; 91968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 92ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private boolean mFrameScheduled; 9320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown private boolean mCallbacksRunning; 9420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown private long mLastFrameTimeNanos; 9559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown private long mFrameIntervalNanos; 96ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 97ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown /** 98ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Callback type: Input callback. Runs first. 99ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown */ 100ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public static final int CALLBACK_INPUT = 0; 101ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 102ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown /** 103ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Callback type: Animation callback. Runs before traversals. 104ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown */ 105ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public static final int CALLBACK_ANIMATION = 1; 106ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 107ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown /** 108ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Callback type: Traversal callback. Handles layout and draw. Runs last 109ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * after all other asynchronous messages have been handled. 110ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown */ 111ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public static final int CALLBACK_TRAVERSAL = 2; 112ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 113ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL; 11496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 11596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private Choreographer(Looper looper) { 11696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLooper = looper; 117968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mHandler = new FrameHandler(looper); 1181654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; 11920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown mLastFrameTimeNanos = Long.MIN_VALUE; 12059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown mFrameIntervalNanos = (long)(1000000000 / 12159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown new Display(Display.DEFAULT_DISPLAY, null).getRefreshRate()); 122ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown 123ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; 124ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown for (int i = 0; i <= CALLBACK_LAST; i++) { 125ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mCallbackQueues[i] = new CallbackQueue(); 126ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 12796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 12996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 1308bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * Gets the choreographer for the calling thread. Must be called from 1318bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * a thread that already has a {@link android.os.Looper} associated with it. 13296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 13396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return The choreographer for this thread. 13496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @throws IllegalStateException if the thread does not have a looper. 13596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 13696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static Choreographer getInstance() { 13796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sThreadInstance.get(); 13896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 13996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 14096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 14196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The amount of time, in milliseconds, between each frame of the animation. This is a 14296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * requested time that the animation will attempt to honor, but the actual delay between 14396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * frames may be different, depending on system load and capabilities. This is a static 14496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 14596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 14696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 14796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 14896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 14996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 15096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return the requested time between frames, in milliseconds 15196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 15296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static long getFrameDelay() { 15396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sFrameDelay; 15496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 15596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 15696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 15796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The amount of time, in milliseconds, between each frame of the animation. This is a 15896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * requested time that the animation will attempt to honor, but the actual delay between 15996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * frames may be different, depending on system load and capabilities. This is a static 16096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 16196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 16296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 16396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 16496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 16596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 16696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param frameDelay the requested time between frames, in milliseconds 16796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 16896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static void setFrameDelay(long frameDelay) { 16996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown sFrameDelay = frameDelay; 17096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 17196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 17296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 1737ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * Subtracts typical frame delay time from a delay interval in milliseconds. 1747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * 1757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * This method can be used to compensate for animation delay times that have baked 1767ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * in assumptions about the frame delay. For example, it's quite common for code to 1777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * assume a 60Hz frame time and bake in a 16ms delay. When we call 1787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * {@link #postAnimationCallbackDelayed} we want to know how long to wait before 1797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * posting the animation callback but let the animation timer take care of the remaining 1807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * frame delay time. 1817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * 1827ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * This method is somewhat conservative about how much of the frame delay it 1837ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * subtracts. It uses the same value returned by {@link #getFrameDelay} which by 1847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * default is 10ms even though many parts of the system assume 16ms. Consequently, 1857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * we might still wait 6ms before posting an animation callback that we want to run 1867ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * on the next frame, but this is much better than waiting a whole 16ms and likely 1877ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * missing the deadline. 1887ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * 1897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param delayMillis The original delay time including an assumed frame delay. 1907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @return The adjusted delay time with the assumed frame delay subtracted out. 1917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown */ 1927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public static long subtractFrameDelay(long delayMillis) { 1937ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long frameDelay = sFrameDelay; 1947ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay; 1957ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 1967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 1977ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown /** 198ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Posts a callback to run on the next frame. 199968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * The callback only runs once and then is automatically removed. 200968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 201ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param callbackType The callback type. 202ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param action The callback action to run during the next frame. 2037ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The callback token, or null if none. 204968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 205ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @see #removeCallbacks 206968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 207ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public void postCallback(int callbackType, Runnable action, Object token) { 208ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown postCallbackDelayed(callbackType, action, token, 0); 209968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 210968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 211968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown /** 212ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Posts a callback to run on the next frame following the specified delay. 2132b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * The callback only runs once and then is automatically removed. 2142b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * 215ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param callbackType The callback type. 216ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param action The callback action to run during the next frame after the specified delay. 2177ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The callback token, or null if none. 2182b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * @param delayMillis The delay time in milliseconds. 2192b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * 220ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @see #removeCallback 2212b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown */ 222ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public void postCallbackDelayed(int callbackType, 223ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Runnable action, Object token, long delayMillis) { 2247ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (action == null) { 2257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown throw new IllegalArgumentException("action must not be null"); 2262b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 227ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (callbackType < 0 || callbackType > CALLBACK_LAST) { 228ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown throw new IllegalArgumentException("callbackType is invalid"); 229ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 2307ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 23143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (DEBUG) { 232ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "PostCallback: type=" + callbackType 233ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown + ", action=" + action + ", token=" + token 23443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown + ", delayMillis=" + delayMillis); 23543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 23643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 2377ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 2387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long now = SystemClock.uptimeMillis(); 2397ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long dueTime = now + delayMillis; 240ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); 2417ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 2427ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (dueTime <= now) { 243ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown scheduleFrameLocked(now); 2447ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } else { 245ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); 246ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown msg.arg1 = callbackType; 247ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown msg.setAsynchronous(true); 2487ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mHandler.sendMessageAtTime(msg, dueTime); 2497ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 2502b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2512b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2522b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown 2532b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown /** 254ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * Removes callbacks that have the specified action and token. 255968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 256ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @param callbackType The callback type. 2577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param action The action property of the callbacks to remove, or null to remove 2587ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * callbacks with any action. 2597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The token property of the callbacks to remove, or null to remove 2607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * callbacks with any token. 261968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 262ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @see #postCallback 263ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown * @see #postCallbackDelayed 264968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 265ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown public void removeCallbacks(int callbackType, Runnable action, Object token) { 266ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (callbackType < 0 || callbackType > CALLBACK_LAST) { 267ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown throw new IllegalArgumentException("callbackType is invalid"); 2682b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2697ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 27043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (DEBUG) { 271ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "RemoveCallbacks: type=" + callbackType 272ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown + ", action=" + action + ", token=" + token); 27343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 27443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 2757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 276ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mCallbackQueues[callbackType].removeCallbacksLocked(action, token); 277ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (action != null && token == null) { 278ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action); 2797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 2802b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2812b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2822b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown 28320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown /** 28420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * Gets the time when the current frame started. The frame time should be used 28520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * instead of {@link SystemClock#uptimeMillis()} to synchronize animations. 28620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * This helps to reduce inter-frame jitter because the frame time is fixed at the 28720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * time the frame was scheduled to start, regardless of when the animations or 28820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * drawing code actually ran. 28920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 29020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * This method should only be called from within a callback. 29120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 29220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * @return The frame start time, in the {@link SystemClock#uptimeMillis()} time base. 29320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 29420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * @throws IllegalStateException if no frame is in progress. 29520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown */ 29620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown public long getFrameTime() { 29720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown return getFrameTimeNanos() / NANOS_PER_MS; 29820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 29920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 30020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown /** 30120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * Same as {@link #getFrameTime()} but with nanosecond precision. 30220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 30320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * @return The frame start time, in the {@link System#nanoTime()} time base. 30420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * 30520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown * @throws IllegalStateException if no frame is in progress. 30620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown */ 30720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown public long getFrameTimeNanos() { 30820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown synchronized (mLock) { 30920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown if (!mCallbacksRunning) { 31020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown throw new IllegalStateException("This method must only be called as " 31120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown + "part of a callback while a frame is in progress."); 31220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 31320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown return USE_FRAME_TIME ? mLastFrameTimeNanos : System.nanoTime(); 31420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 31520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 31620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 317ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown private void scheduleFrameLocked(long now) { 318ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (!mFrameScheduled) { 319ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mFrameScheduled = true; 3204a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (USE_VSYNC) { 3214a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 322ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "Scheduling next frame on vsync."); 3234a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3244a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 3254a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // If running on the Looper thread, then schedule the vsync immediately, 3264a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // otherwise post a message to schedule the vsync from the UI thread 3274a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // as soon as possible. 3284a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (isRunningOnLooperThreadLocked()) { 3297ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleVsyncLocked(); 3304a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 331e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); 332e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown msg.setAsynchronous(true); 333e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown mHandler.sendMessageAtFrontOfQueue(msg); 3344a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3354a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 33620c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown final long nextFrameTime = Math.max( 33720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now); 3384a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 339ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); 3404a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 341ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Message msg = mHandler.obtainMessage(MSG_DO_FRAME); 342e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown msg.setAsynchronous(true); 343ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown mHandler.sendMessageAtTime(msg, nextFrameTime); 3444a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3454a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3464a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3474a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 34820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown void doFrame(long timestampNanos, int frame) { 34959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown final long startNanos; 35087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown synchronized (mLock) { 351ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (!mFrameScheduled) { 35287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown return; // no work to do 35387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 35420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown 35520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown startNanos = System.nanoTime(); 35659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown final long jitterNanos = startNanos - timestampNanos; 35759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown if (jitterNanos >= mFrameIntervalNanos) { 35859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; 35959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown if (DEBUG) { 36059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " 36159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown + "which is more than the frame interval of " 36259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown + (mFrameIntervalNanos * 0.000001f) + " ms! " 36359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown + "Setting frame time to " + (lastFrameOffset * 0.000001f) 36459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown + " ms in the past."); 36559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown } 36659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown timestampNanos = startNanos - lastFrameOffset; 36759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown } 36859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown 36959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown if (timestampNanos < mLastFrameTimeNanos) { 37059bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown if (DEBUG) { 37159bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown Log.d(TAG, "Frame time appears to be going backwards. May be due to a " 37259bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown + "previously skipped frame. Waiting for next vsync"); 37359bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown } 37459bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown scheduleVsyncLocked(); 37559bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown return; 37659bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown } 37759bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown 37859bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown mFrameScheduled = false; 37959bbef0cd781f4933fd8a0a85b6067f36e529e02Jeff Brown mLastFrameTimeNanos = timestampNanos; 38096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 38196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 382ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown doCallbacks(Choreographer.CALLBACK_INPUT); 383ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown doCallbacks(Choreographer.CALLBACK_ANIMATION); 384ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown doCallbacks(Choreographer.CALLBACK_TRAVERSAL); 385968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 38687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (DEBUG) { 38720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown final long endNanos = System.nanoTime(); 388ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "Frame " + frame + ": Finished, took " 38920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown + (endNanos - startNanos) * 0.000001f + " ms, latency " 39020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown + (startNanos - timestampNanos) * 0.000001f + " ms."); 39196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 39296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 39396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 394ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown void doCallbacks(int callbackType) { 3957ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback callbacks; 39687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown synchronized (mLock) { 39720c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown final long now = SystemClock.uptimeMillis(); 39820c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now); 39920c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown if (callbacks == null) { 40020c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown return; 40120c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } 40220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown mCallbacksRunning = true; 40396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 40420c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown try { 405ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown for (Callback c = callbacks; c != null; c = c.next) { 406ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (DEBUG) { 407ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown Log.d(TAG, "RunCallback: type=" + callbackType 408ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown + ", action=" + c.action + ", token=" + c.token 409ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime)); 410ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 411ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown c.action.run(); 412968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 41320c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown } finally { 414ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown synchronized (mLock) { 41520c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown mCallbacksRunning = false; 416ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown do { 417ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown final Callback next = callbacks.next; 418ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown recycleCallbackLocked(callbacks); 419ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown callbacks = next; 420ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } while (callbacks != null); 421ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 42287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 42396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 42496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 425968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doScheduleVsync() { 42658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown synchronized (mLock) { 427ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (mFrameScheduled) { 4287ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleVsyncLocked(); 4297ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 43058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 43158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 43258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 433ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown void doScheduleCallback(int callbackType) { 4347ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 435ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (!mFrameScheduled) { 436ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown final long now = SystemClock.uptimeMillis(); 437ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) { 438ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown scheduleFrameLocked(now); 439ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown } 4407ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 44196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 44296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 44396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 4447ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private void scheduleVsyncLocked() { 4457ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mDisplayEventReceiver.scheduleVsync(); 4467ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 4477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 44858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private boolean isRunningOnLooperThreadLocked() { 44958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown return Looper.myLooper() == mLooper; 45058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 45158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 4527ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private Callback obtainCallbackLocked(long dueTime, Runnable action, Object token) { 453968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown Callback callback = mCallbackPool; 454968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callback == null) { 455968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback = new Callback(); 456968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } else { 457968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mCallbackPool = callback.next; 458968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.next = null; 459968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 4607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.dueTime = dueTime; 4617ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.action = action; 4627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.token = token; 463968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return callback; 464968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 465968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 466968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private void recycleCallbackLocked(Callback callback) { 4677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.action = null; 4687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.token = null; 469968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.next = mCallbackPool; 470968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mCallbackPool = callback; 471968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 472968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 473968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private final class FrameHandler extends Handler { 474968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public FrameHandler(Looper looper) { 475968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown super(looper); 476968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 477968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 478968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown @Override 479968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public void handleMessage(Message msg) { 480968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown switch (msg.what) { 481ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown case MSG_DO_FRAME: 48220c4f87b2916d05e860d11568d7db6b2d340e909Jeff Brown doFrame(System.nanoTime(), 0); 483968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 484968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_SCHEDULE_VSYNC: 485968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doScheduleVsync(); 486968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 487ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown case MSG_DO_SCHEDULE_CALLBACK: 488ebb2d8d708c5c58c79ae88ac2bd10450a856f702Jeff Brown doScheduleCallback(msg.arg1); 4892b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown break; 490968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 491968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 492968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 493968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 494b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown private final class FrameDisplayEventReceiver extends DisplayEventReceiver 495b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown implements Runnable { 496b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown private long mTimestampNanos; 497b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown private int mFrame; 498b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown 49996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public FrameDisplayEventReceiver(Looper looper) { 50096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown super(looper); 50196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 50296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 50396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 50496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void onVsync(long timestampNanos, int frame) { 505b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // Post the vsync event to the Handler. 506b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // The idea is to prevent incoming vsync events from completely starving 507b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // the message queue. If there are no messages in the queue with timestamps 508b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // earlier than the frame time, then the vsync event will be processed immediately. 509b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown // Otherwise, messages that predate the vsync event will be handled first. 510b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown mTimestampNanos = timestampNanos; 511b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown mFrame = frame; 512b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown Message msg = Message.obtain(mHandler, this); 513b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown msg.setAsynchronous(true); 514b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS); 515b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown } 516b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown 517b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown @Override 518b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown public void run() { 519b080660dfd69ea6f0a034946b2ff8d94e97a2537Jeff Brown doFrame(mTimestampNanos, mFrame); 52096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 52196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 522968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 523968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private static final class Callback { 524968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public Callback next; 5257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public long dueTime; 5267ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public Runnable action; 5277ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public Object token; 528968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 52943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 53043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown private final class CallbackQueue { 53143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown private Callback mHead; 53243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 53343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown public boolean hasDueCallbacksLocked(long now) { 53443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return mHead != null && mHead.dueTime <= now; 53543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 53643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 53743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown public Callback extractDueCallbacksLocked(long now) { 53843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown Callback callbacks = mHead; 53943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (callbacks == null || callbacks.dueTime > now) { 54043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return null; 54143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 54243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 54343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown Callback last = callbacks; 54443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown Callback next = last.next; 54543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown while (next != null) { 54643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (next.dueTime > now) { 54743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown last.next = null; 54843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown break; 54943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 55043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown last = next; 55143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown next = next.next; 55243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 55343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown mHead = next; 55443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return callbacks; 55543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 55643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 55743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown public void addCallbackLocked(long dueTime, Runnable action, Object token) { 55843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown Callback callback = obtainCallbackLocked(dueTime, action, token); 55943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown Callback entry = mHead; 56043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (entry == null) { 56143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown mHead = callback; 56243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return; 56343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 56443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (dueTime < entry.dueTime) { 56543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown callback.next = entry; 56643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown mHead = callback; 56743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown return; 56843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 56943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown while (entry.next != null) { 57043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (dueTime < entry.next.dueTime) { 57143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown callback.next = entry.next; 57243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown break; 57343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 57443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown entry = entry.next; 57543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 57643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown entry.next = callback; 57743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 57843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown 57943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown public void removeCallbacksLocked(Runnable action, Object token) { 58043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown Callback predecessor = null; 58143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown for (Callback callback = mHead; callback != null;) { 58243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown final Callback next = callback.next; 58343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if ((action == null || callback.action == action) 58443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown && (token == null || callback.token == token)) { 58543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown if (predecessor != null) { 58643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown predecessor.next = next; 58743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } else { 58843ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown mHead = next; 58943ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 59043ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown recycleCallbackLocked(callback); 59143ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } else { 59243ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown predecessor = callback; 59343ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 59443ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown callback = next; 59543ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 59643ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 59743ea54bdc343a913f62885304796e4ab1bca4ef1Jeff Brown } 59896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown} 599