Choreographer.java revision 7ae9d5faad5816f7e567ec1ec77e78d746cf7e5c
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 6896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // System property to enable/disable vsync for animations and drawing. 6996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // Enabled by default. 7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean USE_VSYNC = SystemProperties.getBoolean( 7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown "debug.choreographer.vsync", true); 7296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 7396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // System property to enable/disable the use of the vsync / animation timer 7496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // for drawing rather than drawing immediately. 7590a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown // Temporarily disabled by default because postponing performTraversals() violates 7690a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown // assumptions about traversals happening in-order relative to other posted messages. 7790a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown // Bug: 5721047 7896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean USE_ANIMATION_TIMER_FOR_DRAW = SystemProperties.getBoolean( 7990a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown "debug.choreographer.animdraw", false); 8096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 8196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final int MSG_DO_ANIMATION = 0; 8296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final int MSG_DO_DRAW = 1; 8358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private static final int MSG_DO_SCHEDULE_VSYNC = 2; 847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private static final int MSG_DO_SCHEDULE_ANIMATION = 3; 857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private static final int MSG_DO_SCHEDULE_DRAW = 4; 8696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 8787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown private final Object mLock = new Object(); 8887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private final Looper mLooper; 90968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private final FrameHandler mHandler; 911654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown private final FrameDisplayEventReceiver mDisplayEventReceiver; 92968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 93968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private Callback mCallbackPool; 9496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 954a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown private Callback mAnimationCallbacks; 964a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown private Callback mDrawCallbacks; 97968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 9896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private boolean mAnimationScheduled; 9996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private boolean mDrawScheduled; 10096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private long mLastAnimationTime; 10196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private long mLastDrawTime; 10296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 10396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private Choreographer(Looper looper) { 10496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLooper = looper; 105968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mHandler = new FrameHandler(looper); 1061654d0b8d9ba477a0134338838b6e5921f1aabb8Jeff Brown mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; 10796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastAnimationTime = Long.MIN_VALUE; 10896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastDrawTime = Long.MIN_VALUE; 10996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 11096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 11196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 1128bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * Gets the choreographer for the calling thread. Must be called from 1138bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * a thread that already has a {@link android.os.Looper} associated with it. 11496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 11596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return The choreographer for this thread. 11696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @throws IllegalStateException if the thread does not have a looper. 11796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 11896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static Choreographer getInstance() { 11996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sThreadInstance.get(); 12096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 12196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 12296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 12396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The amount of time, in milliseconds, between each frame of the animation. This is a 12496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * requested time that the animation will attempt to honor, but the actual delay between 12596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * frames may be different, depending on system load and capabilities. This is a static 12696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 12796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 12996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 13096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 13196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 13296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return the requested time between frames, in milliseconds 13396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 13496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static long getFrameDelay() { 13596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sFrameDelay; 13696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 13796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 13896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 13996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The amount of time, in milliseconds, between each frame of the animation. This is a 14096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * requested time that the animation will attempt to honor, but the actual delay between 14196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * frames may be different, depending on system load and capabilities. This is a static 14296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 14396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 14496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 14596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 14696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 14796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 14896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param frameDelay the requested time between frames, in milliseconds 14996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 15096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static void setFrameDelay(long frameDelay) { 15196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown sFrameDelay = frameDelay; 15296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 15396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 15496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 1557ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * Subtracts typical frame delay time from a delay interval in milliseconds. 1567ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * 1577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * This method can be used to compensate for animation delay times that have baked 1587ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * in assumptions about the frame delay. For example, it's quite common for code to 1597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * assume a 60Hz frame time and bake in a 16ms delay. When we call 1607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * {@link #postAnimationCallbackDelayed} we want to know how long to wait before 1617ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * posting the animation callback but let the animation timer take care of the remaining 1627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * frame delay time. 1637ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * 1647ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * This method is somewhat conservative about how much of the frame delay it 1657ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * subtracts. It uses the same value returned by {@link #getFrameDelay} which by 1667ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * default is 10ms even though many parts of the system assume 16ms. Consequently, 1677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * we might still wait 6ms before posting an animation callback that we want to run 1687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * on the next frame, but this is much better than waiting a whole 16ms and likely 1697ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * missing the deadline. 1707ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * 1717ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param delayMillis The original delay time including an assumed frame delay. 1727ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @return The adjusted delay time with the assumed frame delay subtracted out. 1737ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown */ 1747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public static long subtractFrameDelay(long delayMillis) { 1757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long frameDelay = sFrameDelay; 1767ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay; 1777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 1787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 1797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown /** 1802b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * Posts a callback to run on the next animation cycle. 181968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * The callback only runs once and then is automatically removed. 182968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 1837ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param action The callback action to run during the next animation cycle. 1847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The callback token, or null if none. 185968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 1864a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * @see #removeAnimationCallback 187968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 1887ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public void postAnimationCallback(Runnable action, Object token) { 1897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown postAnimationCallbackDelayed(action, token, 0); 190968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 191968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 192968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown /** 1932b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * Posts a callback to run on the next animation cycle following the specified delay. 1942b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * The callback only runs once and then is automatically removed. 1952b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * 1967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param action The callback action to run during the next animation cycle after 1972b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * the specified delay. 1987ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The callback token, or null if none. 1992b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * @param delayMillis The delay time in milliseconds. 2002b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * 2012b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * @see #removeAnimationCallback 2022b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown */ 2037ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public void postAnimationCallbackDelayed(Runnable action, Object token, long delayMillis) { 2047ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (action == null) { 2057ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown throw new IllegalArgumentException("action must not be null"); 2062b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2077ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 2087ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 2097ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long now = SystemClock.uptimeMillis(); 2107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long dueTime = now + delayMillis; 2117ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, dueTime, action, token); 2127ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 2137ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (dueTime <= now) { 2147ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleAnimationLocked(now); 2157ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } else { 2167ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_ANIMATION, action); 2177ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mHandler.sendMessageAtTime(msg, dueTime); 2187ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 2192b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2202b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2212b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown 2222b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown /** 2237ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * Removes animation callbacks that have the specified action and token. 224968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 2257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param action The action property of the callbacks to remove, or null to remove 2267ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * callbacks with any action. 2277ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The token property of the callbacks to remove, or null to remove 2287ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * callbacks with any token. 229968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 2304a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * @see #postAnimationCallback 2312b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * @see #postAnimationCallbackDelayed 232968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 2337ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public void removeAnimationCallbacks(Runnable action, Object token) { 234968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 2357ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mAnimationCallbacks = removeCallbacksLocked(mAnimationCallbacks, action, token); 2367ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (action != null && token == null) { 2377ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mHandler.removeMessages(MSG_DO_SCHEDULE_ANIMATION, action); 2387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 239968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 240968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 241968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 242968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown /** 2432b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * Posts a callback to run on the next draw cycle. 244968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * The callback only runs once and then is automatically removed. 245968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 2467ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param action The callback action to run during the next draw cycle. 2477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The callback token, or null if none. 248968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 2494a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * @see #removeDrawCallback 250968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 2517ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public void postDrawCallback(Runnable action, Object token) { 2527ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown postDrawCallbackDelayed(action, token, 0); 253968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 254968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 255968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown /** 2562b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * Posts a callback to run on the next draw cycle following the specified delay. 2572b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * The callback only runs once and then is automatically removed. 2582b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * 2597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param action The callback action to run during the next animation cycle after 2602b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * the specified delay. 2617ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The callback token, or null if none. 2622b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * @param delayMillis The delay time in milliseconds. 2632b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * 2642b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * @see #removeDrawCallback 2652b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown */ 2667ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public void postDrawCallbackDelayed(Runnable action, Object token, long delayMillis) { 2677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (action == null) { 2687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown throw new IllegalArgumentException("action must not be null"); 2692b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2707ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 2717ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 2727ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long now = SystemClock.uptimeMillis(); 2737ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long dueTime = now + delayMillis; 2747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mDrawCallbacks = addCallbackLocked(mDrawCallbacks, dueTime, action, token); 2757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleDrawLocked(now); 2767ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 2777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (dueTime <= now) { 2787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleDrawLocked(now); 2797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } else { 2807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_DRAW, action); 2817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mHandler.sendMessageAtTime(msg, dueTime); 2827ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 2832b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2842b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown } 2852b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown 2862b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown /** 2877ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * Removes draw callbacks that have the specified action and token. 288968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 2897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param action The action property of the callbacks to remove, or null to remove 2907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * callbacks with any action. 2917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * @param token The token property of the callbacks to remove, or null to remove 2927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown * callbacks with any token. 293968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 2944a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * @see #postDrawCallback 2952b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown * @see #postDrawCallbackDelayed 296968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 2977ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public void removeDrawCallbacks(Runnable action, Object token) { 298968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 2997ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mDrawCallbacks = removeCallbacksLocked(mDrawCallbacks, action, token); 3007ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (action != null && token == null) { 3017ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mHandler.removeMessages(MSG_DO_SCHEDULE_DRAW, action); 3027ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 3034a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3044a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3054a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 3067ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private void scheduleAnimationLocked(long now) { 3074a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (!mAnimationScheduled) { 3084a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mAnimationScheduled = true; 3094a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (USE_VSYNC) { 3104a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 3114a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown Log.d(TAG, "Scheduling vsync for animation."); 3124a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3134a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 3144a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // If running on the Looper thread, then schedule the vsync immediately, 3154a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // otherwise post a message to schedule the vsync from the UI thread 3164a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // as soon as possible. 3174a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (isRunningOnLooperThreadLocked()) { 3187ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleVsyncLocked(); 3194a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 320e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); 321e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown msg.setAsynchronous(true); 322e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown mHandler.sendMessageAtFrontOfQueue(msg); 3234a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3244a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 3254a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); 3264a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 3274a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); 3284a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 329e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown Message msg = mHandler.obtainMessage(MSG_DO_ANIMATION); 330e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown msg.setAsynchronous(true); 331e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown mHandler.sendMessageAtTime(msg, nextAnimationTime); 3324a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3334a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3344a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 3354a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 3367ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private void scheduleDrawLocked(long now) { 3374a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (!mDrawScheduled) { 3384a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mDrawScheduled = true; 3394a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (USE_ANIMATION_TIMER_FOR_DRAW) { 3407ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleAnimationLocked(now); 3414a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 3424a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 3434a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown Log.d(TAG, "Scheduling draw immediately."); 3444a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 345e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown Message msg = mHandler.obtainMessage(MSG_DO_DRAW); 346e0dbd002750856e55d637e883b629e09adfc8a4eJeff Brown msg.setAsynchronous(true); 3477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mHandler.sendMessageAtTime(msg, now); 3484a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 34996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 35096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 35196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 352968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doAnimation() { 35387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown doAnimationInner(); 35487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 35587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (USE_ANIMATION_TIMER_FOR_DRAW) { 35687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown doDraw(); 35787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 35887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 35987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 360968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doAnimationInner() { 36187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown final long start; 3627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback callbacks; 36387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown synchronized (mLock) { 36487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (!mAnimationScheduled) { 36587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown return; // no work to do 36687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 36796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mAnimationScheduled = false; 36896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 36987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown start = SystemClock.uptimeMillis(); 37096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 37196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime) 37296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown + " ms have elapsed since previous animation."); 37396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 37496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastAnimationTime = start; 37596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 3764a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown callbacks = mAnimationCallbacks; 3777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (callbacks != null) { 3787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (callbacks.dueTime > start) { 3797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callbacks = null; 3807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } else { 3817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback predecessor = callbacks; 3827ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback successor = predecessor.next; 3837ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown while (successor != null) { 3847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (successor.dueTime > start) { 3857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown predecessor.next = null; 3867ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown break; 3877ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 3887ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown predecessor = successor; 3897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown successor = successor.next; 3907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 3917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mAnimationCallbacks = successor; 3927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 3937ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 39496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 39596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 396968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callbacks != null) { 397968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown runCallbacks(callbacks); 398968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 399968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown recycleCallbacksLocked(callbacks); 400968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 401968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 402968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 40387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (DEBUG) { 40487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms."); 40596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 40696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 40796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 408968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doDraw() { 40987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown final long start; 4107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback callbacks; 41187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown synchronized (mLock) { 41287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (!mDrawScheduled) { 41387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown return; // no work to do 41487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 41596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mDrawScheduled = false; 41696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 41787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown start = SystemClock.uptimeMillis(); 41896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 41996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Performing draw: " + Math.max(0, start - mLastDrawTime) 42096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown + " ms have elapsed since previous draw."); 42196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 42296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastDrawTime = start; 42396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 4244a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown callbacks = mDrawCallbacks; 4257ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (callbacks != null) { 4267ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (callbacks.dueTime > start) { 4277ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callbacks = null; 4287ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } else { 4297ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback predecessor = callbacks; 4307ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback successor = predecessor.next; 4317ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown while (successor != null) { 4327ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (successor.dueTime > start) { 4337ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown predecessor.next = null; 4347ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown break; 4357ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 4367ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown predecessor = successor; 4377ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown successor = successor.next; 4387ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 4397ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mDrawCallbacks = successor; 4407ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 4417ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 44296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 44387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 444968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callbacks != null) { 445968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown runCallbacks(callbacks); 446968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 447968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown recycleCallbacksLocked(callbacks); 448968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 449968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 450968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 45187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (DEBUG) { 45287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms."); 45387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 45496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 45596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 456968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doScheduleVsync() { 45758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown synchronized (mLock) { 4587ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (mAnimationScheduled) { 4597ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleVsyncLocked(); 4607ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 46158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 46258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 46358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 4647ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown void doScheduleAnimation() { 4657ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 4667ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long now = SystemClock.uptimeMillis(); 4677ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (mAnimationCallbacks != null && mAnimationCallbacks.dueTime <= now) { 4687ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleAnimationLocked(now); 4697ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 47096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 47196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 47296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 4737ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown void doScheduleDraw() { 4747ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown synchronized (mLock) { 4757ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown final long now = SystemClock.uptimeMillis(); 4767ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (mDrawCallbacks != null && mDrawCallbacks.dueTime <= now) { 4777ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown scheduleDrawLocked(now); 4787ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 4797ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 4807ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 4817ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 4827ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private void scheduleVsyncLocked() { 4837ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown mDisplayEventReceiver.scheduleVsync(); 4847ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 4857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown 48658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private boolean isRunningOnLooperThreadLocked() { 48758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown return Looper.myLooper() == mLooper; 48858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 48958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 4907ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private Callback addCallbackLocked(Callback head, 4917ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown long dueTime, Runnable action, Object token) { 4927ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback callback = obtainCallbackLocked(dueTime, action, token); 493968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (head == null) { 494968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return callback; 495968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 4967ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown Callback entry = head; 4977ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (dueTime < entry.dueTime) { 4987ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.next = entry; 4997ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown return callback; 5007ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 5017ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown while (entry.next != null) { 5027ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if (dueTime < entry.next.dueTime) { 5037ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.next = entry.next; 5047ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown break; 5057ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown } 5067ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown entry = entry.next; 507968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 5087ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown entry.next = callback; 509968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return head; 510968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 511968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 5127ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private Callback removeCallbacksLocked(Callback head, Runnable action, Object token) { 513968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown Callback predecessor = null; 514968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown for (Callback callback = head; callback != null;) { 515968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown final Callback next = callback.next; 5167ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown if ((action == null || callback.action == action) 5177ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown && (token == null || callback.token == token)) { 518968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (predecessor != null) { 519968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown predecessor.next = next; 520968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } else { 521968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown head = next; 522968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 523968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown recycleCallbackLocked(callback); 524968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } else { 525968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown predecessor = callback; 526968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 527968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback = next; 528968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 529968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return head; 530968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 531968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 532968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private void runCallbacks(Callback head) { 533968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown while (head != null) { 5347ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown head.action.run(); 535968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown head = head.next; 536968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 537968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 538968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 539968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private void recycleCallbacksLocked(Callback head) { 540968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown while (head != null) { 541968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown final Callback next = head.next; 542968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown recycleCallbackLocked(head); 543968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown head = next; 544968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 545968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 546968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 5477ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown private Callback obtainCallbackLocked(long dueTime, Runnable action, Object token) { 548968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown Callback callback = mCallbackPool; 549968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callback == null) { 550968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback = new Callback(); 551968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } else { 552968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mCallbackPool = callback.next; 553968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.next = null; 554968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 5557ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.dueTime = dueTime; 5567ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.action = action; 5577ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.token = token; 558968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return callback; 559968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 560968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 561968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private void recycleCallbackLocked(Callback callback) { 5627ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.action = null; 5637ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown callback.token = null; 564968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.next = mCallbackPool; 565968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mCallbackPool = callback; 566968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 567968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 568968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private final class FrameHandler extends Handler { 569968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public FrameHandler(Looper looper) { 570968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown super(looper); 571968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 572968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 573968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown @Override 574968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public void handleMessage(Message msg) { 575968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown switch (msg.what) { 576968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_ANIMATION: 577968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doAnimation(); 578968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 579968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_DRAW: 580968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doDraw(); 581968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 582968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_SCHEDULE_VSYNC: 583968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doScheduleVsync(); 584968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 5857ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown case MSG_DO_SCHEDULE_ANIMATION: 5867ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown doScheduleAnimation(); 5872b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown break; 5887ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown case MSG_DO_SCHEDULE_DRAW: 5897ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown doScheduleDraw(); 5902b6cb9a27e6f11fb30c9b9baaa5fc02f29f4072eJeff Brown break; 591968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 592968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 593968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 594968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 59596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private final class FrameDisplayEventReceiver extends DisplayEventReceiver { 59696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public FrameDisplayEventReceiver(Looper looper) { 59796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown super(looper); 59896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 59996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 60096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 60196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void onVsync(long timestampNanos, int frame) { 60296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown doAnimation(); 60396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 60496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 605968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 606968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private static final class Callback { 607968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public Callback next; 6087ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public long dueTime; 6097ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public Runnable action; 6107ae9d5faad5816f7e567ec1ec77e78d746cf7e5cJeff Brown public Object token; 611968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 61296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown} 613