1 /*
2  * Copyright (C) 2006 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 android.view.animation;
18 
19 import android.annotation.AnimRes;
20 import android.annotation.ColorInt;
21 import android.annotation.InterpolatorRes;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.content.Context;
24 import android.content.res.TypedArray;
25 import android.graphics.RectF;
26 import android.os.Build;
27 import android.os.Handler;
28 import android.os.SystemProperties;
29 import android.util.AttributeSet;
30 import android.util.TypedValue;
31 
32 import dalvik.system.CloseGuard;
33 
34 /**
35  * Abstraction for an Animation that can be applied to Views, Surfaces, or
36  * other objects. See the {@link android.view.animation animation package
37  * description file}.
38  */
39 public abstract class Animation implements Cloneable {
40     /**
41      * Repeat the animation indefinitely.
42      */
43     public static final int INFINITE = -1;
44 
45     /**
46      * When the animation reaches the end and the repeat count is INFINTE_REPEAT
47      * or a positive value, the animation restarts from the beginning.
48      */
49     public static final int RESTART = 1;
50 
51     /**
52      * When the animation reaches the end and the repeat count is INFINTE_REPEAT
53      * or a positive value, the animation plays backward (and then forward again).
54      */
55     public static final int REVERSE = 2;
56 
57     /**
58      * Can be used as the start time to indicate the start time should be the current
59      * time when {@link #getTransformation(long, Transformation)} is invoked for the
60      * first animation frame. This can is useful for short animations.
61      */
62     public static final int START_ON_FIRST_FRAME = -1;
63 
64     /**
65      * The specified dimension is an absolute number of pixels.
66      */
67     public static final int ABSOLUTE = 0;
68 
69     /**
70      * The specified dimension holds a float and should be multiplied by the
71      * height or width of the object being animated.
72      */
73     public static final int RELATIVE_TO_SELF = 1;
74 
75     /**
76      * The specified dimension holds a float and should be multiplied by the
77      * height or width of the parent of the object being animated.
78      */
79     public static final int RELATIVE_TO_PARENT = 2;
80 
81     /**
82      * Requests that the content being animated be kept in its current Z
83      * order.
84      */
85     public static final int ZORDER_NORMAL = 0;
86 
87     /**
88      * Requests that the content being animated be forced on top of all other
89      * content for the duration of the animation.
90      */
91     public static final int ZORDER_TOP = 1;
92 
93     /**
94      * Requests that the content being animated be forced under all other
95      * content for the duration of the animation.
96      */
97     public static final int ZORDER_BOTTOM = -1;
98 
99     // Use a preload holder to isolate static initialization into inner class, which allows
100     // Animation and its subclasses to be compile-time initialized.
101     private static class NoImagePreloadHolder {
102         public static final boolean USE_CLOSEGUARD
103                 = SystemProperties.getBoolean("log.closeguard.Animation", false);
104     }
105 
106     /**
107      * Set by {@link #getTransformation(long, Transformation)} when the animation ends.
108      */
109     boolean mEnded = false;
110 
111     /**
112      * Set by {@link #getTransformation(long, Transformation)} when the animation starts.
113      */
114     boolean mStarted = false;
115 
116     /**
117      * Set by {@link #getTransformation(long, Transformation)} when the animation repeats
118      * in REVERSE mode.
119      */
120     boolean mCycleFlip = false;
121 
122     /**
123      * This value must be set to true by {@link #initialize(int, int, int, int)}. It
124      * indicates the animation was successfully initialized and can be played.
125      */
126     boolean mInitialized = false;
127 
128     /**
129      * Indicates whether the animation transformation should be applied before the
130      * animation starts. The value of this variable is only relevant if mFillEnabled is true;
131      * otherwise it is assumed to be true.
132      */
133     boolean mFillBefore = true;
134 
135     /**
136      * Indicates whether the animation transformation should be applied after the
137      * animation ends.
138      */
139     boolean mFillAfter = false;
140 
141     /**
142      * Indicates whether fillBefore should be taken into account.
143      */
144     boolean mFillEnabled = false;
145 
146     /**
147      * The time in milliseconds at which the animation must start;
148      */
149     long mStartTime = -1;
150 
151     /**
152      * The delay in milliseconds after which the animation must start. When the
153      * start offset is > 0, the start time of the animation is startTime + startOffset.
154      */
155     long mStartOffset;
156 
157     /**
158      * The duration of one animation cycle in milliseconds.
159      */
160     long mDuration;
161 
162     /**
163      * The number of times the animation must repeat. By default, an animation repeats
164      * indefinitely.
165      */
166     int mRepeatCount = 0;
167 
168     /**
169      * Indicates how many times the animation was repeated.
170      */
171     int mRepeated = 0;
172 
173     /**
174      * The behavior of the animation when it repeats. The repeat mode is either
175      * {@link #RESTART} or {@link #REVERSE}.
176      *
177      */
178     int mRepeatMode = RESTART;
179 
180     /**
181      * The interpolator used by the animation to smooth the movement.
182      */
183     Interpolator mInterpolator;
184 
185     /**
186      * An animation listener to be notified when the animation starts, ends or repeats.
187      */
188     // If you need to chain the AnimationListener, wrap the existing Animation into an AnimationSet
189     // and add your new listener to that set
190     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117519981)
191     private AnimationListener mListener;
192 
193     /**
194      * Desired Z order mode during animation.
195      */
196     private int mZAdjustment;
197 
198     /**
199      * The desired color of the backdrop to show behind the animation.
200      */
201     private int mBackdropColor;
202 
203     /**
204      * scalefactor to apply to pivot points, etc. during animation. Subclasses retrieve the
205      * value via getScaleFactor().
206      */
207     private float mScaleFactor = 1f;
208 
209     private boolean mShowWallpaper;
210     private boolean mHasRoundedCorners;
211 
212     /**
213      * Whether to show a background behind the windows during the animation.
214      * @see #getShowBackdrop()
215      * @see #setShowBackdrop(boolean)
216      */
217     private boolean mShowBackdrop;
218 
219     private boolean mMore = true;
220     private boolean mOneMoreTime = true;
221 
222     @UnsupportedAppUsage
223     RectF mPreviousRegion = new RectF();
224     @UnsupportedAppUsage
225     RectF mRegion = new RectF();
226     @UnsupportedAppUsage
227     Transformation mTransformation = new Transformation();
228     @UnsupportedAppUsage
229     Transformation mPreviousTransformation = new Transformation();
230 
231     private final CloseGuard guard = CloseGuard.get();
232 
233     private Handler mListenerHandler;
234     private Runnable mOnStart;
235     private Runnable mOnRepeat;
236     private Runnable mOnEnd;
237 
238     /**
239      * Creates a new animation with a duration of 0ms, the default interpolator, with
240      * fillBefore set to true and fillAfter set to false
241      */
Animation()242     public Animation() {
243         ensureInterpolator();
244     }
245 
246     /**
247      * Creates a new animation whose parameters come from the specified context and
248      * attributes set.
249      *
250      * @param context the application environment
251      * @param attrs the set of attributes holding the animation parameters
252      */
Animation(Context context, AttributeSet attrs)253     public Animation(Context context, AttributeSet attrs) {
254         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation);
255 
256         setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0));
257         setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0));
258 
259         setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled));
260         setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
261         setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));
262 
263         setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount));
264         setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));
265 
266         setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
267 
268         setBackdropColor(a.getInt(com.android.internal.R.styleable.Animation_backdropColor, 0));
269 
270         setDetachWallpaper(
271                 a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
272         setShowWallpaper(
273                 a.getBoolean(com.android.internal.R.styleable.Animation_showWallpaper, false));
274         setHasRoundedCorners(
275                 a.getBoolean(com.android.internal.R.styleable.Animation_hasRoundedCorners, false));
276         setShowBackdrop(
277                 a.getBoolean(com.android.internal.R.styleable.Animation_showBackdrop, false));
278 
279         final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
280 
281         a.recycle();
282 
283         if (resID > 0) {
284             setInterpolator(context, resID);
285         }
286 
287         ensureInterpolator();
288     }
289 
290     @Override
clone()291     protected Animation clone() throws CloneNotSupportedException {
292         final Animation animation = (Animation) super.clone();
293         animation.mPreviousRegion = new RectF();
294         animation.mRegion = new RectF();
295         animation.mTransformation = new Transformation();
296         animation.mPreviousTransformation = new Transformation();
297         return animation;
298     }
299 
300     /**
301      * Reset the initialization state of this animation.
302      *
303      * @see #initialize(int, int, int, int)
304      */
reset()305     public void reset() {
306         mPreviousRegion.setEmpty();
307         mPreviousTransformation.clear();
308         mInitialized = false;
309         mCycleFlip = false;
310         mRepeated = 0;
311         mMore = true;
312         mOneMoreTime = true;
313         mListenerHandler = null;
314     }
315 
316     /**
317      * Cancel the animation. Cancelling an animation invokes the animation
318      * listener, if set, to notify the end of the animation.
319      *
320      * If you cancel an animation manually, you must call {@link #reset()}
321      * before starting the animation again.
322      *
323      * @see #reset()
324      * @see #start()
325      * @see #startNow()
326      */
cancel()327     public void cancel() {
328         if (mStarted && !mEnded) {
329             fireAnimationEnd();
330             mEnded = true;
331             guard.close();
332         }
333         // Make sure we move the animation to the end
334         mStartTime = Long.MIN_VALUE;
335         mMore = mOneMoreTime = false;
336     }
337 
338     /**
339      * @hide
340      */
341     @UnsupportedAppUsage
detach()342     public void detach() {
343         if (mStarted && !mEnded) {
344             mEnded = true;
345             guard.close();
346             fireAnimationEnd();
347         }
348     }
349 
350     /**
351      * Whether or not the animation has been initialized.
352      *
353      * @return Has this animation been initialized.
354      * @see #initialize(int, int, int, int)
355      */
isInitialized()356     public boolean isInitialized() {
357         return mInitialized;
358     }
359 
360     /**
361      * Initialize this animation with the dimensions of the object being
362      * animated as well as the objects parents. (This is to support animation
363      * sizes being specified relative to these dimensions.)
364      *
365      * <p>Objects that interpret Animations should call this method when
366      * the sizes of the object being animated and its parent are known, and
367      * before calling {@link #getTransformation}.
368      *
369      *
370      * @param width Width of the object being animated
371      * @param height Height of the object being animated
372      * @param parentWidth Width of the animated object's parent
373      * @param parentHeight Height of the animated object's parent
374      */
initialize(int width, int height, int parentWidth, int parentHeight)375     public void initialize(int width, int height, int parentWidth, int parentHeight) {
376         reset();
377         mInitialized = true;
378     }
379 
380     /**
381      * Sets the handler used to invoke listeners.
382      *
383      * @hide
384      */
setListenerHandler(Handler handler)385     public void setListenerHandler(Handler handler) {
386         if (mListenerHandler == null) {
387             mOnStart = new Runnable() {
388                 public void run() {
389                     dispatchAnimationStart();
390                 }
391             };
392             mOnRepeat = new Runnable() {
393                 public void run() {
394                     dispatchAnimationRepeat();
395                 }
396             };
397             mOnEnd = new Runnable() {
398                 public void run() {
399                     dispatchAnimationEnd();
400                 }
401             };
402         }
403         mListenerHandler = handler;
404     }
405 
406     /**
407      * Sets the acceleration curve for this animation. The interpolator is loaded as
408      * a resource from the specified context.
409      *
410      * @param context The application environment
411      * @param resID The resource identifier of the interpolator to load
412      * @attr ref android.R.styleable#Animation_interpolator
413      */
setInterpolator(Context context, @AnimRes @InterpolatorRes int resID)414     public void setInterpolator(Context context, @AnimRes @InterpolatorRes int resID) {
415         setInterpolator(AnimationUtils.loadInterpolator(context, resID));
416     }
417 
418     /**
419      * Sets the acceleration curve for this animation. Defaults to a linear
420      * interpolation.
421      *
422      * @param i The interpolator which defines the acceleration curve
423      * @attr ref android.R.styleable#Animation_interpolator
424      */
setInterpolator(Interpolator i)425     public void setInterpolator(Interpolator i) {
426         mInterpolator = i;
427     }
428 
429     /**
430      * When this animation should start relative to the start time. This is most
431      * useful when composing complex animations using an {@link AnimationSet }
432      * where some of the animations components start at different times.
433      *
434      * @param startOffset When this Animation should start, in milliseconds from
435      *                    the start time of the root AnimationSet.
436      * @attr ref android.R.styleable#Animation_startOffset
437      */
setStartOffset(long startOffset)438     public void setStartOffset(long startOffset) {
439         mStartOffset = startOffset;
440     }
441 
442     /**
443      * How long this animation should last. The duration cannot be negative.
444      *
445      * @param durationMillis Duration in milliseconds
446      *
447      * @throws java.lang.IllegalArgumentException if the duration is < 0
448      *
449      * @attr ref android.R.styleable#Animation_duration
450      */
setDuration(long durationMillis)451     public void setDuration(long durationMillis) {
452         if (durationMillis < 0) {
453             throw new IllegalArgumentException("Animation duration cannot be negative");
454         }
455         mDuration = durationMillis;
456     }
457 
458     /**
459      * Ensure that the duration that this animation will run is not longer
460      * than <var>durationMillis</var>.  In addition to adjusting the duration
461      * itself, this ensures that the repeat count also will not make it run
462      * longer than the given time.
463      *
464      * @param durationMillis The maximum duration the animation is allowed
465      * to run.
466      */
restrictDuration(long durationMillis)467     public void restrictDuration(long durationMillis) {
468         // If we start after the duration, then we just won't run.
469         if (mStartOffset > durationMillis) {
470             mStartOffset = durationMillis;
471             mDuration = 0;
472             mRepeatCount = 0;
473             return;
474         }
475 
476         long dur = mDuration + mStartOffset;
477         if (dur > durationMillis) {
478             mDuration = durationMillis-mStartOffset;
479             dur = durationMillis;
480         }
481         // If the duration is 0 or less, then we won't run.
482         if (mDuration <= 0) {
483             mDuration = 0;
484             mRepeatCount = 0;
485             return;
486         }
487         // Reduce the number of repeats to keep below the maximum duration.
488         // The comparison between mRepeatCount and duration is to catch
489         // overflows after multiplying them.
490         if (mRepeatCount < 0 || mRepeatCount > durationMillis
491                 || (dur*mRepeatCount) > durationMillis) {
492             // Figure out how many times to do the animation.  Subtract 1 since
493             // repeat count is the number of times to repeat so 0 runs once.
494             mRepeatCount = (int)(durationMillis/dur) - 1;
495             if (mRepeatCount < 0) {
496                 mRepeatCount = 0;
497             }
498         }
499     }
500 
501     /**
502      * How much to scale the duration by.
503      *
504      * @param scale The amount to scale the duration.
505      */
scaleCurrentDuration(float scale)506     public void scaleCurrentDuration(float scale) {
507         mDuration = (long) (mDuration * scale);
508         mStartOffset = (long) (mStartOffset * scale);
509     }
510 
511     /**
512      * When this animation should start. When the start time is set to
513      * {@link #START_ON_FIRST_FRAME}, the animation will start the first time
514      * {@link #getTransformation(long, Transformation)} is invoked. The time passed
515      * to this method should be obtained by calling
516      * {@link AnimationUtils#currentAnimationTimeMillis()} instead of
517      * {@link System#currentTimeMillis()}.
518      *
519      * @param startTimeMillis the start time in milliseconds
520      */
setStartTime(long startTimeMillis)521     public void setStartTime(long startTimeMillis) {
522         mStartTime = startTimeMillis;
523         mStarted = mEnded = false;
524         mCycleFlip = false;
525         mRepeated = 0;
526         mMore = true;
527     }
528 
529     /**
530      * Convenience method to start the animation the first time
531      * {@link #getTransformation(long, Transformation)} is invoked.
532      */
start()533     public void start() {
534         setStartTime(-1);
535     }
536 
537     /**
538      * Convenience method to start the animation at the current time in
539      * milliseconds.
540      */
startNow()541     public void startNow() {
542         setStartTime(AnimationUtils.currentAnimationTimeMillis());
543     }
544 
545     /**
546      * Defines what this animation should do when it reaches the end. This
547      * setting is applied only when the repeat count is either greater than
548      * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
549      *
550      * @param repeatMode {@link #RESTART} or {@link #REVERSE}
551      * @attr ref android.R.styleable#Animation_repeatMode
552      */
setRepeatMode(int repeatMode)553     public void setRepeatMode(int repeatMode) {
554         mRepeatMode = repeatMode;
555     }
556 
557     /**
558      * Sets how many times the animation should be repeated. If the repeat
559      * count is 0, the animation is never repeated. If the repeat count is
560      * greater than 0 or {@link #INFINITE}, the repeat mode will be taken
561      * into account. The repeat count is 0 by default.
562      *
563      * @param repeatCount the number of times the animation should be repeated
564      * @attr ref android.R.styleable#Animation_repeatCount
565      */
setRepeatCount(int repeatCount)566     public void setRepeatCount(int repeatCount) {
567         if (repeatCount < 0) {
568             repeatCount = INFINITE;
569         }
570         mRepeatCount = repeatCount;
571     }
572 
573     /**
574      * If fillEnabled is true, this animation will apply the value of fillBefore.
575      *
576      * @return true if the animation will take fillBefore into account
577      * @attr ref android.R.styleable#Animation_fillEnabled
578      */
isFillEnabled()579     public boolean isFillEnabled() {
580         return mFillEnabled;
581     }
582 
583     /**
584      * If fillEnabled is true, the animation will apply the value of fillBefore.
585      * Otherwise, fillBefore is ignored and the animation
586      * transformation is always applied until the animation ends.
587      *
588      * @param fillEnabled true if the animation should take the value of fillBefore into account
589      * @attr ref android.R.styleable#Animation_fillEnabled
590      *
591      * @see #setFillBefore(boolean)
592      * @see #setFillAfter(boolean)
593      */
setFillEnabled(boolean fillEnabled)594     public void setFillEnabled(boolean fillEnabled) {
595         mFillEnabled = fillEnabled;
596     }
597 
598     /**
599      * If fillBefore is true, this animation will apply its transformation
600      * before the start time of the animation. Defaults to true if
601      * {@link #setFillEnabled(boolean)} is not set to true.
602      * Note that this applies when using an {@link
603      * android.view.animation.AnimationSet AnimationSet} to chain
604      * animations. The transformation is not applied before the AnimationSet
605      * itself starts.
606      *
607      * @param fillBefore true if the animation should apply its transformation before it starts
608      * @attr ref android.R.styleable#Animation_fillBefore
609      *
610      * @see #setFillEnabled(boolean)
611      */
setFillBefore(boolean fillBefore)612     public void setFillBefore(boolean fillBefore) {
613         mFillBefore = fillBefore;
614     }
615 
616     /**
617      * If fillAfter is true, the transformation that this animation performed
618      * will persist when it is finished. Defaults to false if not set.
619      * Note that this applies to individual animations and when using an {@link
620      * android.view.animation.AnimationSet AnimationSet} to chain
621      * animations.
622      *
623      * @param fillAfter true if the animation should apply its transformation after it ends
624      * @attr ref android.R.styleable#Animation_fillAfter
625      *
626      * @see #setFillEnabled(boolean)
627      */
setFillAfter(boolean fillAfter)628     public void setFillAfter(boolean fillAfter) {
629         mFillAfter = fillAfter;
630     }
631 
632     /**
633      * Set the Z ordering mode to use while running the animation.
634      *
635      * @param zAdjustment The desired mode, one of {@link #ZORDER_NORMAL},
636      * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}.
637      * @attr ref android.R.styleable#Animation_zAdjustment
638      */
setZAdjustment(int zAdjustment)639     public void setZAdjustment(int zAdjustment) {
640         mZAdjustment = zAdjustment;
641     }
642 
643     /**
644      * Set background behind animation.
645      *
646      * @param bg The background color.  If 0, no background.  Currently must
647      * be black, with any desired alpha level.
648      *
649      * @deprecated None of window animations are running with background color.
650      * @see #setBackdropColor(int) for an alternative.
651      */
652     @Deprecated
setBackgroundColor(@olorInt int bg)653     public void setBackgroundColor(@ColorInt int bg) {
654         // The background color is not needed any more, do nothing.
655     }
656 
657     /**
658      * The scale factor is set by the call to <code>getTransformation</code>. Overrides of
659      * {@link #getTransformation(long, Transformation, float)} will get this value
660      * directly. Overrides of {@link #applyTransformation(float, Transformation)} can
661      * call this method to get the value.
662      *
663      * @return float The scale factor that should be applied to pre-scaled values in
664      * an Animation such as the pivot points in {@link ScaleAnimation} and {@link RotateAnimation}.
665      */
getScaleFactor()666     protected float getScaleFactor() {
667         return mScaleFactor;
668     }
669 
670     /**
671      * If detachWallpaper is true, and this is a window animation of a window
672      * that has a wallpaper background, then the window will be detached from
673      * the wallpaper while it runs.  That is, the animation will only be applied
674      * to the window, and the wallpaper behind it will remain static.
675      *
676      * @param detachWallpaper true if the wallpaper should be detached from the animation
677      * @attr ref android.R.styleable#Animation_detachWallpaper
678      *
679      * @deprecated All window animations are running with detached wallpaper.
680      */
681     @Deprecated
setDetachWallpaper(boolean detachWallpaper)682     public void setDetachWallpaper(boolean detachWallpaper) {
683     }
684 
685     /**
686      * If this animation is run as a window animation, this will make the wallpaper visible behind
687      * the animation.
688      *
689      * @param showWallpaper Whether the wallpaper should be shown during the animation.
690      * @attr ref android.R.styleable#Animation_detachWallpaper
691      * @hide
692      */
setShowWallpaper(boolean showWallpaper)693     public void setShowWallpaper(boolean showWallpaper) {
694         mShowWallpaper = showWallpaper;
695     }
696 
697     /**
698      * If this is a window animation, the window will have rounded corners matching the display
699      * corner radius.
700      *
701      * @param hasRoundedCorners Whether the window should have rounded corners or not.
702      * @attr ref android.R.styleable#Animation_hasRoundedCorners
703      * @see com.android.internal.policy.ScreenDecorationsUtils#getWindowCornerRadius(Resources)
704      * @hide
705      */
setHasRoundedCorners(boolean hasRoundedCorners)706     public void setHasRoundedCorners(boolean hasRoundedCorners) {
707         mHasRoundedCorners = hasRoundedCorners;
708     }
709 
710     /**
711      * If showBackdrop is {@code true} and this animation is applied on a window, then the windows
712      * in the animation will animate with the background associated with this window behind them.
713      *
714      * If no backdrop color is explicitly set, the backdrop's color comes from the
715      * {@link android.R.styleable#Theme_colorBackground} that is applied to this window through its
716      * theme.
717      *
718      * If multiple animating windows have showBackdrop set to {@code true} during an animation,
719      * the top most window with showBackdrop set to {@code true} and a valid background color
720      * takes precedence.
721      *
722      * @param showBackdrop Whether to show a background behind the windows during the animation.
723      * @attr ref android.R.styleable#Animation_showBackdrop
724      */
setShowBackdrop(boolean showBackdrop)725     public void setShowBackdrop(boolean showBackdrop) {
726         mShowBackdrop = showBackdrop;
727     }
728 
729     /**
730      * Set the color to use for the backdrop shown behind the animating windows.
731      *
732      * Will only show the backdrop if showBackdrop was set to true.
733      * See {@link #setShowBackdrop(boolean)}.
734      *
735      * @param backdropColor The backdrop color. If 0, the backdrop color will not apply.
736      * @attr ref android.R.styleable#Animation_backdropColor
737      */
setBackdropColor(@olorInt int backdropColor)738     public void setBackdropColor(@ColorInt int backdropColor) {
739         mBackdropColor = backdropColor;
740     }
741 
742     /**
743      * Gets the acceleration curve type for this animation.
744      *
745      * @return the {@link Interpolator} associated to this animation
746      * @attr ref android.R.styleable#Animation_interpolator
747      */
getInterpolator()748     public Interpolator getInterpolator() {
749         return mInterpolator;
750     }
751 
752     /**
753      * When this animation should start. If the animation has not startet yet,
754      * this method might return {@link #START_ON_FIRST_FRAME}.
755      *
756      * @return the time in milliseconds when the animation should start or
757      *         {@link #START_ON_FIRST_FRAME}
758      */
getStartTime()759     public long getStartTime() {
760         return mStartTime;
761     }
762 
763     /**
764      * How long this animation should last
765      *
766      * @return the duration in milliseconds of the animation
767      * @attr ref android.R.styleable#Animation_duration
768      */
getDuration()769     public long getDuration() {
770         return mDuration;
771     }
772 
773     /**
774      * When this animation should start, relative to StartTime
775      *
776      * @return the start offset in milliseconds
777      * @attr ref android.R.styleable#Animation_startOffset
778      */
getStartOffset()779     public long getStartOffset() {
780         return mStartOffset;
781     }
782 
783     /**
784      * Defines what this animation should do when it reaches the end.
785      *
786      * @return either one of {@link #REVERSE} or {@link #RESTART}
787      * @attr ref android.R.styleable#Animation_repeatMode
788      */
getRepeatMode()789     public int getRepeatMode() {
790         return mRepeatMode;
791     }
792 
793     /**
794      * Defines how many times the animation should repeat. The default value
795      * is 0.
796      *
797      * @return the number of times the animation should repeat, or {@link #INFINITE}
798      * @attr ref android.R.styleable#Animation_repeatCount
799      */
getRepeatCount()800     public int getRepeatCount() {
801         return mRepeatCount;
802     }
803 
804     /**
805      * If fillBefore is true, this animation will apply its transformation
806      * before the start time of the animation. If fillBefore is false and
807      * {@link #isFillEnabled() fillEnabled} is true, the transformation will not be applied until
808      * the start time of the animation.
809      *
810      * @return true if the animation applies its transformation before it starts
811      * @attr ref android.R.styleable#Animation_fillBefore
812      */
getFillBefore()813     public boolean getFillBefore() {
814         return mFillBefore;
815     }
816 
817     /**
818      * If fillAfter is true, this animation will apply its transformation
819      * after the end time of the animation.
820      *
821      * @return true if the animation applies its transformation after it ends
822      * @attr ref android.R.styleable#Animation_fillAfter
823      */
getFillAfter()824     public boolean getFillAfter() {
825         return mFillAfter;
826     }
827 
828     /**
829      * Returns the Z ordering mode to use while running the animation as
830      * previously set by {@link #setZAdjustment}.
831      *
832      * @return Returns one of {@link #ZORDER_NORMAL},
833      * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}.
834      * @attr ref android.R.styleable#Animation_zAdjustment
835      */
getZAdjustment()836     public int getZAdjustment() {
837         return mZAdjustment;
838     }
839 
840     /**
841      * Returns the background color behind the animation.
842      *
843      * @deprecated None of window animations are running with background color.
844      * @see #getBackdropColor() for an alternative.
845      */
846     @Deprecated
847     @ColorInt
getBackgroundColor()848     public int getBackgroundColor() {
849         return 0;
850     }
851 
852     /**
853      * Return value of {@link #setDetachWallpaper(boolean)}.
854      * @attr ref android.R.styleable#Animation_detachWallpaper
855      *
856      * @deprecated All window animations are running with detached wallpaper.
857      */
858     @Deprecated
getDetachWallpaper()859     public boolean getDetachWallpaper() {
860         return true;
861     }
862 
863     /**
864      * @return If run as a window animation, returns whether the wallpaper will be shown behind
865      *         during the animation.
866      * @attr ref android.R.styleable#Animation_showWallpaper
867      * @hide
868      */
getShowWallpaper()869     public boolean getShowWallpaper() {
870         return mShowWallpaper;
871     }
872 
873     /**
874      * @return if a window animation should have rounded corners or not.
875      *
876      * @attr ref android.R.styleable#Animation_hasRoundedCorners
877      * @hide
878      */
hasRoundedCorners()879     public boolean hasRoundedCorners() {
880         return mHasRoundedCorners;
881     }
882 
883     /**
884      * @return if a window animation has outsets applied to it.
885      *
886      * @hide
887      */
hasExtension()888     public boolean hasExtension() {
889         return false;
890     }
891 
892     /**
893      * If showBackdrop is {@code true} and this animation is applied on a window, then the windows
894      * in the animation will animate with the background associated with this window behind them.
895      *
896      * If no backdrop color is explicitly set, the backdrop's color comes from the
897      * {@link android.R.styleable#Theme_colorBackground} that is applied to this window
898      * through its theme.
899      *
900      * If multiple animating windows have showBackdrop set to {@code true} during an animation,
901      * the top most window with showBackdrop set to {@code true} and a valid background color
902      * takes precedence.
903      *
904      * @return if a backdrop should be shown behind the animating windows.
905      * @attr ref android.R.styleable#Animation_showBackdrop
906      */
getShowBackdrop()907     public boolean getShowBackdrop() {
908         return mShowBackdrop;
909     }
910 
911     /**
912      * Returns the background color to show behind the animating windows.
913      *
914      * Will only show the background if showBackdrop was set to true.
915      * See {@link #setShowBackdrop(boolean)}.
916      *
917      * @return The backdrop color. If 0, the backdrop color will not apply.
918      * @attr ref android.R.styleable#Animation_backdropColor
919      */
920     @ColorInt
getBackdropColor()921     public int getBackdropColor() {
922         return mBackdropColor;
923     }
924 
925     /**
926      * <p>Indicates whether or not this animation will affect the transformation
927      * matrix. For instance, a fade animation will not affect the matrix whereas
928      * a scale animation will.</p>
929      *
930      * @return true if this animation will change the transformation matrix
931      */
willChangeTransformationMatrix()932     public boolean willChangeTransformationMatrix() {
933         // assume we will change the matrix
934         return true;
935     }
936 
937     /**
938      * <p>Indicates whether or not this animation will affect the bounds of the
939      * animated view. For instance, a fade animation will not affect the bounds
940      * whereas a 200% scale animation will.</p>
941      *
942      * @return true if this animation will change the view's bounds
943      */
willChangeBounds()944     public boolean willChangeBounds() {
945         // assume we will change the bounds
946         return true;
947     }
948 
hasAnimationListener()949     private boolean hasAnimationListener() {
950         return mListener != null;
951     }
952 
953     /**
954      * <p>Binds an animation listener to this animation. The animation listener
955      * is notified of animation events such as the end of the animation or the
956      * repetition of the animation.</p>
957      *
958      * @param listener the animation listener to be notified
959      */
setAnimationListener(AnimationListener listener)960     public void setAnimationListener(AnimationListener listener) {
961         mListener = listener;
962     }
963 
964     /**
965      * Gurantees that this animation has an interpolator. Will use
966      * a AccelerateDecelerateInterpolator is nothing else was specified.
967      */
ensureInterpolator()968     protected void ensureInterpolator() {
969         if (mInterpolator == null) {
970             mInterpolator = new AccelerateDecelerateInterpolator();
971         }
972     }
973 
974     /**
975      * Compute a hint at how long the entire animation may last, in milliseconds.
976      * Animations can be written to cause themselves to run for a different
977      * duration than what is computed here, but generally this should be
978      * accurate.
979      */
computeDurationHint()980     public long computeDurationHint() {
981         return (getStartOffset() + getDuration()) * (getRepeatCount() + 1);
982     }
983 
984     /**
985      * Gets the transformation to apply a specific point in time. Implementations of this method
986      * should always be kept in sync with getTransformation.
987      *
988      * @param normalizedTime time between 0 and 1 where 0 is the start of the animation and 1 the
989      *                       end.
990      * @param outTransformation A transformation object that is provided by the
991      *        caller and will be filled in by the animation.
992      * @hide
993      */
getTransformationAt(float normalizedTime, Transformation outTransformation)994     public void getTransformationAt(float normalizedTime, Transformation outTransformation) {
995         final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
996         applyTransformation(interpolatedTime, outTransformation);
997     }
998 
999     /**
1000      * Gets the transformation to apply at a specified point in time. Implementations of this
1001      * method should always replace the specified Transformation or document they are doing
1002      * otherwise.
1003      *
1004      * @param currentTime Where we are in the animation. This is wall clock time.
1005      * @param outTransformation A transformation object that is provided by the
1006      *        caller and will be filled in by the animation.
1007      * @return True if the animation is still running
1008      */
getTransformation(long currentTime, Transformation outTransformation)1009     public boolean getTransformation(long currentTime, Transformation outTransformation) {
1010         if (mStartTime == -1) {
1011             mStartTime = currentTime;
1012         }
1013 
1014         final long startOffset = getStartOffset();
1015         final long duration = mDuration;
1016         float normalizedTime;
1017         if (duration != 0) {
1018             normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
1019                     (float) duration;
1020         } else {
1021             // time is a step-change with a zero duration
1022             normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
1023         }
1024 
1025         final boolean expired = normalizedTime >= 1.0f || isCanceled();
1026         mMore = !expired;
1027 
1028         if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
1029 
1030         if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
1031             if (!mStarted) {
1032                 fireAnimationStart();
1033                 mStarted = true;
1034                 if (NoImagePreloadHolder.USE_CLOSEGUARD) {
1035                     guard.open("cancel or detach or getTransformation");
1036                 }
1037             }
1038 
1039             if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
1040 
1041             if (mCycleFlip) {
1042                 normalizedTime = 1.0f - normalizedTime;
1043             }
1044 
1045             getTransformationAt(normalizedTime, outTransformation);
1046         }
1047 
1048         if (expired) {
1049             if (mRepeatCount == mRepeated || isCanceled()) {
1050                 if (!mEnded) {
1051                     mEnded = true;
1052                     guard.close();
1053                     fireAnimationEnd();
1054                 }
1055             } else {
1056                 if (mRepeatCount > 0) {
1057                     mRepeated++;
1058                 }
1059 
1060                 if (mRepeatMode == REVERSE) {
1061                     mCycleFlip = !mCycleFlip;
1062                 }
1063 
1064                 mStartTime = -1;
1065                 mMore = true;
1066 
1067                 fireAnimationRepeat();
1068             }
1069         }
1070 
1071         if (!mMore && mOneMoreTime) {
1072             mOneMoreTime = false;
1073             return true;
1074         }
1075 
1076         return mMore;
1077     }
1078 
isCanceled()1079     private boolean isCanceled() {
1080         return mStartTime == Long.MIN_VALUE;
1081     }
1082 
fireAnimationStart()1083     private void fireAnimationStart() {
1084         if (hasAnimationListener()) {
1085             if (mListenerHandler == null) dispatchAnimationStart();
1086             else mListenerHandler.postAtFrontOfQueue(mOnStart);
1087         }
1088     }
1089 
fireAnimationRepeat()1090     private void fireAnimationRepeat() {
1091         if (hasAnimationListener()) {
1092             if (mListenerHandler == null) dispatchAnimationRepeat();
1093             else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
1094         }
1095     }
1096 
fireAnimationEnd()1097     private void fireAnimationEnd() {
1098         if (hasAnimationListener()) {
1099             if (mListenerHandler == null) dispatchAnimationEnd();
1100             else mListenerHandler.postAtFrontOfQueue(mOnEnd);
1101         }
1102     }
1103 
dispatchAnimationStart()1104     void dispatchAnimationStart() {
1105         if (mListener != null) {
1106             mListener.onAnimationStart(this);
1107         }
1108     }
1109 
dispatchAnimationRepeat()1110     void dispatchAnimationRepeat() {
1111         if (mListener != null) {
1112             mListener.onAnimationRepeat(this);
1113         }
1114     }
1115 
dispatchAnimationEnd()1116     void dispatchAnimationEnd() {
1117         if (mListener != null) {
1118             mListener.onAnimationEnd(this);
1119         }
1120     }
1121 
1122     /**
1123      * Gets the transformation to apply at a specified point in time. Implementations of this
1124      * method should always replace the specified Transformation or document they are doing
1125      * otherwise.
1126      *
1127      * @param currentTime Where we are in the animation. This is wall clock time.
1128      * @param outTransformation A transformation object that is provided by the
1129      *        caller and will be filled in by the animation.
1130      * @param scale Scaling factor to apply to any inputs to the transform operation, such
1131      *        pivot points being rotated or scaled around.
1132      * @return True if the animation is still running
1133      */
getTransformation(long currentTime, Transformation outTransformation, float scale)1134     public boolean getTransformation(long currentTime, Transformation outTransformation,
1135             float scale) {
1136         mScaleFactor = scale;
1137         return getTransformation(currentTime, outTransformation);
1138     }
1139 
1140     /**
1141      * <p>Indicates whether this animation has started or not.</p>
1142      *
1143      * @return true if the animation has started, false otherwise
1144      */
hasStarted()1145     public boolean hasStarted() {
1146         return mStarted;
1147     }
1148 
1149     /**
1150      * <p>Indicates whether this animation has ended or not.</p>
1151      *
1152      * @return true if the animation has ended, false otherwise
1153      */
hasEnded()1154     public boolean hasEnded() {
1155         return mEnded;
1156     }
1157 
1158     /**
1159      * Helper for getTransformation. Subclasses should implement this to apply
1160      * their transforms given an interpolation value.  Implementations of this
1161      * method should always replace the specified Transformation or document
1162      * they are doing otherwise.
1163      *
1164      * @param interpolatedTime The value of the normalized time (0.0 to 1.0)
1165      *        after it has been run through the interpolation function.
1166      * @param t The Transformation object to fill in with the current
1167      *        transforms.
1168      */
applyTransformation(float interpolatedTime, Transformation t)1169     protected void applyTransformation(float interpolatedTime, Transformation t) {
1170     }
1171 
1172     /**
1173      * Convert the information in the description of a size to an actual
1174      * dimension
1175      *
1176      * @param type One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
1177      *             Animation.RELATIVE_TO_PARENT.
1178      * @param value The dimension associated with the type parameter
1179      * @param size The size of the object being animated
1180      * @param parentSize The size of the parent of the object being animated
1181      * @return The dimension to use for the animation
1182      */
resolveSize(int type, float value, int size, int parentSize)1183     protected float resolveSize(int type, float value, int size, int parentSize) {
1184         switch (type) {
1185             case ABSOLUTE:
1186                 return value;
1187             case RELATIVE_TO_SELF:
1188                 return size * value;
1189             case RELATIVE_TO_PARENT:
1190                 return parentSize * value;
1191             default:
1192                 return value;
1193         }
1194     }
1195 
1196     /**
1197      * @param left
1198      * @param top
1199      * @param right
1200      * @param bottom
1201      * @param invalidate
1202      * @param transformation
1203      *
1204      * @hide
1205      */
1206     @UnsupportedAppUsage
getInvalidateRegion(int left, int top, int right, int bottom, RectF invalidate, Transformation transformation)1207     public void getInvalidateRegion(int left, int top, int right, int bottom,
1208             RectF invalidate, Transformation transformation) {
1209 
1210         final RectF tempRegion = mRegion;
1211         final RectF previousRegion = mPreviousRegion;
1212 
1213         invalidate.set(left, top, right, bottom);
1214         transformation.getMatrix().mapRect(invalidate);
1215         // Enlarge the invalidate region to account for rounding errors
1216         invalidate.inset(-1.0f, -1.0f);
1217         tempRegion.set(invalidate);
1218         invalidate.union(previousRegion);
1219 
1220         previousRegion.set(tempRegion);
1221 
1222         final Transformation tempTransformation = mTransformation;
1223         final Transformation previousTransformation = mPreviousTransformation;
1224 
1225         tempTransformation.set(transformation);
1226         transformation.set(previousTransformation);
1227         previousTransformation.set(tempTransformation);
1228     }
1229 
1230     /**
1231      * @param left
1232      * @param top
1233      * @param right
1234      * @param bottom
1235      *
1236      * @hide
1237      */
1238     @UnsupportedAppUsage
initializeInvalidateRegion(int left, int top, int right, int bottom)1239     public void initializeInvalidateRegion(int left, int top, int right, int bottom) {
1240         final RectF region = mPreviousRegion;
1241         region.set(left, top, right, bottom);
1242         // Enlarge the invalidate region to account for rounding errors
1243         region.inset(-1.0f, -1.0f);
1244         if (mFillBefore) {
1245             final Transformation previousTransformation = mPreviousTransformation;
1246             applyTransformation(mInterpolator.getInterpolation(0.0f), previousTransformation);
1247         }
1248     }
1249 
finalize()1250     protected void finalize() throws Throwable {
1251         try {
1252             if (guard != null) {
1253                 guard.warnIfOpen();
1254             }
1255         } finally {
1256             super.finalize();
1257         }
1258     }
1259 
1260     /**
1261      * Return true if this animation changes the view's alpha property.
1262      *
1263      * @hide
1264      */
hasAlpha()1265     public boolean hasAlpha() {
1266         return false;
1267     }
1268 
1269     /**
1270      * Utility class to parse a string description of a size.
1271      */
1272     protected static class Description {
1273         /**
1274          * One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
1275          * Animation.RELATIVE_TO_PARENT.
1276          */
1277         public int type;
1278 
1279         /**
1280          * The absolute or relative dimension for this Description.
1281          */
1282         public float value;
1283 
1284         /**
1285          * Size descriptions can appear in four forms:
1286          * <ol>
1287          * <li>An absolute size. This is represented by a number.</li>
1288          * <li>A size relative to the size of the object being animated. This
1289          * is represented by a number followed by "%".</li>
1290          * <li>A size relative to the size of the parent of object being
1291          * animated. This is represented by a number followed by "%p".</li>
1292          * <li>(Starting from API 32) A complex number.</li>
1293          * </ol>
1294          * @param value The typed value to parse
1295          * @return The parsed version of the description
1296          */
parseValue(TypedValue value, Context context)1297         static Description parseValue(TypedValue value, Context context) {
1298             Description d = new Description();
1299             if (value == null) {
1300                 d.type = ABSOLUTE;
1301                 d.value = 0;
1302             } else {
1303                 if (value.type == TypedValue.TYPE_FRACTION) {
1304                     d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) ==
1305                             TypedValue.COMPLEX_UNIT_FRACTION_PARENT ?
1306                                     RELATIVE_TO_PARENT : RELATIVE_TO_SELF;
1307                     d.value = TypedValue.complexToFloat(value.data);
1308                     return d;
1309                 } else if (value.type == TypedValue.TYPE_FLOAT) {
1310                     d.type = ABSOLUTE;
1311                     d.value = value.getFloat();
1312                     return d;
1313                 } else if (value.type >= TypedValue.TYPE_FIRST_INT &&
1314                         value.type <= TypedValue.TYPE_LAST_INT) {
1315                     d.type = ABSOLUTE;
1316                     d.value = value.data;
1317                     return d;
1318                 } else if (value.type == TypedValue.TYPE_DIMENSION) {
1319                     d.type = ABSOLUTE;
1320                     d.value = TypedValue.complexToDimension(value.data,
1321                             context.getResources().getDisplayMetrics());
1322                     return d;
1323                 }
1324             }
1325 
1326             d.type = ABSOLUTE;
1327             d.value = 0.0f;
1328 
1329             return d;
1330         }
1331     }
1332 
1333     /**
1334      * <p>An animation listener receives notifications from an animation.
1335      * Notifications indicate animation related events, such as the end or the
1336      * repetition of the animation.</p>
1337      */
1338     public static interface AnimationListener {
1339         /**
1340          * <p>Notifies the start of the animation.</p>
1341          *
1342          * @param animation The started animation.
1343          */
1344         void onAnimationStart(Animation animation);
1345 
1346         /**
1347          * <p>Notifies the end of the animation. This callback is not invoked
1348          * for animations with repeat count set to INFINITE.</p>
1349          *
1350          * @param animation The animation which reached its end.
1351          */
1352         void onAnimationEnd(Animation animation);
1353 
1354         /**
1355          * <p>Notifies the repetition of the animation.</p>
1356          *
1357          * @param animation The animation which was repeated.
1358          */
1359         void onAnimationRepeat(Animation animation);
1360     }
1361 }
1362