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