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