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