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