Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (C) 2010 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.animation;
     18 
     19 import java.util.ArrayList;
     20 
     21 /**
     22  * This is the superclass for classes which provide basic support for animations which can be
     23  * started, ended, and have <code>AnimatorListeners</code> added to them.
     24  */
     25 public abstract class Animator implements Cloneable {
     26 
     27     /**
     28      * The set of listeners to be sent events through the life of an animation.
     29      */
     30     ArrayList<AnimatorListener> mListeners = null;
     31 
     32     /**
     33      * The set of listeners to be sent pause/resume events through the life
     34      * of an animation.
     35      */
     36     ArrayList<AnimatorPauseListener> mPauseListeners = null;
     37 
     38     /**
     39      * Whether this animator is currently in a paused state.
     40      */
     41     boolean mPaused = false;
     42 
     43     /**
     44      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
     45      * running after that delay elapses. A non-delayed animation will have its initial
     46      * value(s) set immediately, followed by calls to
     47      * {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
     48      *
     49      * <p>The animation started by calling this method will be run on the thread that called
     50      * this method. This thread should have a Looper on it (a runtime exception will be thrown if
     51      * this is not the case). Also, if the animation will animate
     52      * properties of objects in the view hierarchy, then the calling thread should be the UI
     53      * thread for that view hierarchy.</p>
     54      *
     55      */
     56     public void start() {
     57     }
     58 
     59     /**
     60      * Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to
     61      * stop in its tracks, sending an
     62      * {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to
     63      * its listeners, followed by an
     64      * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message.
     65      *
     66      * <p>This method must be called on the thread that is running the animation.</p>
     67      */
     68     public void cancel() {
     69     }
     70 
     71     /**
     72      * Ends the animation. This causes the animation to assign the end value of the property being
     73      * animated, then calling the
     74      * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on
     75      * its listeners.
     76      *
     77      * <p>This method must be called on the thread that is running the animation.</p>
     78      */
     79     public void end() {
     80     }
     81 
     82     /**
     83      * Pauses a running animation. This method should only be called on the same thread on
     84      * which the animation was started. If the animation has not yet been {@link
     85      * #isStarted() started} or has since ended, then the call is ignored. Paused
     86      * animations can be resumed by calling {@link #resume()}.
     87      *
     88      * @see #resume()
     89      * @see #isPaused()
     90      * @see AnimatorPauseListener
     91      */
     92     public void pause() {
     93         if (isStarted() && !mPaused) {
     94             mPaused = true;
     95             if (mPauseListeners != null) {
     96                 ArrayList<AnimatorPauseListener> tmpListeners =
     97                         (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
     98                 int numListeners = tmpListeners.size();
     99                 for (int i = 0; i < numListeners; ++i) {
    100                     tmpListeners.get(i).onAnimationPause(this);
    101                 }
    102             }
    103         }
    104     }
    105 
    106     /**
    107      * Resumes a paused animation, causing the animator to pick up where it left off
    108      * when it was paused. This method should only be called on the same thread on
    109      * which the animation was started. Calls to resume() on an animator that is
    110      * not currently paused will be ignored.
    111      *
    112      * @see #pause()
    113      * @see #isPaused()
    114      * @see AnimatorPauseListener
    115      */
    116     public void resume() {
    117         if (mPaused) {
    118             mPaused = false;
    119             if (mPauseListeners != null) {
    120                 ArrayList<AnimatorPauseListener> tmpListeners =
    121                         (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
    122                 int numListeners = tmpListeners.size();
    123                 for (int i = 0; i < numListeners; ++i) {
    124                     tmpListeners.get(i).onAnimationResume(this);
    125                 }
    126             }
    127         }
    128     }
    129 
    130     /**
    131      * Returns whether this animator is currently in a paused state.
    132      *
    133      * @return True if the animator is currently paused, false otherwise.
    134      *
    135      * @see #pause()
    136      * @see #resume()
    137      */
    138     public boolean isPaused() {
    139         return mPaused;
    140     }
    141 
    142     /**
    143      * The amount of time, in milliseconds, to delay processing the animation
    144      * after {@link #start()} is called.
    145      *
    146      * @return the number of milliseconds to delay running the animation
    147      */
    148     public abstract long getStartDelay();
    149 
    150     /**
    151      * The amount of time, in milliseconds, to delay processing the animation
    152      * after {@link #start()} is called.
    153 
    154      * @param startDelay The amount of the delay, in milliseconds
    155      */
    156     public abstract void setStartDelay(long startDelay);
    157 
    158     /**
    159      * Sets the duration of the animation.
    160      *
    161      * @param duration The length of the animation, in milliseconds.
    162      */
    163     public abstract Animator setDuration(long duration);
    164 
    165     /**
    166      * Gets the duration of the animation.
    167      *
    168      * @return The length of the animation, in milliseconds.
    169      */
    170     public abstract long getDuration();
    171 
    172     /**
    173      * The time interpolator used in calculating the elapsed fraction of the
    174      * animation. The interpolator determines whether the animation runs with
    175      * linear or non-linear motion, such as acceleration and deceleration. The
    176      * default value is {@link android.view.animation.AccelerateDecelerateInterpolator}.
    177      *
    178      * @param value the interpolator to be used by this animation
    179      */
    180     public abstract void setInterpolator(TimeInterpolator value);
    181 
    182     /**
    183      * Returns the timing interpolator that this animation uses.
    184      *
    185      * @return The timing interpolator for this animation.
    186      */
    187     public TimeInterpolator getInterpolator() {
    188         return null;
    189     }
    190 
    191     /**
    192      * Returns whether this Animator is currently running (having been started and gone past any
    193      * initial startDelay period and not yet ended).
    194      *
    195      * @return Whether the Animator is running.
    196      */
    197     public abstract boolean isRunning();
    198 
    199     /**
    200      * Returns whether this Animator has been started and not yet ended. This state is a superset
    201      * of the state of {@link #isRunning()}, because an Animator with a nonzero
    202      * {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during the
    203      * delay phase, whereas {@link #isRunning()} will return true only after the delay phase
    204      * is complete.
    205      *
    206      * @return Whether the Animator has been started and not yet ended.
    207      */
    208     public boolean isStarted() {
    209         // Default method returns value for isRunning(). Subclasses should override to return a
    210         // real value.
    211         return isRunning();
    212     }
    213 
    214     /**
    215      * Adds a listener to the set of listeners that are sent events through the life of an
    216      * animation, such as start, repeat, and end.
    217      *
    218      * @param listener the listener to be added to the current set of listeners for this animation.
    219      */
    220     public void addListener(AnimatorListener listener) {
    221         if (mListeners == null) {
    222             mListeners = new ArrayList<AnimatorListener>();
    223         }
    224         mListeners.add(listener);
    225     }
    226 
    227     /**
    228      * Removes a listener from the set listening to this animation.
    229      *
    230      * @param listener the listener to be removed from the current set of listeners for this
    231      *                 animation.
    232      */
    233     public void removeListener(AnimatorListener listener) {
    234         if (mListeners == null) {
    235             return;
    236         }
    237         mListeners.remove(listener);
    238         if (mListeners.size() == 0) {
    239             mListeners = null;
    240         }
    241     }
    242 
    243     /**
    244      * Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently
    245      * listening for events on this <code>Animator</code> object.
    246      *
    247      * @return ArrayList<AnimatorListener> The set of listeners.
    248      */
    249     public ArrayList<AnimatorListener> getListeners() {
    250         return mListeners;
    251     }
    252 
    253     /**
    254      * Adds a pause listener to this animator.
    255      *
    256      * @param listener the listener to be added to the current set of pause listeners
    257      * for this animation.
    258      */
    259     public void addPauseListener(AnimatorPauseListener listener) {
    260         if (mPauseListeners == null) {
    261             mPauseListeners = new ArrayList<AnimatorPauseListener>();
    262         }
    263         mPauseListeners.add(listener);
    264     }
    265 
    266     /**
    267      * Removes a pause listener from the set listening to this animation.
    268      *
    269      * @param listener the listener to be removed from the current set of pause
    270      * listeners for this animation.
    271      */
    272     public void removePauseListener(AnimatorPauseListener listener) {
    273         if (mPauseListeners == null) {
    274             return;
    275         }
    276         mPauseListeners.remove(listener);
    277         if (mPauseListeners.size() == 0) {
    278             mPauseListeners = null;
    279         }
    280     }
    281 
    282     /**
    283      * Removes all {@link #addListener(android.animation.Animator.AnimatorListener) listeners}
    284      * and {@link #addPauseListener(android.animation.Animator.AnimatorPauseListener)
    285      * pauseListeners} from this object.
    286      */
    287     public void removeAllListeners() {
    288         if (mListeners != null) {
    289             mListeners.clear();
    290             mListeners = null;
    291         }
    292         if (mPauseListeners != null) {
    293             mPauseListeners.clear();
    294             mPauseListeners = null;
    295         }
    296     }
    297 
    298     @Override
    299     public Animator clone() {
    300         try {
    301             final Animator anim = (Animator) super.clone();
    302             if (mListeners != null) {
    303                 ArrayList<AnimatorListener> oldListeners = mListeners;
    304                 anim.mListeners = new ArrayList<AnimatorListener>();
    305                 int numListeners = oldListeners.size();
    306                 for (int i = 0; i < numListeners; ++i) {
    307                     anim.mListeners.add(oldListeners.get(i));
    308                 }
    309             }
    310             if (mPauseListeners != null) {
    311                 ArrayList<AnimatorPauseListener> oldListeners = mPauseListeners;
    312                 anim.mPauseListeners = new ArrayList<AnimatorPauseListener>();
    313                 int numListeners = oldListeners.size();
    314                 for (int i = 0; i < numListeners; ++i) {
    315                     anim.mPauseListeners.add(oldListeners.get(i));
    316                 }
    317             }
    318             return anim;
    319         } catch (CloneNotSupportedException e) {
    320            throw new AssertionError();
    321         }
    322     }
    323 
    324     /**
    325      * This method tells the object to use appropriate information to extract
    326      * starting values for the animation. For example, a AnimatorSet object will pass
    327      * this call to its child objects to tell them to set up the values. A
    328      * ObjectAnimator object will use the information it has about its target object
    329      * and PropertyValuesHolder objects to get the start values for its properties.
    330      * A ValueAnimator object will ignore the request since it does not have enough
    331      * information (such as a target object) to gather these values.
    332      */
    333     public void setupStartValues() {
    334     }
    335 
    336     /**
    337      * This method tells the object to use appropriate information to extract
    338      * ending values for the animation. For example, a AnimatorSet object will pass
    339      * this call to its child objects to tell them to set up the values. A
    340      * ObjectAnimator object will use the information it has about its target object
    341      * and PropertyValuesHolder objects to get the start values for its properties.
    342      * A ValueAnimator object will ignore the request since it does not have enough
    343      * information (such as a target object) to gather these values.
    344      */
    345     public void setupEndValues() {
    346     }
    347 
    348     /**
    349      * Sets the target object whose property will be animated by this animation. Not all subclasses
    350      * operate on target objects (for example, {@link ValueAnimator}, but this method
    351      * is on the superclass for the convenience of dealing generically with those subclasses
    352      * that do handle targets.
    353      *
    354      * @param target The object being animated
    355      */
    356     public void setTarget(Object target) {
    357     }
    358 
    359     // Hide reverse() and canReverse() for now since reverse() only work for simple
    360     // cases, like we don't support sequential, neither startDelay.
    361     // TODO: make reverse() works for all the Animators.
    362     /**
    363      * @hide
    364      */
    365     public boolean canReverse() {
    366         return false;
    367     }
    368 
    369     /**
    370      * @hide
    371      */
    372     public void reverse() {
    373         throw new IllegalStateException("Reverse is not supported");
    374     }
    375 
    376     /**
    377      * <p>An animation listener receives notifications from an animation.
    378      * Notifications indicate animation related events, such as the end or the
    379      * repetition of the animation.</p>
    380      */
    381     public static interface AnimatorListener {
    382         /**
    383          * <p>Notifies the start of the animation.</p>
    384          *
    385          * @param animation The started animation.
    386          */
    387         void onAnimationStart(Animator animation);
    388 
    389         /**
    390          * <p>Notifies the end of the animation. This callback is not invoked
    391          * for animations with repeat count set to INFINITE.</p>
    392          *
    393          * @param animation The animation which reached its end.
    394          */
    395         void onAnimationEnd(Animator animation);
    396 
    397         /**
    398          * <p>Notifies the cancellation of the animation. This callback is not invoked
    399          * for animations with repeat count set to INFINITE.</p>
    400          *
    401          * @param animation The animation which was canceled.
    402          */
    403         void onAnimationCancel(Animator animation);
    404 
    405         /**
    406          * <p>Notifies the repetition of the animation.</p>
    407          *
    408          * @param animation The animation which was repeated.
    409          */
    410         void onAnimationRepeat(Animator animation);
    411     }
    412 
    413     /**
    414      * A pause listener receives notifications from an animation when the
    415      * animation is {@link #pause() paused} or {@link #resume() resumed}.
    416      *
    417      * @see #addPauseListener(AnimatorPauseListener)
    418      */
    419     public static interface AnimatorPauseListener {
    420         /**
    421          * <p>Notifies that the animation was paused.</p>
    422          *
    423          * @param animation The animaton being paused.
    424          * @see #pause()
    425          */
    426         void onAnimationPause(Animator animation);
    427 
    428         /**
    429          * <p>Notifies that the animation was resumed, after being
    430          * previously paused.</p>
    431          *
    432          * @param animation The animation being resumed.
    433          * @see #resume()
    434          */
    435         void onAnimationResume(Animator animation);
    436     }
    437 
    438     /**
    439      * <p>Whether or not the Animator is allowed to run asynchronously off of
    440      * the UI thread. This is a hint that informs the Animator that it is
    441      * OK to run the animation off-thread, however the Animator may decide
    442      * that it must run the animation on the UI thread anyway.
    443      *
    444      * <p>Regardless of whether or not the animation runs asynchronously, all
    445      * listener callbacks will be called on the UI thread.</p>
    446      *
    447      * <p>To be able to use this hint the following must be true:</p>
    448      * <ol>
    449      * <li>The animator is immutable while {@link #isStarted()} is true. Requests
    450      *    to change duration, delay, etc... may be ignored.</li>
    451      * <li>Lifecycle callback events may be asynchronous. Events such as
    452      *    {@link Animator.AnimatorListener#onAnimationEnd(Animator)} or
    453      *    {@link Animator.AnimatorListener#onAnimationRepeat(Animator)} may end up delayed
    454      *    as they must be posted back to the UI thread, and any actions performed
    455      *    by those callbacks (such as starting new animations) will not happen
    456      *    in the same frame.</li>
    457      * <li>State change requests ({@link #cancel()}, {@link #end()}, {@link #reverse()}, etc...)
    458      *    may be asynchronous. It is guaranteed that all state changes that are
    459      *    performed on the UI thread in the same frame will be applied as a single
    460      *    atomic update, however that frame may be the current frame,
    461      *    the next frame, or some future frame. This will also impact the observed
    462      *    state of the Animator. For example, {@link #isStarted()} may still return true
    463      *    after a call to {@link #end()}. Using the lifecycle callbacks is preferred over
    464      *    queries to {@link #isStarted()}, {@link #isRunning()}, and {@link #isPaused()}
    465      *    for this reason.</li>
    466      * </ol>
    467      * @hide
    468      */
    469     public void setAllowRunningAsynchronously(boolean mayRunAsync) {
    470         // It is up to subclasses to support this, if they can.
    471     }
    472 }
    473