1631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes/*
2631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * Copyright (C) 2015 The Android Open Source Project
3631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes *
4631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * Licensed under the Apache License, Version 2.0 (the "License");
5631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * you may not use this file except in compliance with the License.
6631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * You may obtain a copy of the License at
7631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes *
8631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes *      http://www.apache.org/licenses/LICENSE-2.0
9631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes *
10631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * Unless required by applicable law or agreed to in writing, software
11631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * distributed under the License is distributed on an "AS IS" BASIS,
12631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * See the License for the specific language governing permissions and
14631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * limitations under the License.
15631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes */
16631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
17631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banespackage android.support.design.widget;
18631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
19631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport android.os.Handler;
20631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport android.os.Looper;
21631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport android.os.SystemClock;
22631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport android.view.animation.AccelerateDecelerateInterpolator;
23631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesimport android.view.animation.Interpolator;
24631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
25631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes/**
26631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes * A 'fake' ValueAnimator implementation which uses a Runnable.
27631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes */
28631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banesclass ValueAnimatorCompatImplEclairMr1 extends ValueAnimatorCompat.Impl {
29631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
30631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private static final int HANDLER_DELAY = 10;
31631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private static final int DEFAULT_DURATION = 200;
32631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
33631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private static final Handler sHandler = new Handler(Looper.getMainLooper());
34631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
35631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private long mStartTime;
36631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private boolean mIsRunning;
37631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
38631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private final int[] mIntValues = new int[2];
39631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private final float[] mFloatValues = new float[2];
40631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
41631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private int mDuration = DEFAULT_DURATION;
42631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private Interpolator mInterpolator;
43631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private AnimatorListenerProxy mListener;
44631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private AnimatorUpdateListenerProxy mUpdateListener;
45631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
46631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private float mAnimatedFraction;
47631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
48631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
49631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void start() {
50631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mIsRunning) {
51631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // If we're already running, ignore
52631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            return;
53631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
54631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
55631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mInterpolator == null) {
56631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mInterpolator = new AccelerateDecelerateInterpolator();
57631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
58631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
59631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mStartTime = SystemClock.uptimeMillis();
60631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mIsRunning = true;
61631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
62631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mListener != null) {
63631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mListener.onAnimationStart();
64631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
65631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
66631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        sHandler.postDelayed(mRunnable, HANDLER_DELAY);
67631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
68631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
69631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
70631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public boolean isRunning() {
71631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        return mIsRunning;
72631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
73631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
74631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
75631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setInterpolator(Interpolator interpolator) {
76631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mInterpolator = interpolator;
77631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
78631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
79631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
80631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setListener(AnimatorListenerProxy listener) {
81631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mListener = listener;
82631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
83631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
84631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
85631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setUpdateListener(AnimatorUpdateListenerProxy updateListener) {
86631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mUpdateListener = updateListener;
87631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
88631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
89631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
90631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setIntValues(int from, int to) {
91631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mIntValues[0] = from;
92631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mIntValues[1] = to;
93631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
94631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
95631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
96631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public int getAnimatedIntValue() {
97631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        return AnimationUtils.lerp(mIntValues[0], mIntValues[1], getAnimatedFraction());
98631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
99631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
100631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
101631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setFloatValues(float from, float to) {
102631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mFloatValues[0] = from;
103631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mFloatValues[1] = to;
104631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
105631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
106631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
107631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public float getAnimatedFloatValue() {
108631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        return AnimationUtils.lerp(mFloatValues[0], mFloatValues[1], getAnimatedFraction());
109631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
110631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
111631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
112631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setDuration(int duration) {
113631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mDuration = duration;
114631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
115631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
116631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
117631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void cancel() {
118631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mIsRunning = false;
119631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        sHandler.removeCallbacks(mRunnable);
120631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
121631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mListener != null) {
122631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mListener.onAnimationCancel();
123631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
124631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
125631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
126631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
127631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public float getAnimatedFraction() {
128631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        return mAnimatedFraction;
129631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
130631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
131631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
132631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void end() {
133631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mIsRunning) {
134631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mIsRunning = false;
135631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            sHandler.removeCallbacks(mRunnable);
136631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
137631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // Set our animated fraction to 1
138631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mAnimatedFraction = 1f;
139631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
140631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mUpdateListener != null) {
141631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mUpdateListener.onAnimationUpdate();
142631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
143631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
144631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mListener != null) {
145631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mListener.onAnimationEnd();
146631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
147631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
148631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
149631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
150631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private void update() {
151631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mIsRunning) {
152631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // Update the animated fraction
153631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final long elapsed = SystemClock.uptimeMillis() - mStartTime;
154631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final float linearFraction = elapsed / (float) mDuration;
155631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mAnimatedFraction = mInterpolator != null
156631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    ? mInterpolator.getInterpolation(linearFraction)
157631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    : linearFraction;
158631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
159631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // If we're running, dispatch tp the listener
160631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mUpdateListener != null) {
161631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mUpdateListener.onAnimationUpdate();
162631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
163631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
164631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // Check to see if we've passed the animation duration
165631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (SystemClock.uptimeMillis() >= (mStartTime + mDuration)) {
166631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mIsRunning = false;
167631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
168631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                if (mListener != null) {
169631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    mListener.onAnimationEnd();
170631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                }
171631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
172631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
173631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
174631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mIsRunning) {
175631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // If we're still running, post another delayed runnable
176631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            sHandler.postDelayed(mRunnable, HANDLER_DELAY);
177631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
178631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
179631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
180631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private final Runnable mRunnable = new Runnable() {
181631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        public void run() {
182631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            update();
183631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
184631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    };
185631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes}
186