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