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