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