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