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