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