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