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