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