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