13618d30f8ab6018025b11869676b309c3b4961cfDoris Liu/*
23618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * Copyright (C) 2015 The Android Open Source Project
33618d30f8ab6018025b11869676b309c3b4961cfDoris Liu *
43618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * Licensed under the Apache License, Version 2.0 (the "License");
53618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * you may not use this file except in compliance with the License.
63618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * You may obtain a copy of the License at
73618d30f8ab6018025b11869676b309c3b4961cfDoris Liu *
83618d30f8ab6018025b11869676b309c3b4961cfDoris Liu *      http://www.apache.org/licenses/LICENSE-2.0
93618d30f8ab6018025b11869676b309c3b4961cfDoris Liu *
103618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * Unless required by applicable law or agreed to in writing, software
113618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * distributed under the License is distributed on an "AS IS" BASIS,
123618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * See the License for the specific language governing permissions and
143618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * limitations under the License.
153618d30f8ab6018025b11869676b309c3b4961cfDoris Liu */
163618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
173618d30f8ab6018025b11869676b309c3b4961cfDoris Liupackage android.animation;
183618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
193618d30f8ab6018025b11869676b309c3b4961cfDoris Liuimport android.os.SystemClock;
203618d30f8ab6018025b11869676b309c3b4961cfDoris Liuimport android.util.ArrayMap;
213618d30f8ab6018025b11869676b309c3b4961cfDoris Liuimport android.view.Choreographer;
223618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
233618d30f8ab6018025b11869676b309c3b4961cfDoris Liuimport java.util.ArrayList;
243618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
253618d30f8ab6018025b11869676b309c3b4961cfDoris Liu/**
263618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * This custom, static handler handles the timing pulse that is shared by all active
273618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * ValueAnimators. This approach ensures that the setting of animation values will happen on the
283618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * same thread that animations start on, and that all animations will share the same times for
293618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * calculating their values, which makes synchronizing animations possible.
303618d30f8ab6018025b11869676b309c3b4961cfDoris Liu *
313618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * The handler uses the Choreographer by default for doing periodic callbacks. A custom
32f310e889392be5198004c6c6611b2b50ae3344b8Doris Liu * AnimationFrameCallbackProvider can be set on the handler to provide timing pulse that
333618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * may be independent of UI frame update. This could be useful in testing.
343618d30f8ab6018025b11869676b309c3b4961cfDoris Liu *
353618d30f8ab6018025b11869676b309c3b4961cfDoris Liu * @hide
363618d30f8ab6018025b11869676b309c3b4961cfDoris Liu */
373618d30f8ab6018025b11869676b309c3b4961cfDoris Liupublic class AnimationHandler {
383618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
393618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Internal per-thread collections used to avoid set collisions as animations start and end
403618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * while being processed.
413618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * @hide
423618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
433618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private final ArrayMap<AnimationFrameCallback, Long> mDelayedCallbackStartTime =
443618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            new ArrayMap<>();
453618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private final ArrayList<AnimationFrameCallback> mAnimationCallbacks =
463618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            new ArrayList<>();
473618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private final ArrayList<AnimationFrameCallback> mCommitCallbacks =
483618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            new ArrayList<>();
493618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private AnimationFrameCallbackProvider mProvider;
503618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
513618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
523618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        @Override
533618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        public void doFrame(long frameTimeNanos) {
543618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            doAnimationFrame(getProvider().getFrameTime());
553618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            if (mAnimationCallbacks.size() > 0) {
563618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                getProvider().postFrameCallback(this);
573618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            }
583618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
593618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    };
603618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
613618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
623618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private boolean mListDirty = false;
633618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
643618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public static AnimationHandler getInstance() {
653618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (sAnimatorHandler.get() == null) {
663618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            sAnimatorHandler.set(new AnimationHandler());
673618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
683618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        return sAnimatorHandler.get();
693618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
703618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
713618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
723618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * By default, the Choreographer is used to provide timing for frame callbacks. A custom
733618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * provider can be used here to provide different timing pulse.
743618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
753618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public void setProvider(AnimationFrameCallbackProvider provider) {
763618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (provider == null) {
773618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mProvider = new MyFrameCallbackProvider();
783618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        } else {
793618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mProvider = provider;
803618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
813618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
823618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
833618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private AnimationFrameCallbackProvider getProvider() {
843618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (mProvider == null) {
853618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mProvider = new MyFrameCallbackProvider();
863618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
873618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        return mProvider;
883618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
893618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
903618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
913618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Register to get a callback on the next frame after the delay.
923618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
933618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
943618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (mAnimationCallbacks.size() == 0) {
953618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            getProvider().postFrameCallback(mFrameCallback);
963618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
973618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (!mAnimationCallbacks.contains(callback)) {
983618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mAnimationCallbacks.add(callback);
993618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1003618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
1013618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (delay > 0) {
1023618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
1033618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1043618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
1053618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
1063618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
1073618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Register to get a one shot callback for frame commit timing. Frame commit timing is the
1083618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * time *after* traversals are done, as opposed to the animation frame timing, which is
1093618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * before any traversals. This timing can be used to adjust the start time of an animation
1103618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * when expensive traversals create big delta between the animation frame timing and the time
1113618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * that animation is first shown on screen.
1123618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     *
1133618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Note this should only be called when the animation has already registered to receive
1143618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * animation frame callbacks. This callback will be guaranteed to happen *after* the next
1153618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * animation frame callback.
1163618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
1173618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public void addOneShotCommitCallback(final AnimationFrameCallback callback) {
1183618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (!mCommitCallbacks.contains(callback)) {
1193618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mCommitCallbacks.add(callback);
1203618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1213618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
1223618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
1233618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
1243618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Removes the given callback from the list, so it will no longer be called for frame related
1253618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * timing.
1263618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
1273618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public void removeCallback(AnimationFrameCallback callback) {
1283618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        mCommitCallbacks.remove(callback);
1293618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        mDelayedCallbackStartTime.remove(callback);
1303618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        int id = mAnimationCallbacks.indexOf(callback);
1313618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (id >= 0) {
1323618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mAnimationCallbacks.set(id, null);
1333618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mListDirty = true;
1343618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1353618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
1363618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
1373618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private void doAnimationFrame(long frameTime) {
1383618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        long currentTime = SystemClock.uptimeMillis();
139da9374211f84b899e8c09c0600ec3fe6ed35b22fChet Haase        final int size = mAnimationCallbacks.size();
140da9374211f84b899e8c09c0600ec3fe6ed35b22fChet Haase        for (int i = 0; i < size; i++) {
1413618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
1423618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            if (callback == null) {
1433618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                continue;
1443618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            }
1453618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            if (isCallbackDue(callback, currentTime)) {
1463618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                callback.doAnimationFrame(frameTime);
1473618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                if (mCommitCallbacks.contains(callback)) {
1483618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                    getProvider().postCommitCallback(new Runnable() {
1493618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                        @Override
1503618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                        public void run() {
1513618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                            commitAnimationFrame(callback, getProvider().getFrameTime());
1523618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                        }
1533618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                    });
1543618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                }
1553618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            }
1563618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1573618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        cleanUpList();
1583618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
1593618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
1603618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private void commitAnimationFrame(AnimationFrameCallback callback, long frameTime) {
1613618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (!mDelayedCallbackStartTime.containsKey(callback) &&
1623618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                mCommitCallbacks.contains(callback)) {
1633618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            callback.commitAnimationFrame(frameTime);
1643618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mCommitCallbacks.remove(callback);
1653618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1663618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
1673618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
1683618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
1693618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Remove the callbacks from mDelayedCallbackStartTime once they have passed the initial delay
1703618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * so that they can start getting frame callbacks.
1713618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     *
1723618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * @return true if they have passed the initial delay or have no delay, false otherwise.
1733618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
1743618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private boolean isCallbackDue(AnimationFrameCallback callback, long currentTime) {
1753618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        Long startTime = mDelayedCallbackStartTime.get(callback);
1763618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (startTime == null) {
1773618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            return true;
1783618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1793618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (startTime < currentTime) {
1803618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mDelayedCallbackStartTime.remove(callback);
1813618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            return true;
1823618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1833618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        return false;
1843618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
1853618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
1863618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
1873618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Return the number of callbacks that have registered for frame callbacks.
1883618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
1893618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public static int getAnimationCount() {
1903618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        AnimationHandler handler = sAnimatorHandler.get();
1913618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (handler == null) {
1923618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            return 0;
1933618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
1943618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        return handler.getCallbackSize();
1953618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
1963618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
1973618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public static void setFrameDelay(long delay) {
1983618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        getInstance().getProvider().setFrameDelay(delay);
1993618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
2003618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2013618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public static long getFrameDelay() {
2023618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        return getInstance().getProvider().getFrameDelay();
2033618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
2043618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2053618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    void autoCancelBasedOn(ObjectAnimator objectAnimator) {
2063618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
2073618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            AnimationFrameCallback cb = mAnimationCallbacks.get(i);
2083618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            if (cb == null) {
2093618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                continue;
2103618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            }
2113618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            if (objectAnimator.shouldAutoCancel(cb)) {
2123618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                ((Animator) mAnimationCallbacks.get(i)).cancel();
2133618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            }
2143618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
2153618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
2163618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2173618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private void cleanUpList() {
2183618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        if (mListDirty) {
2193618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
2203618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                if (mAnimationCallbacks.get(i) == null) {
2213618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                    mAnimationCallbacks.remove(i);
2223618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                }
2233618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            }
2243618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mListDirty = false;
2253618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
2263618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
2273618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2283618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private int getCallbackSize() {
2293618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        int count = 0;
2303618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        int size = mAnimationCallbacks.size();
2313618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        for (int i = size - 1; i >= 0; i--) {
2323618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            if (mAnimationCallbacks.get(i) != null) {
2333618d30f8ab6018025b11869676b309c3b4961cfDoris Liu                count++;
2343618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            }
2353618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
2363618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        return count;
2373618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
2383618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2393618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
2403618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Default provider of timing pulse that uses Choreographer for frame callbacks.
2413618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
2423618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {
2433618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2443618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        final Choreographer mChoreographer = Choreographer.getInstance();
2453618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2463618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        @Override
2473618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        public void postFrameCallback(Choreographer.FrameCallback callback) {
2483618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mChoreographer.postFrameCallback(callback);
2493618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
2503618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2513618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        @Override
2523618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        public void postCommitCallback(Runnable runnable) {
2533618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
2543618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
2553618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2563618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        @Override
2573618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        public long getFrameTime() {
2583618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            return mChoreographer.getFrameTime();
2593618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
2603618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2613618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        @Override
2623618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        public long getFrameDelay() {
2633618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            return Choreographer.getFrameDelay();
2643618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
2653618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2663618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        @Override
2673618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        public void setFrameDelay(long delay) {
2683618d30f8ab6018025b11869676b309c3b4961cfDoris Liu            Choreographer.setFrameDelay(delay);
2693618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        }
2703618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
2713618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2723618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
2733618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Callbacks that receives notifications for animation timing and frame commit timing.
2743618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
2753618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    interface AnimationFrameCallback {
2763618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        /**
2773618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * Run animation based on the frame time.
2783618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * @param frameTime The frame start time, in the {@link SystemClock#uptimeMillis()} time
2793618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         *                  base.
28013351997aa36eb53e5ff0fcee3f5e3da83787278Doris Liu         * @return if the animation has finished.
2813618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         */
28213351997aa36eb53e5ff0fcee3f5e3da83787278Doris Liu        boolean doAnimationFrame(long frameTime);
2833618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
2843618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        /**
2853618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * This notifies the callback of frame commit time. Frame commit time is the time after
2863618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * traversals happen, as opposed to the normal animation frame time that is before
2873618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * traversals. This is used to compensate expensive traversals that happen as the
2883618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * animation starts. When traversals take a long time to complete, the rendering of the
2893618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * initial frame will be delayed (by a long time). But since the startTime of the
2903618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * animation is set before the traversal, by the time of next frame, a lot of time would
2913618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * have passed since startTime was set, the animation will consequently skip a few frames
2923618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * to respect the new frameTime. By having the commit time, we can adjust the start time to
2933618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * when the first frame was drawn (after any expensive traversals) so that no frames
2943618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * will be skipped.
2953618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         *
2963618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         * @param frameTime The frame time after traversals happen, if any, in the
2973618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         *                  {@link SystemClock#uptimeMillis()} time base.
2983618d30f8ab6018025b11869676b309c3b4961cfDoris Liu         */
2993618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        void commitAnimationFrame(long frameTime);
3003618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
3013618d30f8ab6018025b11869676b309c3b4961cfDoris Liu
3023618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    /**
3033618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * The intention for having this interface is to increase the testability of ValueAnimator.
3043618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * Specifically, we can have a custom implementation of the interface below and provide
3053618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * timing pulse without using Choreographer. That way we could use any arbitrary interval for
3063618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * our timing pulse in the tests.
3073618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     *
3083618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     * @hide
3093618d30f8ab6018025b11869676b309c3b4961cfDoris Liu     */
3103618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    public interface AnimationFrameCallbackProvider {
3113618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        void postFrameCallback(Choreographer.FrameCallback callback);
3123618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        void postCommitCallback(Runnable runnable);
3133618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        long getFrameTime();
3143618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        long getFrameDelay();
3153618d30f8ab6018025b11869676b309c3b4961cfDoris Liu        void setFrameDelay(long delay);
3163618d30f8ab6018025b11869676b309c3b4961cfDoris Liu    }
3173618d30f8ab6018025b11869676b309c3b4961cfDoris Liu}
318