AnimationHandler.java revision f6b8b05a9aa1c417d31dd119a0a8d1e68b79903b
1d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu/* 2d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Copyright (C) 2017 The Android Open Source Project 3d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 4d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Licensed under the Apache License, Version 2.0 (the "License"); 5d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * you may not use this file except in compliance with the License. 6d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * You may obtain a copy of the License at 7d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 8d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * http://www.apache.org/licenses/LICENSE-2.0 9d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 10d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Unless required by applicable law or agreed to in writing, software 11d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * distributed under the License is distributed on an "AS IS" BASIS, 12d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * See the License for the specific language governing permissions and 14d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * limitations under the License. 15d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 16d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.dynamicanimation.animation; 18d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 19d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liuimport android.os.Build; 20d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liuimport android.os.Handler; 21d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liuimport android.os.Looper; 22d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liuimport android.os.SystemClock; 23f6b8b05a9aa1c417d31dd119a0a8d1e68b79903bAurimas Liutikasimport android.view.Choreographer; 24f6b8b05a9aa1c417d31dd119a0a8d1e68b79903bAurimas Liutikas 25ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RequiresApi; 26ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.collection.SimpleArrayMap; 27d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 28d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liuimport java.util.ArrayList; 29d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 30d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu/** 31d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * This custom, static handler handles the timing pulse that is shared by all active 32d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * ValueAnimators. This approach ensures that the setting of animation values will happen on the 33d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * same thread that animations start on, and that all animations will share the same times for 34d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * calculating their values, which makes synchronizing animations possible. 35d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 36d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * The handler uses the Choreographer by default for doing periodic callbacks. A custom 37d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * AnimationFrameCallbackProvider can be set on the handler to provide timing pulse that 38d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * may be independent of UI frame update. This could be useful in testing. 39d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 40d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liuclass AnimationHandler { 41d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 42d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Callbacks that receives notifications for animation timing 43d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 44d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu interface AnimationFrameCallback { 45d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 46d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Run animation based on the frame time. 47d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @param frameTime The frame start time 48d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 49d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu boolean doAnimationFrame(long frameTime); 50d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 51d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 52d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 53d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu * This class is responsible for interacting with the available frame provider by either 54d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu * registering frame callback or posting runnable, and receiving a callback for when a 55d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu * new frame has arrived. This dispatcher class then notifies all the on-going animations of 56d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu * the new frame, so that they can update animation values as needed. 57d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu */ 58d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu class AnimationCallbackDispatcher { 5904c9e28ea0be0cedcee58e4d29343ac08733d58aAurimas Liutikas void dispatchAnimationFrame() { 60d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mCurrentFrameTime = SystemClock.uptimeMillis(); 61d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu AnimationHandler.this.doAnimationFrame(mCurrentFrameTime); 62d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu if (mAnimationCallbacks.size() > 0) { 63d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu getProvider().postFrameCallback(); 64d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 65d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 66d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 67d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu 68d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private static final long FRAME_DELAY_MS = 10; 69d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu public static final ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>(); 70d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu 71d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu /** 72d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Internal per-thread collections used to avoid set collisions as animations start and end 73d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * while being processed. 74d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 75d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private final SimpleArrayMap<AnimationFrameCallback, Long> mDelayedCallbackStartTime = 76d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu new SimpleArrayMap<>(); 77d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private final ArrayList<AnimationFrameCallback> mAnimationCallbacks = new ArrayList<>(); 78d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private final AnimationCallbackDispatcher mCallbackDispatcher = 79d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu new AnimationCallbackDispatcher(); 80d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 81d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private AnimationFrameCallbackProvider mProvider; 82d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private long mCurrentFrameTime = 0; 83d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private boolean mListDirty = false; 84d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 85d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static AnimationHandler getInstance() { 86d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (sAnimatorHandler.get() == null) { 87d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu sAnimatorHandler.set(new AnimationHandler()); 88d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 89d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return sAnimatorHandler.get(); 90d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 91d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 92d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public static long getFrameTime() { 93d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (sAnimatorHandler.get() == null) { 94d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return 0; 95d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 96d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return sAnimatorHandler.get().mCurrentFrameTime; 97d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 98d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 99d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 100d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * By default, the Choreographer is used to provide timing for frame callbacks. A custom 101d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * provider can be used here to provide different timing pulse. 102d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 103d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public void setProvider(AnimationFrameCallbackProvider provider) { 104d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mProvider = provider; 105d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 106d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 107d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private AnimationFrameCallbackProvider getProvider() { 108d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (mProvider == null) { 109d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 110d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mProvider = new FrameCallbackProvider16(mCallbackDispatcher); 111d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } else { 112d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mProvider = new FrameCallbackProvider14(mCallbackDispatcher); 113d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 114d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 115d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return mProvider; 116d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 117d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 118d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 119d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Register to get a callback on the next frame after the delay. 120d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 121d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) { 122d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (mAnimationCallbacks.size() == 0) { 123d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu getProvider().postFrameCallback(); 124d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 125d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (!mAnimationCallbacks.contains(callback)) { 126d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mAnimationCallbacks.add(callback); 127d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 128d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 129d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (delay > 0) { 130d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay)); 131d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 132d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 133d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 134d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Removes the given callback from the list, so it will no longer be called for frame related 135d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * timing. 136d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 137d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu public void removeCallback(AnimationFrameCallback callback) { 138d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mDelayedCallbackStartTime.remove(callback); 139d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu int id = mAnimationCallbacks.indexOf(callback); 140d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (id >= 0) { 141d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mAnimationCallbacks.set(id, null); 142d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mListDirty = true; 143d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 144d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 145d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 146d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private void doAnimationFrame(long frameTime) { 147d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu long currentTime = SystemClock.uptimeMillis(); 148d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu for (int i = 0; i < mAnimationCallbacks.size(); i++) { 149d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu final AnimationFrameCallback callback = mAnimationCallbacks.get(i); 150d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (callback == null) { 151d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu continue; 152d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 153d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (isCallbackDue(callback, currentTime)) { 154d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu callback.doAnimationFrame(frameTime); 155d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 156d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 157d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu cleanUpList(); 158d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 159d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 160d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 161d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Remove the callbacks from mDelayedCallbackStartTime once they have passed the initial delay 162d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * so that they can start getting frame callbacks. 163d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * 164d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * @return true if they have passed the initial delay or have no delay, false otherwise. 165d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 166d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private boolean isCallbackDue(AnimationFrameCallback callback, long currentTime) { 167d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu Long startTime = mDelayedCallbackStartTime.get(callback); 168d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (startTime == null) { 169d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return true; 170d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 171d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (startTime < currentTime) { 172d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mDelayedCallbackStartTime.remove(callback); 173d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return true; 174d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 175d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu return false; 176d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 177d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 178d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu private void cleanUpList() { 179d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (mListDirty) { 180d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) { 181d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu if (mAnimationCallbacks.get(i) == null) { 182d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mAnimationCallbacks.remove(i); 183d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 184d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 185d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu mListDirty = false; 186d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 187d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 188d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 189d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 190d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Default provider of timing pulse that uses Choreographer for frame callbacks. 191d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 192d8a34479f81c58db620b26ab31ee2ca5e811059dAurimas Liutikas @RequiresApi(Build.VERSION_CODES.JELLY_BEAN) 193d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private static class FrameCallbackProvider16 extends AnimationFrameCallbackProvider { 194d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu 195d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private final Choreographer mChoreographer = Choreographer.getInstance(); 196d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private final Choreographer.FrameCallback mChoreographerCallback; 197d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu 198d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu FrameCallbackProvider16(AnimationCallbackDispatcher dispatcher) { 199d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu super(dispatcher); 200d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mChoreographerCallback = new Choreographer.FrameCallback() { 201d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu @Override 202d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu public void doFrame(long frameTimeNanos) { 203d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mDispatcher.dispatchAnimationFrame(); 204d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 205d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu }; 206d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 207d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu 208d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu @Override 209d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu void postFrameCallback() { 210d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mChoreographer.postFrameCallback(mChoreographerCallback); 211d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 212d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 213d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu 214d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu /** 215d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu * Frame provider for ICS and ICS-MR1 releases. The frame callback is achieved via posting 216d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu * a Runnable to the main thread Handler with a delay. 217d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu */ 218d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private static class FrameCallbackProvider14 extends AnimationFrameCallbackProvider { 219d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu 220d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private final Runnable mRunnable; 221d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private final Handler mHandler; 222d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu private long mLastFrameTime = -1; 223d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 224d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu FrameCallbackProvider14(AnimationCallbackDispatcher dispatcher) { 225d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu super(dispatcher); 226d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mRunnable = new Runnable() { 227d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu @Override 228d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu public void run() { 229d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mLastFrameTime = SystemClock.uptimeMillis(); 230d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mDispatcher.dispatchAnimationFrame(); 231d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 232d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu }; 233d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mHandler = new Handler(Looper.myLooper()); 234d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 235d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 236d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu @Override 237d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu void postFrameCallback() { 238d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu long delay = FRAME_DELAY_MS - (SystemClock.uptimeMillis() - mLastFrameTime); 239d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu delay = Math.max(delay, 0); 240d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mHandler.postDelayed(mRunnable, delay); 241d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 242d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 243d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu 244d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu /** 245d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * The intention for having this interface is to increase the testability of ValueAnimator. 246d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * Specifically, we can have a custom implementation of the interface below and provide 247d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * timing pulse without using Choreographer. That way we could use any arbitrary interval for 248d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu * our timing pulse in the tests. 249d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu */ 25004c9e28ea0be0cedcee58e4d29343ac08733d58aAurimas Liutikas abstract static class AnimationFrameCallbackProvider { 251d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu final AnimationCallbackDispatcher mDispatcher; 252d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu AnimationFrameCallbackProvider(AnimationCallbackDispatcher dispatcher) { 253d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu mDispatcher = dispatcher; 254d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu } 255d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu 256d216d895647877d4ab7bd616a3347862b5e47f4aDoris Liu abstract void postFrameCallback(); 257d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu } 258d5206a7781d95cba12ca70a20f7ee742a2e9d807Doris Liu} 259