Choreographer.java revision 96e942dabeeaaa9ab6df3a870668c6fe53d930da
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/** 2996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Coodinates animations and drawing for UI on a particular thread. 3096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @hide 3196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 3296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brownpublic final class Choreographer extends Handler { 3396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final String TAG = "Choreographer"; 3496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean DEBUG = false; 3596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 3696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // The default amount of time in ms between animation frames. 3796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // When vsync is not enabled, we want to have some idea of how long we should 3896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // wait before posting the next animation message. It is important that the 3996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // default value be less than the true inter-frame delay on all devices to avoid 4096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // situations where we might skip frames by waiting too long (we must compensate 4196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // for jitter and hardware variations). Regardless of this value, the animation 4296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // and display loop is ultimately rate-limited by how fast new graphics buffers can 4396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // be dequeued. 4496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final long DEFAULT_FRAME_DELAY = 10; 4596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 4696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // The number of milliseconds between animation frames. 4796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static long sFrameDelay = DEFAULT_FRAME_DELAY; 4896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 4996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // Thread local storage for the choreographer. 5096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final ThreadLocal<Choreographer> sThreadInstance = 5196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown new ThreadLocal<Choreographer>() { 5296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 5396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown protected Choreographer initialValue() { 5496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Looper looper = Looper.myLooper(); 5596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (looper == null) { 5696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown throw new IllegalStateException("The current thread must have a looper!"); 5796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 5896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return new Choreographer(looper); 5996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 6096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown }; 6196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 6296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // System property to enable/disable vsync for animations and drawing. 6396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // Enabled by default. 6496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean USE_VSYNC = SystemProperties.getBoolean( 6596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown "debug.choreographer.vsync", true); 6696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 6796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // System property to enable/disable the use of the vsync / animation timer 6896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // for drawing rather than drawing immediately. 6996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown // Enabled by default. 7096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final boolean USE_ANIMATION_TIMER_FOR_DRAW = SystemProperties.getBoolean( 7196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown "debug.choreographer.animdraw", true); 7296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 7396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final int MSG_DO_ANIMATION = 0; 7496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private static final int MSG_DO_DRAW = 1; 7596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 7696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private final Looper mLooper; 7796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 7896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private OnAnimateListener[] mOnAnimateListeners; 7996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private OnDrawListener[] mOnDrawListeners; 8096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 8196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private boolean mAnimationScheduled; 8296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private boolean mDrawScheduled; 8396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private FrameDisplayEventReceiver mFrameDisplayEventReceiver; 8496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private long mLastAnimationTime; 8596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private long mLastDrawTime; 8696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 8796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private Choreographer(Looper looper) { 8896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown super(looper); 8996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLooper = looper; 9096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastAnimationTime = Long.MIN_VALUE; 9196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastDrawTime = Long.MIN_VALUE; 9296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 9396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 9496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 9596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Gets the choreographer for this thread. 9696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Must be called on the UI thread. 9796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 9896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return The choreographer for this thread. 9996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @throws IllegalStateException if the thread does not have a looper. 10096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 10196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static Choreographer getInstance() { 10296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sThreadInstance.get(); 10396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 10496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 10596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 10696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The amount of time, in milliseconds, between each frame of the animation. This is a 10796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * requested time that the animation will attempt to honor, but the actual delay between 10896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * frames may be different, depending on system load and capabilities. This is a static 10996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 11096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 11196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 11296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 11396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 11496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 11596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @return the requested time between frames, in milliseconds 11696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 11796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static long getFrameDelay() { 11896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown return sFrameDelay; 11996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 12096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 12196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 12296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The amount of time, in milliseconds, between each frame of the animation. This is a 12396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * requested time that the animation will attempt to honor, but the actual delay between 12496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * frames may be different, depending on system load and capabilities. This is a static 12596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * function because the same delay will be applied to all animations, since they are all 12696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * run off of a single timing loop. 12796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 12896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * The frame delay may be ignored when the animation system uses an external timing 12996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * source, such as the display refresh rate (vsync), to govern animations. 13096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 13196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param frameDelay the requested time between frames, in milliseconds 13296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 13396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static void setFrameDelay(long frameDelay) { 13496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown sFrameDelay = frameDelay; 13596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 13696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 13796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 13896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Schedules animation (and drawing) to occur on the next frame synchronization boundary. 13996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Must be called on the UI thread. 14096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 14196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void scheduleAnimation() { 14296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (!mAnimationScheduled) { 14396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mAnimationScheduled = true; 14496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (USE_VSYNC) { 14596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 14696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Scheduling vsync for animation."); 14796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 14896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mFrameDisplayEventReceiver == null) { 14996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper); 15096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 15196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mFrameDisplayEventReceiver.scheduleVsync(); 15296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } else { 15396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown final long now = SystemClock.uptimeMillis(); 15496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now); 15596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 15696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); 15796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 15896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime); 15996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 16096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 16196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 16296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 16396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 16496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Schedules drawing to occur on the next frame synchronization boundary. 16596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Must be called on the UI thread. 16696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 16796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void scheduleDraw() { 16896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (!mDrawScheduled) { 16996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mDrawScheduled = true; 17096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (USE_ANIMATION_TIMER_FOR_DRAW) { 17196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown scheduleAnimation(); 17296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } else { 17396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 17496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Scheduling draw immediately."); 17596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 17696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown sendEmptyMessage(MSG_DO_DRAW); 17796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 17896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 17996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 18096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 18196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 18296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void handleMessage(Message msg) { 18396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown switch (msg.what) { 18496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown case MSG_DO_ANIMATION: 18596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown doAnimation(); 18696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown break; 18796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown case MSG_DO_DRAW: 18896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown doDraw(); 18996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown break; 19096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 19196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 19296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 19396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private void doAnimation() { 19496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mAnimationScheduled) { 19596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mAnimationScheduled = false; 19696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 19796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown final long start = SystemClock.uptimeMillis(); 19896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 19996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime) 20096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown + " ms have elapsed since previous animation."); 20196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 20296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastAnimationTime = start; 20396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 20496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown final OnAnimateListener[] listeners = mOnAnimateListeners; 20596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (listeners != null) { 20696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown for (int i = 0; i < listeners.length; i++) { 20796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown listeners[i].onAnimate(); 20896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 20996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 21096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 21196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 21296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms."); 21396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 21496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 21596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 21696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (USE_ANIMATION_TIMER_FOR_DRAW) { 21796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown doDraw(); 21896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 21996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 22096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 22196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private void doDraw() { 22296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mDrawScheduled) { 22396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mDrawScheduled = false; 22496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 22596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown final long start = SystemClock.uptimeMillis(); 22696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 22796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Performing draw: " + Math.max(0, start - mLastDrawTime) 22896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown + " ms have elapsed since previous draw."); 22996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 23096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mLastDrawTime = start; 23196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 23296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown final OnDrawListener[] listeners = mOnDrawListeners; 23396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (listeners != null) { 23496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown for (int i = 0; i < listeners.length; i++) { 23596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown listeners[i].onDraw(); 23696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 23796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 23896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 23996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 24096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms."); 24196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 24296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 24396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 24496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 24596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 24696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Adds an animation listener. 24796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Must be called on the UI thread. 24896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 24996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param listener The listener to add. 25096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 25196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void addOnAnimateListener(OnAnimateListener listener) { 25296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (listener == null) { 25396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown throw new IllegalArgumentException("listener must not be null"); 25496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 25596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 25696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 25796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Adding onAnimate listener: " + listener); 25896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 25996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 26096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class, 26196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mOnAnimateListeners, listener); 26296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 26396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 26496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 26596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Removes an animation listener. 26696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Must be called on the UI thread. 26796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 26896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param listener The listener to remove. 26996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 27096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void removeOnAnimateListener(OnAnimateListener listener) { 27196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (listener == null) { 27296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown throw new IllegalArgumentException("listener must not be null"); 27396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 27496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 27596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 27696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Removing onAnimate listener: " + listener); 27796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 27896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 27996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class, 28096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mOnAnimateListeners, listener); 28196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown stopTimingLoopIfNoListeners(); 28296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 28396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 28496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 28596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Adds a draw listener. 28696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Must be called on the UI thread. 28796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 28896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param listener The listener to add. 28996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 29096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void addOnDrawListener(OnDrawListener listener) { 29196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (listener == null) { 29296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown throw new IllegalArgumentException("listener must not be null"); 29396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 29496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 29596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 29696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Adding onDraw listener: " + listener); 29796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 29896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 29996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class, 30096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mOnDrawListeners, listener); 30196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 30296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 30396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 30496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Removes a draw listener. 30596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Must be called on the UI thread. 30696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * 30796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * @param listener The listener to remove. 30896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 30996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void removeOnDrawListener(OnDrawListener listener) { 31096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (listener == null) { 31196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown throw new IllegalArgumentException("listener must not be null"); 31296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 31396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 31496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 31596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Removing onDraw listener: " + listener); 31696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 31796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 31896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class, 31996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mOnDrawListeners, listener); 32096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown stopTimingLoopIfNoListeners(); 32196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 32296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 32396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private void stopTimingLoopIfNoListeners() { 32496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mOnDrawListeners == null && mOnAnimateListeners == null) { 32596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (DEBUG) { 32696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown Log.d(TAG, "Stopping timing loop."); 32796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 32896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 32996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mAnimationScheduled) { 33096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mAnimationScheduled = false; 33196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (!USE_VSYNC) { 33296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown removeMessages(MSG_DO_ANIMATION); 33396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 33496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 33596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 33696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mDrawScheduled) { 33796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mDrawScheduled = false; 33896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (!USE_ANIMATION_TIMER_FOR_DRAW) { 33996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown removeMessages(MSG_DO_DRAW); 34096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 34196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 34296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 34396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown if (mFrameDisplayEventReceiver != null) { 34496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mFrameDisplayEventReceiver.dispose(); 34596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown mFrameDisplayEventReceiver = null; 34696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 34796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 34896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 34996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 35096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 35196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Listens for animation frame timing events. 35296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 35396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static interface OnAnimateListener { 35496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 35596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Called to animate properties before drawing the frame. 35696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 35796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void onAnimate(); 35896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 35996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 36096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 36196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Listens for draw frame timing events. 36296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 36396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public static interface OnDrawListener { 36496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown /** 36596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown * Called to draw the frame. 36696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown */ 36796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void onDraw(); 36896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 36996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 37096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown private final class FrameDisplayEventReceiver extends DisplayEventReceiver { 37196e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public FrameDisplayEventReceiver(Looper looper) { 37296e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown super(looper); 37396e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 37496e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown 37596e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown @Override 37696e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown public void onVsync(long timestampNanos, int frame) { 37796e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown doAnimation(); 37896e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 37996e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown } 38096e942dabeeaaa9ab6df3a870668c6fe53d930daJeff Brown} 381