Choreographer.java revision 4a06c8008b2edd6677f9a411af79b0a4971b87fe
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 4258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown // Amount of time in ms to wait before actually disposing of the display event 434a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // receiver when it has not been needed for some time. 444a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown private static final long DISPOSE_RECEIVER_DELAY = 30 * 1000; 4558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 4696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // The default amount of time in ms between animation frames. 4796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // When vsync is not enabled, we want to have some idea of how long we should 4896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // wait before posting the next animation message. It is important that the 4996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // default value be less than the true inter-frame delay on all devices to avoid 5096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // situations where we might skip frames by waiting too long (we must compensate 5196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // for jitter and hardware variations). Regardless of this value, the animation 5296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // and display loop is ultimately rate-limited by how fast new graphics buffers can 5396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // be dequeued. 5496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final long DEFAULT_FRAME_DELAY = 10; 5596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 5696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // The number of milliseconds between animation frames. 5787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY; 5896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 5996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // Thread local storage for the choreographer. 6096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final ThreadLocal<Choreographer> sThreadInstance = 6196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown new ThreadLocal<Choreographer>() { 6296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 6396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown protected Choreographer initialValue() { 6496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Looper looper = Looper.myLooper(); 6596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (looper == null) { 6696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown throw new IllegalStateException("The current thread must have a looper!"); 6796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 6896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return new Choreographer(looper); 6996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown }; 7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 7296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // System property to enable/disable vsync for animations and drawing. 7396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // Enabled by default. 7496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean USE_VSYNC = SystemProperties.getBoolean( 7596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown "debug.choreographer.vsync", true); 7696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 7796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // System property to enable/disable the use of the vsync / animation timer 7896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // for drawing rather than drawing immediately. 7990a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown // Temporarily disabled by default because postponing performTraversals() violates 8090a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown // assumptions about traversals happening in-order relative to other posted messages. 8190a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown // Bug: 5721047 8296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean USE_ANIMATION_TIMER_FOR_DRAW = SystemProperties.getBoolean( 8390a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown "debug.choreographer.animdraw", false); 8496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 8596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final int MSG_DO_ANIMATION = 0; 8696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final int MSG_DO_DRAW = 1; 8758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private static final int MSG_DO_SCHEDULE_VSYNC = 2; 8858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private static final int MSG_DO_DISPOSE_RECEIVER = 3; 8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 9087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown private final Object mLock = new Object(); 9187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 9296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private final Looper mLooper; 93968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private final FrameHandler mHandler; 94968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 95968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private Callback mCallbackPool; 9696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 974a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown private Callback mAnimationCallbacks; 984a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown private Callback mDrawCallbacks; 99968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 10096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private boolean mAnimationScheduled; 10196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private boolean mDrawScheduled; 10258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private boolean mFrameDisplayEventReceiverNeeded; 10396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private FrameDisplayEventReceiver mFrameDisplayEventReceiver; 10496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private long mLastAnimationTime; 10596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private long mLastDrawTime; 10696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 10796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private Choreographer(Looper looper) { 10896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLooper = looper; 109968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mHandler = new FrameHandler(looper); 11096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastAnimationTime = Long.MIN_VALUE; 11196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastDrawTime = Long.MIN_VALUE; 11296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 11396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 11496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 1158bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * Gets the choreographer for the calling thread. Must be called from 1168bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * a thread that already has a {@link android.os.Looper} associated with it. 11796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 11896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return The choreographer for this thread. 11996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @throws IllegalStateException if the thread does not have a looper. 12096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 12196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static Choreographer getInstance() { 12296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sThreadInstance.get(); 12396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 12496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 12596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 12696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The amount of time, in milliseconds, between each frame of the animation. This is a 12796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * requested time that the animation will attempt to honor, but the actual delay between 12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * frames may be different, depending on system load and capabilities. This is a static 12996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 13096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 13196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 13296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 13396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 13496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 13596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return the requested time between frames, in milliseconds 13696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 13796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static long getFrameDelay() { 13896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sFrameDelay; 13996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 14096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 14196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 14296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The amount of time, in milliseconds, between each frame of the animation. This is a 14396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * requested time that the animation will attempt to honor, but the actual delay between 14496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * frames may be different, depending on system load and capabilities. This is a static 14596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 14696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 14796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 14896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 14996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 15096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 15196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param frameDelay the requested time between frames, in milliseconds 15296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 15396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static void setFrameDelay(long frameDelay) { 15496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown sFrameDelay = frameDelay; 15596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 15696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 15796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 158968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * Posts a callback to run on the next animation cycle and schedules an animation cycle. 159968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * The callback only runs once and then is automatically removed. 160968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 161968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * @param runnable The callback to run during the next animation cycle. 162968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 1634a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * @see #removeAnimationCallback 164968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 1654a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown public void postAnimationCallback(Runnable runnable) { 166968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (runnable == null) { 167968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown throw new IllegalArgumentException("runnable must not be null"); 168968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 169968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 1704a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, runnable); 1714a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown scheduleAnimationLocked(); 172968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 173968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 174968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 175968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown /** 176968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * Removes an animation callback. 177968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * Does nothing if the specified animation callback has not been posted or has already 178968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * been removed. 179968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 180968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * @param runnable The animation callback to remove. 181968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 1824a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * @see #postAnimationCallback 183968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 1844a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown public void removeAnimationCallback(Runnable runnable) { 185968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (runnable == null) { 186968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown throw new IllegalArgumentException("runnable must not be null"); 187968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 188968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 1894a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mAnimationCallbacks = removeCallbackLocked(mAnimationCallbacks, runnable); 1904a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown stopTimingLoopIfNoCallbacksLocked(); 191968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 192968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 193968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 194968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown /** 195968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * Posts a callback to run on the next draw cycle and schedules a draw cycle. 196968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * The callback only runs once and then is automatically removed. 197968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 198968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * @param runnable The callback to run during the next draw cycle. 199968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 2004a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * @see #removeDrawCallback 201968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 2024a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown public void postDrawCallback(Runnable runnable) { 203968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (runnable == null) { 204968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown throw new IllegalArgumentException("runnable must not be null"); 205968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 206968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 2074a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mDrawCallbacks = addCallbackLocked(mDrawCallbacks, runnable); 208968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown scheduleDrawLocked(); 209968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 210968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 211968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 212968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown /** 213968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * Removes a draw callback. 214968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * Does nothing if the specified draw callback has not been posted or has already 215968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * been removed. 216968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 217968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * @param runnable The draw callback to remove. 218968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown * 2194a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown * @see #postDrawCallback 220968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown */ 2214a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown public void removeDrawCallback(Runnable runnable) { 222968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (runnable == null) { 223968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown throw new IllegalArgumentException("runnable must not be null"); 224968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 225968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 2264a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mDrawCallbacks = removeCallbackLocked(mDrawCallbacks, runnable); 2274a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown stopTimingLoopIfNoCallbacksLocked(); 2284a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2294a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2304a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 2314a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown private void scheduleAnimationLocked() { 2324a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (!mAnimationScheduled) { 2334a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mAnimationScheduled = true; 2344a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (USE_VSYNC) { 2354a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 2364a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown Log.d(TAG, "Scheduling vsync for animation."); 2374a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2384a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 2394a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // If running on the Looper thread, then schedule the vsync immediately, 2404a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // otherwise post a message to schedule the vsync from the UI thread 2414a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown // as soon as possible. 2424a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (!mFrameDisplayEventReceiverNeeded) { 2434a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mFrameDisplayEventReceiverNeeded = true; 2444a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (mFrameDisplayEventReceiver != null) { 2454a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mHandler.removeMessages(MSG_DO_DISPOSE_RECEIVER); 2464a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2474a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2484a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (isRunningOnLooperThreadLocked()) { 2494a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown doScheduleVsyncLocked(); 2504a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 2514a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mHandler.sendMessageAtFrontOfQueue( 2524a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC)); 2534a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2544a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 2554a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown final long now = SystemClock.uptimeMillis(); 2564a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); 2574a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 2584a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); 2594a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2604a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mHandler.sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime); 2614a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2624a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2634a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2644a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown 2654a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown private void scheduleDrawLocked() { 2664a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (!mDrawScheduled) { 2674a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mDrawScheduled = true; 2684a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (USE_ANIMATION_TIMER_FOR_DRAW) { 2694a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown scheduleAnimationLocked(); 2704a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } else { 2714a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (DEBUG) { 2724a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown Log.d(TAG, "Scheduling draw immediately."); 2734a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 2744a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mHandler.sendEmptyMessage(MSG_DO_DRAW); 2754a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown } 27696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 27796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 27896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 279968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doAnimation() { 28087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown doAnimationInner(); 28187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 28287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (USE_ANIMATION_TIMER_FOR_DRAW) { 28387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown doDraw(); 28487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 28587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 28687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 287968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doAnimationInner() { 28887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown final long start; 289968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown final Callback callbacks; 29087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown synchronized (mLock) { 29187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (!mAnimationScheduled) { 29287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown return; // no work to do 29387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 29496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mAnimationScheduled = false; 29596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 29687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown start = SystemClock.uptimeMillis(); 29796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 29896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime) 29996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown + " ms have elapsed since previous animation."); 30096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 30196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastAnimationTime = start; 30296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 3034a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown callbacks = mAnimationCallbacks; 3044a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mAnimationCallbacks = null; 30596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 30696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 307968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callbacks != null) { 308968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown runCallbacks(callbacks); 309968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 310968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown recycleCallbacksLocked(callbacks); 311968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 312968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 313968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 31487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (DEBUG) { 31587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms."); 31696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 31796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 31896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 319968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doDraw() { 32087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown final long start; 321968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown final Callback callbacks; 32287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown synchronized (mLock) { 32387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (!mDrawScheduled) { 32487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown return; // no work to do 32587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 32696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mDrawScheduled = false; 32796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 32887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown start = SystemClock.uptimeMillis(); 32996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 33096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Performing draw: " + Math.max(0, start - mLastDrawTime) 33196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown + " ms have elapsed since previous draw."); 33296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 33396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastDrawTime = start; 33496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 3354a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown callbacks = mDrawCallbacks; 3364a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown mDrawCallbacks = null; 33796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 33887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown 339968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callbacks != null) { 340968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown runCallbacks(callbacks); 341968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown synchronized (mLock) { 342968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown recycleCallbacksLocked(callbacks); 343968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 344968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 345968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 34687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown if (DEBUG) { 34787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms."); 34887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown } 34996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 35096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 351968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doScheduleVsync() { 35258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown synchronized (mLock) { 35358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown doScheduleVsyncLocked(); 35458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 35558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 35658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 35758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private void doScheduleVsyncLocked() { 35858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown if (mFrameDisplayEventReceiverNeeded && mAnimationScheduled) { 35958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown if (mFrameDisplayEventReceiver == null) { 36058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper); 36158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 36258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown mFrameDisplayEventReceiver.scheduleVsync(); 36358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 36458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 36558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 366968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown void doDisposeReceiver() { 36758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown synchronized (mLock) { 36858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown if (!mFrameDisplayEventReceiverNeeded && mFrameDisplayEventReceiver != null) { 36958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown mFrameDisplayEventReceiver.dispose(); 37058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown mFrameDisplayEventReceiver = null; 37158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 37258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 37358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 37458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 3754a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown private void stopTimingLoopIfNoCallbacksLocked() { 3764a06c8008b2edd6677f9a411af79b0a4971b87feJeff Brown if (mAnimationCallbacks == null && mDrawCallbacks == null) { 37796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 37896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Stopping timing loop."); 37996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 38096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 38196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mAnimationScheduled) { 38296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mAnimationScheduled = false; 38358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown if (USE_VSYNC) { 384968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mHandler.removeMessages(MSG_DO_SCHEDULE_VSYNC); 38558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } else { 386968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mHandler.removeMessages(MSG_DO_ANIMATION); 38796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 38896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 38996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 39096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mDrawScheduled) { 39196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mDrawScheduled = false; 39296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (!USE_ANIMATION_TIMER_FOR_DRAW) { 393968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mHandler.removeMessages(MSG_DO_DRAW); 39496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 39596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 39696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 39758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown // Post a message to dispose the display event receiver if we haven't needed 39858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown // it again after a certain amount of time has elapsed. Another reason to 39958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown // defer disposal is that it is possible for use to attempt to dispose the 40058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown // receiver while handling a vsync event that it dispatched, which might 40158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown // cause a few problems... 40258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown if (mFrameDisplayEventReceiverNeeded) { 40358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown mFrameDisplayEventReceiverNeeded = false; 40458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown if (mFrameDisplayEventReceiver != null) { 405968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mHandler.sendEmptyMessageDelayed(MSG_DO_DISPOSE_RECEIVER, 406968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown DISPOSE_RECEIVER_DELAY); 40758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 40896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 40996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 41096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 41196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 41258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown private boolean isRunningOnLooperThreadLocked() { 41358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown return Looper.myLooper() == mLooper; 41458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown } 41558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown 416968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private Callback addCallbackLocked(Callback head, Runnable runnable) { 417968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown Callback callback = obtainCallbackLocked(runnable); 418968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (head == null) { 419968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return callback; 420968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 421968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown Callback tail = head; 422968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown while (tail.next != null) { 423968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown tail = tail.next; 424968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 425968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown tail.next = callback; 426968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return head; 427968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 428968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 429968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private Callback removeCallbackLocked(Callback head, Runnable runnable) { 430968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown Callback predecessor = null; 431968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown for (Callback callback = head; callback != null;) { 432968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown final Callback next = callback.next; 433968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callback.runnable == runnable) { 434968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (predecessor != null) { 435968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown predecessor.next = next; 436968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } else { 437968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown head = next; 438968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 439968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown recycleCallbackLocked(callback); 440968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } else { 441968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown predecessor = callback; 442968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 443968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback = next; 444968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 445968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return head; 446968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 447968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 448968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private void runCallbacks(Callback head) { 449968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown while (head != null) { 450968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown head.runnable.run(); 451968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown head = head.next; 452968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 453968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 454968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 455968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private void recycleCallbacksLocked(Callback head) { 456968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown while (head != null) { 457968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown final Callback next = head.next; 458968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown recycleCallbackLocked(head); 459968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown head = next; 460968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 461968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 462968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 463968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private Callback obtainCallbackLocked(Runnable runnable) { 464968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown Callback callback = mCallbackPool; 465968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown if (callback == null) { 466968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback = new Callback(); 467968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } else { 468968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mCallbackPool = callback.next; 469968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.next = null; 470968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 471968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.runnable = runnable; 472968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown return callback; 473968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 474968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 475968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private void recycleCallbackLocked(Callback callback) { 476968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.runnable = null; 477968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown callback.next = mCallbackPool; 478968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown mCallbackPool = callback; 479968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 480968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 481968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private final class FrameHandler extends Handler { 482968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public FrameHandler(Looper looper) { 483968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown super(looper); 484968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 485968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 486968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown @Override 487968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public void handleMessage(Message msg) { 488968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown switch (msg.what) { 489968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_ANIMATION: 490968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doAnimation(); 491968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 492968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_DRAW: 493968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doDraw(); 494968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 495968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_SCHEDULE_VSYNC: 496968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doScheduleVsync(); 497968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 498968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown case MSG_DO_DISPOSE_RECEIVER: 499968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown doDisposeReceiver(); 500968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown break; 501968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 502968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 503968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 504968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 50596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private final class FrameDisplayEventReceiver extends DisplayEventReceiver { 50696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public FrameDisplayEventReceiver(Looper looper) { 50796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown super(looper); 50896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 50996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 51096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 51196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void onVsync(long timestampNanos, int frame) { 51296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown doAnimation(); 51396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 51496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 515968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown 516968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown private static final class Callback { 517968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public Callback next; 518968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown public Runnable runnable; 519968588573cf516fd8cf33c133d06f06c67ca1785Jeff Brown } 52096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown} 521