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
41e852801f9258e00f89da48918b58a6e933643ab9Aurimas Liutikas    private long 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
62c530cc115fddab8e1d9645b322424dd45f9ecd0dKirill Grouchnikov        // Reset the animated fraction
63c530cc115fddab8e1d9645b322424dd45f9ecd0dKirill Grouchnikov        mAnimatedFraction = 0f;
64c530cc115fddab8e1d9645b322424dd45f9ecd0dKirill Grouchnikov
65631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mListener != null) {
66631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mListener.onAnimationStart();
67631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
68631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
69631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        sHandler.postDelayed(mRunnable, HANDLER_DELAY);
70631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
71631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
72631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
73631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public boolean isRunning() {
74631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        return mIsRunning;
75631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
76631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
77631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
78631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setInterpolator(Interpolator interpolator) {
79631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mInterpolator = interpolator;
80631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
81631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
82631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
83631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setListener(AnimatorListenerProxy listener) {
84631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mListener = listener;
85631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
86631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
87631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
88631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setUpdateListener(AnimatorUpdateListenerProxy updateListener) {
89631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mUpdateListener = updateListener;
90631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
91631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
92631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
93631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setIntValues(int from, int to) {
94631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mIntValues[0] = from;
95631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mIntValues[1] = to;
96631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
97631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
98631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
99631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public int getAnimatedIntValue() {
100631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        return AnimationUtils.lerp(mIntValues[0], mIntValues[1], getAnimatedFraction());
101631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
102631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
103631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
104631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void setFloatValues(float from, float to) {
105631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mFloatValues[0] = from;
106631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mFloatValues[1] = to;
107631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
108631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
109631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
110631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public float getAnimatedFloatValue() {
111631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        return AnimationUtils.lerp(mFloatValues[0], mFloatValues[1], getAnimatedFraction());
112631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
113631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
114631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
115e852801f9258e00f89da48918b58a6e933643ab9Aurimas Liutikas    public void setDuration(long duration) {
116631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mDuration = duration;
117631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
118631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
119631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
120631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void cancel() {
121631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        mIsRunning = false;
122631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        sHandler.removeCallbacks(mRunnable);
123631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
124631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mListener != null) {
125631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mListener.onAnimationCancel();
126c530cc115fddab8e1d9645b322424dd45f9ecd0dKirill Grouchnikov            mListener.onAnimationEnd();
127631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
128631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
129631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
130631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
131631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public float getAnimatedFraction() {
132631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        return mAnimatedFraction;
133631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
134631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
135631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    @Override
136631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    public void end() {
137631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mIsRunning) {
138631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mIsRunning = false;
139631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            sHandler.removeCallbacks(mRunnable);
140631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
141631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // Set our animated fraction to 1
142631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mAnimatedFraction = 1f;
143631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
144631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mUpdateListener != null) {
145631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mUpdateListener.onAnimationUpdate();
146631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
147631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
148631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mListener != null) {
149631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mListener.onAnimationEnd();
150631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
151631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
152631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
153631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
154ba2a96aaf54f6fc755856ef05a3c967a5f000b82Chris Banes    @Override
155ba2a96aaf54f6fc755856ef05a3c967a5f000b82Chris Banes    public long getDuration() {
156ba2a96aaf54f6fc755856ef05a3c967a5f000b82Chris Banes        return mDuration;
157ba2a96aaf54f6fc755856ef05a3c967a5f000b82Chris Banes    }
158ba2a96aaf54f6fc755856ef05a3c967a5f000b82Chris Banes
159631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private void update() {
160631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mIsRunning) {
161631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // Update the animated fraction
162631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            final long elapsed = SystemClock.uptimeMillis() - mStartTime;
163c530cc115fddab8e1d9645b322424dd45f9ecd0dKirill Grouchnikov            final float linearFraction = MathUtils.constrain(elapsed / (float) mDuration, 0f, 1f);
164631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            mAnimatedFraction = mInterpolator != null
165631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    ? mInterpolator.getInterpolation(linearFraction)
166631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    : linearFraction;
167631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
168631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // If we're running, dispatch tp the listener
169631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (mUpdateListener != null) {
170631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mUpdateListener.onAnimationUpdate();
171631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
172631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
173631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // Check to see if we've passed the animation duration
174631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            if (SystemClock.uptimeMillis() >= (mStartTime + mDuration)) {
175631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                mIsRunning = false;
176631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
177631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                if (mListener != null) {
178631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                    mListener.onAnimationEnd();
179631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes                }
180631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            }
181631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
182631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
183631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        if (mIsRunning) {
184631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            // If we're still running, post another delayed runnable
185631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            sHandler.postDelayed(mRunnable, HANDLER_DELAY);
186631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
187631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    }
188631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes
189631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    private final Runnable mRunnable = new Runnable() {
190631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        public void run() {
191631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes            update();
192631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes        }
193631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes    };
194631f64ec9c6255f38a7f746d7949b6a537c1180fChris Banes}
195