ValueAnimatorCompatImplEclairMr1.java revision c530cc115fddab8e1d9645b322424dd45f9ecd0d
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.design.widget;
18
19import android.os.Handler;
20import android.os.Looper;
21import android.os.SystemClock;
22import android.view.animation.AccelerateDecelerateInterpolator;
23import android.view.animation.Interpolator;
24
25/**
26 * A 'fake' ValueAnimator implementation which uses a Runnable.
27 */
28class ValueAnimatorCompatImplEclairMr1 extends ValueAnimatorCompat.Impl {
29
30    private static final int HANDLER_DELAY = 10;
31    private static final int DEFAULT_DURATION = 200;
32
33    private static final Handler sHandler = new Handler(Looper.getMainLooper());
34
35    private long mStartTime;
36    private boolean mIsRunning;
37
38    private final int[] mIntValues = new int[2];
39    private final float[] mFloatValues = new float[2];
40
41    private int mDuration = DEFAULT_DURATION;
42    private Interpolator mInterpolator;
43    private AnimatorListenerProxy mListener;
44    private AnimatorUpdateListenerProxy mUpdateListener;
45
46    private float mAnimatedFraction;
47
48    @Override
49    public void start() {
50        if (mIsRunning) {
51            // If we're already running, ignore
52            return;
53        }
54
55        if (mInterpolator == null) {
56            mInterpolator = new AccelerateDecelerateInterpolator();
57        }
58
59        mStartTime = SystemClock.uptimeMillis();
60        mIsRunning = true;
61
62        // Reset the animated fraction
63        mAnimatedFraction = 0f;
64
65        if (mListener != null) {
66            mListener.onAnimationStart();
67        }
68
69        sHandler.postDelayed(mRunnable, HANDLER_DELAY);
70    }
71
72    @Override
73    public boolean isRunning() {
74        return mIsRunning;
75    }
76
77    @Override
78    public void setInterpolator(Interpolator interpolator) {
79        mInterpolator = interpolator;
80    }
81
82    @Override
83    public void setListener(AnimatorListenerProxy listener) {
84        mListener = listener;
85    }
86
87    @Override
88    public void setUpdateListener(AnimatorUpdateListenerProxy updateListener) {
89        mUpdateListener = updateListener;
90    }
91
92    @Override
93    public void setIntValues(int from, int to) {
94        mIntValues[0] = from;
95        mIntValues[1] = to;
96    }
97
98    @Override
99    public int getAnimatedIntValue() {
100        return AnimationUtils.lerp(mIntValues[0], mIntValues[1], getAnimatedFraction());
101    }
102
103    @Override
104    public void setFloatValues(float from, float to) {
105        mFloatValues[0] = from;
106        mFloatValues[1] = to;
107    }
108
109    @Override
110    public float getAnimatedFloatValue() {
111        return AnimationUtils.lerp(mFloatValues[0], mFloatValues[1], getAnimatedFraction());
112    }
113
114    @Override
115    public void setDuration(int duration) {
116        mDuration = duration;
117    }
118
119    @Override
120    public void cancel() {
121        mIsRunning = false;
122        sHandler.removeCallbacks(mRunnable);
123
124        if (mListener != null) {
125            mListener.onAnimationCancel();
126            mListener.onAnimationEnd();
127        }
128    }
129
130    @Override
131    public float getAnimatedFraction() {
132        return mAnimatedFraction;
133    }
134
135    @Override
136    public void end() {
137        if (mIsRunning) {
138            mIsRunning = false;
139            sHandler.removeCallbacks(mRunnable);
140
141            // Set our animated fraction to 1
142            mAnimatedFraction = 1f;
143
144            if (mUpdateListener != null) {
145                mUpdateListener.onAnimationUpdate();
146            }
147
148            if (mListener != null) {
149                mListener.onAnimationEnd();
150            }
151        }
152    }
153
154    @Override
155    public long getDuration() {
156        return mDuration;
157    }
158
159    private void update() {
160        if (mIsRunning) {
161            // Update the animated fraction
162            final long elapsed = SystemClock.uptimeMillis() - mStartTime;
163            final float linearFraction = MathUtils.constrain(elapsed / (float) mDuration, 0f, 1f);
164            mAnimatedFraction = mInterpolator != null
165                    ? mInterpolator.getInterpolation(linearFraction)
166                    : linearFraction;
167
168            // If we're running, dispatch tp the listener
169            if (mUpdateListener != null) {
170                mUpdateListener.onAnimationUpdate();
171            }
172
173            // Check to see if we've passed the animation duration
174            if (SystemClock.uptimeMillis() >= (mStartTime + mDuration)) {
175                mIsRunning = false;
176
177                if (mListener != null) {
178                    mListener.onAnimationEnd();
179                }
180            }
181        }
182
183        if (mIsRunning) {
184            // If we're still running, post another delayed runnable
185            sHandler.postDelayed(mRunnable, HANDLER_DELAY);
186        }
187    }
188
189    private final Runnable mRunnable = new Runnable() {
190        public void run() {
191            update();
192        }
193    };
194}
195