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