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