Choreographer.java revision 58aedbc9bea13415e2d42cf7c9fe8a7efd243e66
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 com.android.internal.util.ArrayUtils;
2096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
2196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Handler;
2296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Looper;
2396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.Message;
2496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.SystemClock;
2596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.os.SystemProperties;
2696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownimport android.util.Log;
2796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
2896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown/**
298bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn * Coordinates animations and drawing for UI on a particular thread.
3087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown *
3187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown * This object is thread-safe.  Other threads can add and remove listeners
3287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown * or schedule work to occur at a later time on the UI thread.
3387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown *
3458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver}
3558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * can only be accessed from the UI thread so operations that touch the event receiver
3658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown * are posted to the UI thread if needed.
3758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown *
3896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @hide
3996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */
4096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownpublic final class Choreographer extends Handler {
4196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final String TAG = "Choreographer";
4296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean DEBUG = false;
4396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
4458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    // Amount of time in ms to wait before actually disposing of the display event
4558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    // receiver after all listeners have been removed.
4658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private static final long DISPOSE_RECEIVER_DELAY = 200;
4758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
4896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // The default amount of time in ms between animation frames.
4996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // When vsync is not enabled, we want to have some idea of how long we should
5096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // wait before posting the next animation message.  It is important that the
5196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // default value be less than the true inter-frame delay on all devices to avoid
5296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // situations where we might skip frames by waiting too long (we must compensate
5396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // for jitter and hardware variations).  Regardless of this value, the animation
5496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // and display loop is ultimately rate-limited by how fast new graphics buffers can
5596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // be dequeued.
5696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final long DEFAULT_FRAME_DELAY = 10;
5796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
5896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // The number of milliseconds between animation frames.
5987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
6096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
6196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // Thread local storage for the choreographer.
6296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final ThreadLocal<Choreographer> sThreadInstance =
6396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            new ThreadLocal<Choreographer>() {
6496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
6596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        protected Choreographer initialValue() {
6696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            Looper looper = Looper.myLooper();
6796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (looper == null) {
6896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                throw new IllegalStateException("The current thread must have a looper!");
6996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            return new Choreographer(looper);
7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
7296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    };
7396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
7496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // System property to enable/disable vsync for animations and drawing.
7596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // Enabled by default.
7696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean USE_VSYNC = SystemProperties.getBoolean(
7796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            "debug.choreographer.vsync", true);
7896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
7996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // System property to enable/disable the use of the vsync / animation timer
8096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    // for drawing rather than drawing immediately.
8190a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown    // Temporarily disabled by default because postponing performTraversals() violates
8290a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown    // assumptions about traversals happening in-order relative to other posted messages.
8390a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown    // Bug: 5721047
8496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final boolean USE_ANIMATION_TIMER_FOR_DRAW = SystemProperties.getBoolean(
8590a3c5f51ddf0f98769a258ed224f2ec5b645d0eJeff Brown            "debug.choreographer.animdraw", false);
8696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
8796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final int MSG_DO_ANIMATION = 0;
8896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private static final int MSG_DO_DRAW = 1;
8958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private static final int MSG_DO_SCHEDULE_VSYNC = 2;
9058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private static final int MSG_DO_DISPOSE_RECEIVER = 3;
9196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
9287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private final Object mLock = new Object();
9387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
9496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private final Looper mLooper;
9596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
9696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private OnAnimateListener[] mOnAnimateListeners;
9796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private OnDrawListener[] mOnDrawListeners;
9896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
9996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private boolean mAnimationScheduled;
10096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private boolean mDrawScheduled;
10158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private boolean mFrameDisplayEventReceiverNeeded;
10296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private FrameDisplayEventReceiver mFrameDisplayEventReceiver;
10396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private long mLastAnimationTime;
10496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private long mLastDrawTime;
10596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
10696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private Choreographer(Looper looper) {
10796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        super(looper);
10896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLooper = looper;
10996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLastAnimationTime = Long.MIN_VALUE;
11096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        mLastDrawTime = Long.MIN_VALUE;
11196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
11296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
11396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
1148bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * Gets the choreographer for the calling thread.  Must be called from
1158bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * a thread that already has a {@link android.os.Looper} associated with it.
11696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
11796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return The choreographer for this thread.
11896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @throws IllegalStateException if the thread does not have a looper.
11996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
12096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static Choreographer getInstance() {
12196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sThreadInstance.get();
12296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
12396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
12496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
12596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The amount of time, in milliseconds, between each frame of the animation. This is a
12696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * requested time that the animation will attempt to honor, but the actual delay between
12796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * frames may be different, depending on system load and capabilities. This is a static
12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
12996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
13096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
13196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
13296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
13396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
13496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @return the requested time between frames, in milliseconds
13596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
13696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static long getFrameDelay() {
13796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        return sFrameDelay;
13896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
13996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
14096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
14196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The amount of time, in milliseconds, between each frame of the animation. This is a
14296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * requested time that the animation will attempt to honor, but the actual delay between
14396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * frames may be different, depending on system load and capabilities. This is a static
14496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * function because the same delay will be applied to all animations, since they are all
14596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * run off of a single timing loop.
14696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
14796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * The frame delay may be ignored when the animation system uses an external timing
14896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * source, such as the display refresh rate (vsync), to govern animations.
14996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
15096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param frameDelay the requested time between frames, in milliseconds
15196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
15296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static void setFrameDelay(long frameDelay) {
15396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        sFrameDelay = frameDelay;
15496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
15596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
15696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
15796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Schedules animation (and drawing) to occur on the next frame synchronization boundary.
15896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
15996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public void scheduleAnimation() {
16087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
16187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            scheduleAnimationLocked();
16287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
16387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    }
16487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
16587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private void scheduleAnimationLocked() {
16696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (!mAnimationScheduled) {
16796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mAnimationScheduled = true;
16896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (USE_VSYNC) {
16996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                if (DEBUG) {
17096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                    Log.d(TAG, "Scheduling vsync for animation.");
17196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                }
17258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
17358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                // If running on the Looper thread, then schedule the vsync immediately,
17458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                // otherwise post a message to schedule the vsync from the UI thread
17558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                // as soon as possible.
17658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                if (!mFrameDisplayEventReceiverNeeded) {
17758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                    mFrameDisplayEventReceiverNeeded = true;
17858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                    if (mFrameDisplayEventReceiver != null) {
17958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                        removeMessages(MSG_DO_DISPOSE_RECEIVER);
18058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                    }
18158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                }
18258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                if (isRunningOnLooperThreadLocked()) {
18358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                    doScheduleVsyncLocked();
18458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                } else {
18558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                    sendMessageAtFrontOfQueue(obtainMessage(MSG_DO_SCHEDULE_VSYNC));
18696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                }
18796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            } else {
18896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                final long now = SystemClock.uptimeMillis();
18996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now);
19096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                if (DEBUG) {
19196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                    Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms.");
19296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                }
19396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime);
19496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
19596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
19696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
19796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
19896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
19987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown     * Returns true if {@link #scheduleAnimation()} has been called but
2008bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has
2018bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * not yet been called.
2028bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     */
2038bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn    public boolean isAnimationScheduled() {
20487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
20587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            return mAnimationScheduled;
20687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
2078bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn    }
2088bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn
2098bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn    /**
21096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Schedules drawing to occur on the next frame synchronization boundary.
21196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Must be called on the UI thread.
21296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
21396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public void scheduleDraw() {
21487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
21587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            if (!mDrawScheduled) {
21687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                mDrawScheduled = true;
21787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                if (USE_ANIMATION_TIMER_FOR_DRAW) {
21887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                    scheduleAnimationLocked();
21987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                } else {
22087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                    if (DEBUG) {
22187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                        Log.d(TAG, "Scheduling draw immediately.");
22287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                    }
22387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                    sendEmptyMessage(MSG_DO_DRAW);
22496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                }
22596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
22696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
22796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
22896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
2298bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn    /**
23087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown     * Returns true if {@link #scheduleDraw()} has been called but
2318bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has
2328bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     * not yet been called.
2338bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn     */
2348bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn    public boolean isDrawScheduled() {
23587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
23687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            return mDrawScheduled;
23787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
2388bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn    }
2398bcd54b98ad5d98d47364ff14e06910deadf9302Dianne Hackborn
24096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    @Override
24196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public void handleMessage(Message msg) {
24296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        switch (msg.what) {
24396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            case MSG_DO_ANIMATION:
24496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                doAnimation();
24596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                break;
24696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            case MSG_DO_DRAW:
24796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                doDraw();
24896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                break;
24958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            case MSG_DO_SCHEDULE_VSYNC:
25058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                doScheduleVsync();
25158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                break;
25258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            case MSG_DO_DISPOSE_RECEIVER:
25358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                doDisposeReceiver();
25458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                break;
25596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
25696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
25796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
25896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private void doAnimation() {
25987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        doAnimationInner();
26087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
26187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (USE_ANIMATION_TIMER_FOR_DRAW) {
26287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            doDraw();
26387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
26487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    }
26587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
26687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private void doAnimationInner() {
26787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        final long start;
26887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        final OnAnimateListener[] listeners;
26987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
27087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            if (!mAnimationScheduled) {
27187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                return; // no work to do
27287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            }
27396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mAnimationScheduled = false;
27496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
27587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            start = SystemClock.uptimeMillis();
27696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (DEBUG) {
27796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime)
27896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                        + " ms have elapsed since previous animation.");
27996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
28096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mLastAnimationTime = start;
28196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
28287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            listeners = mOnAnimateListeners;
28387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
28496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
28587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (listeners != null) {
28687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            for (int i = 0; i < listeners.length; i++) {
28787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                listeners[i].onAnimate();
28896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
28996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
29096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
29187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (DEBUG) {
29287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms.");
29396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
29496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
29596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
29696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private void doDraw() {
29787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        final long start;
29887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        final OnDrawListener[] listeners;
29987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
30087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            if (!mDrawScheduled) {
30187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                return; // no work to do
30287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            }
30396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mDrawScheduled = false;
30496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
30587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            start = SystemClock.uptimeMillis();
30696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (DEBUG) {
30796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                Log.d(TAG, "Performing draw: " + Math.max(0, start - mLastDrawTime)
30896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                        + " ms have elapsed since previous draw.");
30996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
31096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            mLastDrawTime = start;
31196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
31287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            listeners = mOnDrawListeners;
31387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
31496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
31587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (listeners != null) {
31687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            for (int i = 0; i < listeners.length; i++) {
31787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                listeners[i].onDraw();
31896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
31996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
32087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown
32187d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        if (DEBUG) {
32287d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms.");
32387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
32496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
32596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
32658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private void doScheduleVsync() {
32758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        synchronized (mLock) {
32858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            doScheduleVsyncLocked();
32958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        }
33058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
33158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
33258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private void doScheduleVsyncLocked() {
33358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        if (mFrameDisplayEventReceiverNeeded && mAnimationScheduled) {
33458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            if (mFrameDisplayEventReceiver == null) {
33558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper);
33658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            }
33758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            mFrameDisplayEventReceiver.scheduleVsync();
33858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        }
33958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
34058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
34158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private void doDisposeReceiver() {
34258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        synchronized (mLock) {
34358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            if (!mFrameDisplayEventReceiverNeeded && mFrameDisplayEventReceiver != null) {
34458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                mFrameDisplayEventReceiver.dispose();
34558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                mFrameDisplayEventReceiver = null;
34658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            }
34758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        }
34858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
34958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
35096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
35196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Adds an animation listener.
35296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
35396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param listener The listener to add.
35496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
35596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public void addOnAnimateListener(OnAnimateListener listener) {
35696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (listener == null) {
35796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            throw new IllegalArgumentException("listener must not be null");
35896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
35996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
36096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (DEBUG) {
36196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            Log.d(TAG, "Adding onAnimate listener: " + listener);
36296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
36396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
36487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
36587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class,
36687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                    mOnAnimateListeners, listener);
36787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
36896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
36996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
37096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
37196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Removes an animation listener.
37296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
37396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param listener The listener to remove.
37496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
37596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public void removeOnAnimateListener(OnAnimateListener listener) {
37696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (listener == null) {
37796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            throw new IllegalArgumentException("listener must not be null");
37896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
37996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
38096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (DEBUG) {
38196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            Log.d(TAG, "Removing onAnimate listener: " + listener);
38296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
38396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
38487d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
38587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class,
38687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                    mOnAnimateListeners, listener);
38787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            stopTimingLoopIfNoListenersLocked();
38887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
38996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
39096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
39196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
39296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Adds a draw listener.
39396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
39496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param listener The listener to add.
39596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
39696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public void addOnDrawListener(OnDrawListener listener) {
39796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (listener == null) {
39896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            throw new IllegalArgumentException("listener must not be null");
39996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
40096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
40196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (DEBUG) {
40296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            Log.d(TAG, "Adding onDraw listener: " + listener);
40396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
40496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
40587d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
40687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class,
40787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                    mOnDrawListeners, listener);
40887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
40996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
41096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
41196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
41296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Removes a draw listener.
41396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Must be called on the UI thread.
41496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     *
41596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * @param listener The listener to remove.
41696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
41796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public void removeOnDrawListener(OnDrawListener listener) {
41896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (listener == null) {
41996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            throw new IllegalArgumentException("listener must not be null");
42096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
42196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
42296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (DEBUG) {
42396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            Log.d(TAG, "Removing onDraw listener: " + listener);
42496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
42596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
42687d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        synchronized (mLock) {
42787d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class,
42887d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown                    mOnDrawListeners, listener);
42987d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown            stopTimingLoopIfNoListenersLocked();
43087d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown        }
43196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
43296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
43387d0b03f1f16590ff261ae30441e838ae5446e84Jeff Brown    private void stopTimingLoopIfNoListenersLocked() {
43496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        if (mOnDrawListeners == null && mOnAnimateListeners == null) {
43596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (DEBUG) {
43696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                Log.d(TAG, "Stopping timing loop.");
43796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
43896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
43996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (mAnimationScheduled) {
44096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                mAnimationScheduled = false;
44158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                if (USE_VSYNC) {
44258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                    removeMessages(MSG_DO_SCHEDULE_VSYNC);
44358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                } else {
44496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                    removeMessages(MSG_DO_ANIMATION);
44596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                }
44696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
44796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
44896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            if (mDrawScheduled) {
44996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                mDrawScheduled = false;
45096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                if (!USE_ANIMATION_TIMER_FOR_DRAW) {
45196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                    removeMessages(MSG_DO_DRAW);
45296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown                }
45396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
45496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
45558aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            // Post a message to dispose the display event receiver if we haven't needed
45658aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            // it again after a certain amount of time has elapsed.  Another reason to
45758aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            // defer disposal is that it is possible for use to attempt to dispose the
45858aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            // receiver while handling a vsync event that it dispatched, which might
45958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            // cause a few problems...
46058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown            if (mFrameDisplayEventReceiverNeeded) {
46158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                mFrameDisplayEventReceiverNeeded = false;
46258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                if (mFrameDisplayEventReceiver != null) {
46358aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                    sendEmptyMessageDelayed(MSG_DO_DISPOSE_RECEIVER, DISPOSE_RECEIVER_DELAY);
46458aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown                }
46596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            }
46696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
46796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
46896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
46958aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    private boolean isRunningOnLooperThreadLocked() {
47058aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown        return Looper.myLooper() == mLooper;
47158aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown    }
47258aedbc9bea13415e2d42cf7c9fe8a7efd243e66Jeff Brown
47396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
47496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Listens for animation frame timing events.
47596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
47696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static interface OnAnimateListener {
47796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        /**
47896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown         * Called to animate properties before drawing the frame.
47996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown         */
48096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public void onAnimate();
48196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
48296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
48396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    /**
48496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     * Listens for draw frame timing events.
48596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown     */
48696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    public static interface OnDrawListener {
48796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        /**
48896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown         * Called to draw the frame.
48996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown         */
49096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public void onDraw();
49196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
49296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
49396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    private final class FrameDisplayEventReceiver extends DisplayEventReceiver {
49496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public FrameDisplayEventReceiver(Looper looper) {
49596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            super(looper);
49696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
49796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown
49896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        @Override
49996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        public void onVsync(long timestampNanos, int frame) {
50096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown            doAnimation();
50196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown        }
50296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown    }
50396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown}
504