1/*
2 * Copyright (C) 2010 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.animation;
18
19/**
20 * This class holds a time/value pair for an animation. The Keyframe class is used
21 * by {@link ValueAnimator} to define the values that the animation target will have over the course
22 * of the animation. As the time proceeds from one keyframe to the other, the value of the
23 * target object will animate between the value at the previous keyframe and the value at the
24 * next keyframe. Each keyframe also holds an optional {@link TimeInterpolator}
25 * object, which defines the time interpolation over the intervalue preceding the keyframe.
26 *
27 * <p>The Keyframe class itself is abstract. The type-specific factory methods will return
28 * a subclass of Keyframe specific to the type of value being stored. This is done to improve
29 * performance when dealing with the most common cases (e.g., <code>float</code> and
30 * <code>int</code> values). Other types will fall into a more general Keyframe class that
31 * treats its values as Objects. Unless your animation requires dealing with a custom type
32 * or a data structure that needs to be animated directly (and evaluated using an implementation
33 * of {@link TypeEvaluator}), you should stick to using float and int as animations using those
34 * types have lower runtime overhead than other types.</p>
35 */
36public abstract class Keyframe implements Cloneable {
37    /**
38     * The time at which mValue will hold true.
39     */
40    float mFraction;
41
42    /**
43     * The type of the value in this Keyframe. This type is determined at construction time,
44     * based on the type of the <code>value</code> object passed into the constructor.
45     */
46    Class mValueType;
47
48    /**
49     * The optional time interpolator for the interval preceding this keyframe. A null interpolator
50     * (the default) results in linear interpolation over the interval.
51     */
52    private TimeInterpolator mInterpolator = null;
53
54    /**
55     * Flag to indicate whether this keyframe has a valid value. This flag is used when an
56     * animation first starts, to populate placeholder keyframes with real values derived
57     * from the target object.
58     */
59    boolean mHasValue = false;
60
61    /**
62     * Constructs a Keyframe object with the given time and value. The time defines the
63     * time, as a proportion of an overall animation's duration, at which the value will hold true
64     * for the animation. The value for the animation between keyframes will be calculated as
65     * an interpolation between the values at those keyframes.
66     *
67     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
68     * of time elapsed of the overall animation duration.
69     * @param value The value that the object will animate to as the animation time approaches
70     * the time in this keyframe, and the the value animated from as the time passes the time in
71     * this keyframe.
72     */
73    public static Keyframe ofInt(float fraction, int value) {
74        return new IntKeyframe(fraction, value);
75    }
76
77    /**
78     * Constructs a Keyframe object with the given time. The value at this time will be derived
79     * from the target object when the animation first starts (note that this implies that keyframes
80     * with no initial value must be used as part of an {@link ObjectAnimator}).
81     * The time defines the
82     * time, as a proportion of an overall animation's duration, at which the value will hold true
83     * for the animation. The value for the animation between keyframes will be calculated as
84     * an interpolation between the values at those keyframes.
85     *
86     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
87     * of time elapsed of the overall animation duration.
88     */
89    public static Keyframe ofInt(float fraction) {
90        return new IntKeyframe(fraction);
91    }
92
93    /**
94     * Constructs a Keyframe object with the given time and value. The time defines the
95     * time, as a proportion of an overall animation's duration, at which the value will hold true
96     * for the animation. The value for the animation between keyframes will be calculated as
97     * an interpolation between the values at those keyframes.
98     *
99     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
100     * of time elapsed of the overall animation duration.
101     * @param value The value that the object will animate to as the animation time approaches
102     * the time in this keyframe, and the the value animated from as the time passes the time in
103     * this keyframe.
104     */
105    public static Keyframe ofFloat(float fraction, float value) {
106        return new FloatKeyframe(fraction, value);
107    }
108
109    /**
110     * Constructs a Keyframe object with the given time. The value at this time will be derived
111     * from the target object when the animation first starts (note that this implies that keyframes
112     * with no initial value must be used as part of an {@link ObjectAnimator}).
113     * The time defines the
114     * time, as a proportion of an overall animation's duration, at which the value will hold true
115     * for the animation. The value for the animation between keyframes will be calculated as
116     * an interpolation between the values at those keyframes.
117     *
118     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
119     * of time elapsed of the overall animation duration.
120     */
121    public static Keyframe ofFloat(float fraction) {
122        return new FloatKeyframe(fraction);
123    }
124
125    /**
126     * Constructs a Keyframe object with the given time and value. The time defines the
127     * time, as a proportion of an overall animation's duration, at which the value will hold true
128     * for the animation. The value for the animation between keyframes will be calculated as
129     * an interpolation between the values at those keyframes.
130     *
131     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
132     * of time elapsed of the overall animation duration.
133     * @param value The value that the object will animate to as the animation time approaches
134     * the time in this keyframe, and the the value animated from as the time passes the time in
135     * this keyframe.
136     */
137    public static Keyframe ofObject(float fraction, Object value) {
138        return new ObjectKeyframe(fraction, value);
139    }
140
141    /**
142     * Constructs a Keyframe object with the given time. The value at this time will be derived
143     * from the target object when the animation first starts (note that this implies that keyframes
144     * with no initial value must be used as part of an {@link ObjectAnimator}).
145     * The time defines the
146     * time, as a proportion of an overall animation's duration, at which the value will hold true
147     * for the animation. The value for the animation between keyframes will be calculated as
148     * an interpolation between the values at those keyframes.
149     *
150     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
151     * of time elapsed of the overall animation duration.
152     */
153    public static Keyframe ofObject(float fraction) {
154        return new ObjectKeyframe(fraction, null);
155    }
156
157    /**
158     * Indicates whether this keyframe has a valid value. This method is called internally when
159     * an {@link ObjectAnimator} first starts; keyframes without values are assigned values at
160     * that time by deriving the value for the property from the target object.
161     *
162     * @return boolean Whether this object has a value assigned.
163     */
164    public boolean hasValue() {
165        return mHasValue;
166    }
167
168    /**
169     * Gets the value for this Keyframe.
170     *
171     * @return The value for this Keyframe.
172     */
173    public abstract Object getValue();
174
175    /**
176     * Sets the value for this Keyframe.
177     *
178     * @param value value for this Keyframe.
179     */
180    public abstract void setValue(Object value);
181
182    /**
183     * Gets the time for this keyframe, as a fraction of the overall animation duration.
184     *
185     * @return The time associated with this keyframe, as a fraction of the overall animation
186     * duration. This should be a value between 0 and 1.
187     */
188    public float getFraction() {
189        return mFraction;
190    }
191
192    /**
193     * Sets the time for this keyframe, as a fraction of the overall animation duration.
194     *
195     * @param fraction time associated with this keyframe, as a fraction of the overall animation
196     * duration. This should be a value between 0 and 1.
197     */
198    public void setFraction(float fraction) {
199        mFraction = fraction;
200    }
201
202    /**
203     * Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
204     * that there is no interpolation, which is the same as linear interpolation.
205     *
206     * @return The optional interpolator for this Keyframe.
207     */
208    public TimeInterpolator getInterpolator() {
209        return mInterpolator;
210    }
211
212    /**
213     * Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
214     * that there is no interpolation, which is the same as linear interpolation.
215     *
216     * @return The optional interpolator for this Keyframe.
217     */
218    public void setInterpolator(TimeInterpolator interpolator) {
219        mInterpolator = interpolator;
220    }
221
222    /**
223     * Gets the type of keyframe. This information is used by ValueAnimator to determine the type of
224     * {@link TypeEvaluator} to use when calculating values between keyframes. The type is based
225     * on the type of Keyframe created.
226     *
227     * @return The type of the value stored in the Keyframe.
228     */
229    public Class getType() {
230        return mValueType;
231    }
232
233    @Override
234    public abstract Keyframe clone();
235
236    /**
237     * This internal subclass is used for all types which are not int or float.
238     */
239    static class ObjectKeyframe extends Keyframe {
240
241        /**
242         * The value of the animation at the time mFraction.
243         */
244        Object mValue;
245
246        ObjectKeyframe(float fraction, Object value) {
247            mFraction = fraction;
248            mValue = value;
249            mHasValue = (value != null);
250            mValueType = mHasValue ? value.getClass() : Object.class;
251        }
252
253        public Object getValue() {
254            return mValue;
255        }
256
257        public void setValue(Object value) {
258            mValue = value;
259            mHasValue = (value != null);
260        }
261
262        @Override
263        public ObjectKeyframe clone() {
264            ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mHasValue ? mValue : null);
265            kfClone.setInterpolator(getInterpolator());
266            return kfClone;
267        }
268    }
269
270    /**
271     * Internal subclass used when the keyframe value is of type int.
272     */
273    static class IntKeyframe extends Keyframe {
274
275        /**
276         * The value of the animation at the time mFraction.
277         */
278        int mValue;
279
280        IntKeyframe(float fraction, int value) {
281            mFraction = fraction;
282            mValue = value;
283            mValueType = int.class;
284            mHasValue = true;
285        }
286
287        IntKeyframe(float fraction) {
288            mFraction = fraction;
289            mValueType = int.class;
290        }
291
292        public int getIntValue() {
293            return mValue;
294        }
295
296        public Object getValue() {
297            return mValue;
298        }
299
300        public void setValue(Object value) {
301            if (value != null && value.getClass() == Integer.class) {
302                mValue = ((Integer)value).intValue();
303                mHasValue = true;
304            }
305        }
306
307        @Override
308        public IntKeyframe clone() {
309            IntKeyframe kfClone = mHasValue ?
310                    new IntKeyframe(getFraction(), mValue) :
311                    new IntKeyframe(getFraction());
312            kfClone.setInterpolator(getInterpolator());
313            return kfClone;
314        }
315    }
316
317    /**
318     * Internal subclass used when the keyframe value is of type float.
319     */
320    static class FloatKeyframe extends Keyframe {
321        /**
322         * The value of the animation at the time mFraction.
323         */
324        float mValue;
325
326        FloatKeyframe(float fraction, float value) {
327            mFraction = fraction;
328            mValue = value;
329            mValueType = float.class;
330            mHasValue = true;
331        }
332
333        FloatKeyframe(float fraction) {
334            mFraction = fraction;
335            mValueType = float.class;
336        }
337
338        public float getFloatValue() {
339            return mValue;
340        }
341
342        public Object getValue() {
343            return mValue;
344        }
345
346        public void setValue(Object value) {
347            if (value != null && value.getClass() == Float.class) {
348                mValue = ((Float)value).floatValue();
349                mHasValue = true;
350            }
351        }
352
353        @Override
354        public FloatKeyframe clone() {
355            FloatKeyframe kfClone = mHasValue ?
356                    new FloatKeyframe(getFraction(), mValue) :
357                    new FloatKeyframe(getFraction());
358            kfClone.setInterpolator(getInterpolator());
359            return kfClone;
360        }
361    }
362}
363