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