Home | History | Annotate | Download | only in animation
      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      */
    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      */
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    749     public int getZAdjustment() {
    750         return mZAdjustment;
    751     }
    752 
    753     /**
    754      * Returns the background color behind the animation.
    755      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    904     private void fireAnimationStart() {
    905         if (mListener != null) {
    906             if (mListenerHandler == null) mListener.onAnimationStart(this);
    907             else mListenerHandler.postAtFrontOfQueue(mOnStart);
    908         }
    909     }
    910 
    911     private void fireAnimationRepeat() {
    912         if (mListener != null) {
    913             if (mListenerHandler == null) mListener.onAnimationRepeat(this);
    914             else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
    915         }
    916     }
    917 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
   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      */
   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 
   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      */
   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          */
   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