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 import java.util.Collection;
     21 import java.util.HashMap;
     22 import java.util.List;
     23 
     24 /**
     25  * This class plays a set of {@link Animator} objects in the specified order. Animations
     26  * can be set up to play together, in sequence, or after a specified delay.
     27  *
     28  * <p>There are two different approaches to adding animations to a <code>AnimatorSet</code>:
     29  * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or
     30  * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add
     31  * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be
     32  * used in conjunction with methods in the {@link AnimatorSet.Builder Builder}
     33  * class to add animations
     34  * one by one.</p>
     35  *
     36  * <p>It is possible to set up a <code>AnimatorSet</code> with circular dependencies between
     37  * its animations. For example, an animation a1 could be set up to start before animation a2, a2
     38  * before a3, and a3 before a1. The results of this configuration are undefined, but will typically
     39  * result in none of the affected animations being played. Because of this (and because
     40  * circular dependencies do not make logical sense anyway), circular dependencies
     41  * should be avoided, and the dependency flow of animations should only be in one direction.
     42  *
     43  * <div class="special reference">
     44  * <h3>Developer Guides</h3>
     45  * <p>For more information about animating with {@code AnimatorSet}, read the
     46  * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#choreography">Property
     47  * Animation</a> developer guide.</p>
     48  * </div>
     49  */
     50 public final class AnimatorSet extends Animator {
     51 
     52     /**
     53      * Internal variables
     54      * NOTE: This object implements the clone() method, making a deep copy of any referenced
     55      * objects. As other non-trivial fields are added to this class, make sure to add logic
     56      * to clone() to make deep copies of them.
     57      */
     58 
     59     /**
     60      * Tracks animations currently being played, so that we know what to
     61      * cancel or end when cancel() or end() is called on this AnimatorSet
     62      */
     63     private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>();
     64 
     65     /**
     66      * Contains all nodes, mapped to their respective Animators. When new
     67      * dependency information is added for an Animator, we want to add it
     68      * to a single node representing that Animator, not create a new Node
     69      * if one already exists.
     70      */
     71     private HashMap<Animator, Node> mNodeMap = new HashMap<Animator, Node>();
     72 
     73     /**
     74      * Set of all nodes created for this AnimatorSet. This list is used upon
     75      * starting the set, and the nodes are placed in sorted order into the
     76      * sortedNodes collection.
     77      */
     78     private ArrayList<Node> mNodes = new ArrayList<Node>();
     79 
     80     /**
     81      * The sorted list of nodes. This is the order in which the animations will
     82      * be played. The details about when exactly they will be played depend
     83      * on the dependency relationships of the nodes.
     84      */
     85     private ArrayList<Node> mSortedNodes = new ArrayList<Node>();
     86 
     87     /**
     88      * Flag indicating whether the nodes should be sorted prior to playing. This
     89      * flag allows us to cache the previous sorted nodes so that if the sequence
     90      * is replayed with no changes, it does not have to re-sort the nodes again.
     91      */
     92     private boolean mNeedsSort = true;
     93 
     94     private AnimatorSetListener mSetListener = null;
     95 
     96     /**
     97      * Flag indicating that the AnimatorSet has been manually
     98      * terminated (by calling cancel() or end()).
     99      * This flag is used to avoid starting other animations when currently-playing
    100      * child animations of this AnimatorSet end. It also determines whether cancel/end
    101      * notifications are sent out via the normal AnimatorSetListener mechanism.
    102      */
    103     boolean mTerminated = false;
    104 
    105     /**
    106      * Indicates whether an AnimatorSet has been start()'d, whether or
    107      * not there is a nonzero startDelay.
    108      */
    109     private boolean mStarted = false;
    110 
    111     // The amount of time in ms to delay starting the animation after start() is called
    112     private long mStartDelay = 0;
    113 
    114     // Animator used for a nonzero startDelay
    115     private ValueAnimator mDelayAnim = null;
    116 
    117 
    118     // How long the child animations should last in ms. The default value is negative, which
    119     // simply means that there is no duration set on the AnimatorSet. When a real duration is
    120     // set, it is passed along to the child animations.
    121     private long mDuration = -1;
    122 
    123     // Records the interpolator for the set. Null value indicates that no interpolator
    124     // was set on this AnimatorSet, so it should not be passed down to the children.
    125     private TimeInterpolator mInterpolator = null;
    126 
    127     private boolean mReversible = true;
    128     /**
    129      * Sets up this AnimatorSet to play all of the supplied animations at the same time.
    130      * This is equivalent to calling {@link #play(Animator)} with the first animator in the
    131      * set and then {@link Builder#with(Animator)} with each of the other animators. Note that
    132      * an Animator with a {@link Animator#setStartDelay(long) startDelay} will not actually
    133      * start until that delay elapses, which means that if the first animator in the list
    134      * supplied to this constructor has a startDelay, none of the other animators will start
    135      * until that first animator's startDelay has elapsed.
    136      *
    137      * @param items The animations that will be started simultaneously.
    138      */
    139     public void playTogether(Animator... items) {
    140         if (items != null) {
    141             mNeedsSort = true;
    142             Builder builder = play(items[0]);
    143             for (int i = 1; i < items.length; ++i) {
    144                 builder.with(items[i]);
    145             }
    146         }
    147     }
    148 
    149     /**
    150      * Sets up this AnimatorSet to play all of the supplied animations at the same time.
    151      *
    152      * @param items The animations that will be started simultaneously.
    153      */
    154     public void playTogether(Collection<Animator> items) {
    155         if (items != null && items.size() > 0) {
    156             mNeedsSort = true;
    157             Builder builder = null;
    158             for (Animator anim : items) {
    159                 if (builder == null) {
    160                     builder = play(anim);
    161                 } else {
    162                     builder.with(anim);
    163                 }
    164             }
    165         }
    166     }
    167 
    168     /**
    169      * Sets up this AnimatorSet to play each of the supplied animations when the
    170      * previous animation ends.
    171      *
    172      * @param items The animations that will be started one after another.
    173      */
    174     public void playSequentially(Animator... items) {
    175         if (items != null) {
    176             mNeedsSort = true;
    177             if (items.length == 1) {
    178                 play(items[0]);
    179             } else {
    180                 mReversible = false;
    181                 for (int i = 0; i < items.length - 1; ++i) {
    182                     play(items[i]).before(items[i+1]);
    183                 }
    184             }
    185         }
    186     }
    187 
    188     /**
    189      * Sets up this AnimatorSet to play each of the supplied animations when the
    190      * previous animation ends.
    191      *
    192      * @param items The animations that will be started one after another.
    193      */
    194     public void playSequentially(List<Animator> items) {
    195         if (items != null && items.size() > 0) {
    196             mNeedsSort = true;
    197             if (items.size() == 1) {
    198                 play(items.get(0));
    199             } else {
    200                 mReversible = false;
    201                 for (int i = 0; i < items.size() - 1; ++i) {
    202                     play(items.get(i)).before(items.get(i+1));
    203                 }
    204             }
    205         }
    206     }
    207 
    208     /**
    209      * Returns the current list of child Animator objects controlled by this
    210      * AnimatorSet. This is a copy of the internal list; modifications to the returned list
    211      * will not affect the AnimatorSet, although changes to the underlying Animator objects
    212      * will affect those objects being managed by the AnimatorSet.
    213      *
    214      * @return ArrayList<Animator> The list of child animations of this AnimatorSet.
    215      */
    216     public ArrayList<Animator> getChildAnimations() {
    217         ArrayList<Animator> childList = new ArrayList<Animator>();
    218         for (Node node : mNodes) {
    219             childList.add(node.animation);
    220         }
    221         return childList;
    222     }
    223 
    224     /**
    225      * Sets the target object for all current {@link #getChildAnimations() child animations}
    226      * of this AnimatorSet that take targets ({@link ObjectAnimator} and
    227      * AnimatorSet).
    228      *
    229      * @param target The object being animated
    230      */
    231     @Override
    232     public void setTarget(Object target) {
    233         for (Node node : mNodes) {
    234             Animator animation = node.animation;
    235             if (animation instanceof AnimatorSet) {
    236                 ((AnimatorSet)animation).setTarget(target);
    237             } else if (animation instanceof ObjectAnimator) {
    238                 ((ObjectAnimator)animation).setTarget(target);
    239             }
    240         }
    241     }
    242 
    243     /**
    244      * @hide
    245      */
    246     @Override
    247     public int getChangingConfigurations() {
    248         int conf = super.getChangingConfigurations();
    249         final int nodeCount = mNodes.size();
    250         for (int i = 0; i < nodeCount; i ++) {
    251             conf |= mNodes.get(i).animation.getChangingConfigurations();
    252         }
    253         return conf;
    254     }
    255 
    256     /**
    257      * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
    258      * of this AnimatorSet. The default value is null, which means that no interpolator
    259      * is set on this AnimatorSet. Setting the interpolator to any non-null value
    260      * will cause that interpolator to be set on the child animations
    261      * when the set is started.
    262      *
    263      * @param interpolator the interpolator to be used by each child animation of this AnimatorSet
    264      */
    265     @Override
    266     public void setInterpolator(TimeInterpolator interpolator) {
    267         mInterpolator = interpolator;
    268     }
    269 
    270     @Override
    271     public TimeInterpolator getInterpolator() {
    272         return mInterpolator;
    273     }
    274 
    275     /**
    276      * This method creates a <code>Builder</code> object, which is used to
    277      * set up playing constraints. This initial <code>play()</code> method
    278      * tells the <code>Builder</code> the animation that is the dependency for
    279      * the succeeding commands to the <code>Builder</code>. For example,
    280      * calling <code>play(a1).with(a2)</code> sets up the AnimatorSet to play
    281      * <code>a1</code> and <code>a2</code> at the same time,
    282      * <code>play(a1).before(a2)</code> sets up the AnimatorSet to play
    283      * <code>a1</code> first, followed by <code>a2</code>, and
    284      * <code>play(a1).after(a2)</code> sets up the AnimatorSet to play
    285      * <code>a2</code> first, followed by <code>a1</code>.
    286      *
    287      * <p>Note that <code>play()</code> is the only way to tell the
    288      * <code>Builder</code> the animation upon which the dependency is created,
    289      * so successive calls to the various functions in <code>Builder</code>
    290      * will all refer to the initial parameter supplied in <code>play()</code>
    291      * as the dependency of the other animations. For example, calling
    292      * <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code>
    293      * and <code>a3</code> when a1 ends; it does not set up a dependency between
    294      * <code>a2</code> and <code>a3</code>.</p>
    295      *
    296      * @param anim The animation that is the dependency used in later calls to the
    297      * methods in the returned <code>Builder</code> object. A null parameter will result
    298      * in a null <code>Builder</code> return value.
    299      * @return Builder The object that constructs the AnimatorSet based on the dependencies
    300      * outlined in the calls to <code>play</code> and the other methods in the
    301      * <code>Builder</code object.
    302      */
    303     public Builder play(Animator anim) {
    304         if (anim != null) {
    305             mNeedsSort = true;
    306             return new Builder(anim);
    307         }
    308         return null;
    309     }
    310 
    311     /**
    312      * {@inheritDoc}
    313      *
    314      * <p>Note that canceling a <code>AnimatorSet</code> also cancels all of the animations that it
    315      * is responsible for.</p>
    316      */
    317     @SuppressWarnings("unchecked")
    318     @Override
    319     public void cancel() {
    320         mTerminated = true;
    321         if (isStarted()) {
    322             ArrayList<AnimatorListener> tmpListeners = null;
    323             if (mListeners != null) {
    324                 tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
    325                 for (AnimatorListener listener : tmpListeners) {
    326                     listener.onAnimationCancel(this);
    327                 }
    328             }
    329             if (mDelayAnim != null && mDelayAnim.isRunning()) {
    330                 // If we're currently in the startDelay period, just cancel that animator and
    331                 // send out the end event to all listeners
    332                 mDelayAnim.cancel();
    333             } else  if (mSortedNodes.size() > 0) {
    334                 for (Node node : mSortedNodes) {
    335                     node.animation.cancel();
    336                 }
    337             }
    338             if (tmpListeners != null) {
    339                 for (AnimatorListener listener : tmpListeners) {
    340                     listener.onAnimationEnd(this);
    341                 }
    342             }
    343             mStarted = false;
    344         }
    345     }
    346 
    347     /**
    348      * {@inheritDoc}
    349      *
    350      * <p>Note that ending a <code>AnimatorSet</code> also ends all of the animations that it is
    351      * responsible for.</p>
    352      */
    353     @Override
    354     public void end() {
    355         mTerminated = true;
    356         if (isStarted()) {
    357             if (mSortedNodes.size() != mNodes.size()) {
    358                 // hasn't been started yet - sort the nodes now, then end them
    359                 sortNodes();
    360                 for (Node node : mSortedNodes) {
    361                     if (mSetListener == null) {
    362                         mSetListener = new AnimatorSetListener(this);
    363                     }
    364                     node.animation.addListener(mSetListener);
    365                 }
    366             }
    367             if (mDelayAnim != null) {
    368                 mDelayAnim.cancel();
    369             }
    370             if (mSortedNodes.size() > 0) {
    371                 for (Node node : mSortedNodes) {
    372                     node.animation.end();
    373                 }
    374             }
    375             if (mListeners != null) {
    376                 ArrayList<AnimatorListener> tmpListeners =
    377                         (ArrayList<AnimatorListener>) mListeners.clone();
    378                 for (AnimatorListener listener : tmpListeners) {
    379                     listener.onAnimationEnd(this);
    380                 }
    381             }
    382             mStarted = false;
    383         }
    384     }
    385 
    386     /**
    387      * Returns true if any of the child animations of this AnimatorSet have been started and have
    388      * not yet ended.
    389      * @return Whether this AnimatorSet has been started and has not yet ended.
    390      */
    391     @Override
    392     public boolean isRunning() {
    393         for (Node node : mNodes) {
    394             if (node.animation.isRunning()) {
    395                 return true;
    396             }
    397         }
    398         return false;
    399     }
    400 
    401     @Override
    402     public boolean isStarted() {
    403         return mStarted;
    404     }
    405 
    406     /**
    407      * The amount of time, in milliseconds, to delay starting the animation after
    408      * {@link #start()} is called.
    409      *
    410      * @return the number of milliseconds to delay running the animation
    411      */
    412     @Override
    413     public long getStartDelay() {
    414         return mStartDelay;
    415     }
    416 
    417     /**
    418      * The amount of time, in milliseconds, to delay starting the animation after
    419      * {@link #start()} is called.
    420 
    421      * @param startDelay The amount of the delay, in milliseconds
    422      */
    423     @Override
    424     public void setStartDelay(long startDelay) {
    425         if (mStartDelay > 0) {
    426             mReversible = false;
    427         }
    428         mStartDelay = startDelay;
    429     }
    430 
    431     /**
    432      * Gets the length of each of the child animations of this AnimatorSet. This value may
    433      * be less than 0, which indicates that no duration has been set on this AnimatorSet
    434      * and each of the child animations will use their own duration.
    435      *
    436      * @return The length of the animation, in milliseconds, of each of the child
    437      * animations of this AnimatorSet.
    438      */
    439     @Override
    440     public long getDuration() {
    441         return mDuration;
    442     }
    443 
    444     /**
    445      * Sets the length of each of the current child animations of this AnimatorSet. By default,
    446      * each child animation will use its own duration. If the duration is set on the AnimatorSet,
    447      * then each child animation inherits this duration.
    448      *
    449      * @param duration The length of the animation, in milliseconds, of each of the child
    450      * animations of this AnimatorSet.
    451      */
    452     @Override
    453     public AnimatorSet setDuration(long duration) {
    454         if (duration < 0) {
    455             throw new IllegalArgumentException("duration must be a value of zero or greater");
    456         }
    457         // Just record the value for now - it will be used later when the AnimatorSet starts
    458         mDuration = duration;
    459         return this;
    460     }
    461 
    462     @Override
    463     public void setupStartValues() {
    464         for (Node node : mNodes) {
    465             node.animation.setupStartValues();
    466         }
    467     }
    468 
    469     @Override
    470     public void setupEndValues() {
    471         for (Node node : mNodes) {
    472             node.animation.setupEndValues();
    473         }
    474     }
    475 
    476     @Override
    477     public void pause() {
    478         boolean previouslyPaused = mPaused;
    479         super.pause();
    480         if (!previouslyPaused && mPaused) {
    481             if (mDelayAnim != null) {
    482                 mDelayAnim.pause();
    483             } else {
    484                 for (Node node : mNodes) {
    485                     node.animation.pause();
    486                 }
    487             }
    488         }
    489     }
    490 
    491     @Override
    492     public void resume() {
    493         boolean previouslyPaused = mPaused;
    494         super.resume();
    495         if (previouslyPaused && !mPaused) {
    496             if (mDelayAnim != null) {
    497                 mDelayAnim.resume();
    498             } else {
    499                 for (Node node : mNodes) {
    500                     node.animation.resume();
    501                 }
    502             }
    503         }
    504     }
    505 
    506     /**
    507      * {@inheritDoc}
    508      *
    509      * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which
    510      * it is responsible. The details of when exactly those animations are started depends on
    511      * the dependency relationships that have been set up between the animations.
    512      */
    513     @SuppressWarnings("unchecked")
    514     @Override
    515     public void start() {
    516         mTerminated = false;
    517         mStarted = true;
    518         mPaused = false;
    519 
    520         for (Node node : mNodes) {
    521             node.animation.setAllowRunningAsynchronously(false);
    522         }
    523 
    524         if (mDuration >= 0) {
    525             // If the duration was set on this AnimatorSet, pass it along to all child animations
    526             for (Node node : mNodes) {
    527                 // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
    528                 // insert "play-after" delays
    529                 node.animation.setDuration(mDuration);
    530             }
    531         }
    532         if (mInterpolator != null) {
    533             for (Node node : mNodes) {
    534                 node.animation.setInterpolator(mInterpolator);
    535             }
    536         }
    537         // First, sort the nodes (if necessary). This will ensure that sortedNodes
    538         // contains the animation nodes in the correct order.
    539         sortNodes();
    540 
    541         int numSortedNodes = mSortedNodes.size();
    542         for (int i = 0; i < numSortedNodes; ++i) {
    543             Node node = mSortedNodes.get(i);
    544             // First, clear out the old listeners
    545             ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
    546             if (oldListeners != null && oldListeners.size() > 0) {
    547                 final ArrayList<AnimatorListener> clonedListeners = new
    548                         ArrayList<AnimatorListener>(oldListeners);
    549 
    550                 for (AnimatorListener listener : clonedListeners) {
    551                     if (listener instanceof DependencyListener ||
    552                             listener instanceof AnimatorSetListener) {
    553                         node.animation.removeListener(listener);
    554                     }
    555                 }
    556             }
    557         }
    558 
    559         // nodesToStart holds the list of nodes to be started immediately. We don't want to
    560         // start the animations in the loop directly because we first need to set up
    561         // dependencies on all of the nodes. For example, we don't want to start an animation
    562         // when some other animation also wants to start when the first animation begins.
    563         final ArrayList<Node> nodesToStart = new ArrayList<Node>();
    564         for (int i = 0; i < numSortedNodes; ++i) {
    565             Node node = mSortedNodes.get(i);
    566             if (mSetListener == null) {
    567                 mSetListener = new AnimatorSetListener(this);
    568             }
    569             if (node.dependencies == null || node.dependencies.size() == 0) {
    570                 nodesToStart.add(node);
    571             } else {
    572                 int numDependencies = node.dependencies.size();
    573                 for (int j = 0; j < numDependencies; ++j) {
    574                     Dependency dependency = node.dependencies.get(j);
    575                     dependency.node.animation.addListener(
    576                             new DependencyListener(this, node, dependency.rule));
    577                 }
    578                 node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone();
    579             }
    580             node.animation.addListener(mSetListener);
    581         }
    582         // Now that all dependencies are set up, start the animations that should be started.
    583         if (mStartDelay <= 0) {
    584             for (Node node : nodesToStart) {
    585                 node.animation.start();
    586                 mPlayingSet.add(node.animation);
    587             }
    588         } else {
    589             mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
    590             mDelayAnim.setDuration(mStartDelay);
    591             mDelayAnim.addListener(new AnimatorListenerAdapter() {
    592                 boolean canceled = false;
    593                 public void onAnimationCancel(Animator anim) {
    594                     canceled = true;
    595                 }
    596                 public void onAnimationEnd(Animator anim) {
    597                     if (!canceled) {
    598                         int numNodes = nodesToStart.size();
    599                         for (int i = 0; i < numNodes; ++i) {
    600                             Node node = nodesToStart.get(i);
    601                             node.animation.start();
    602                             mPlayingSet.add(node.animation);
    603                         }
    604                     }
    605                     mDelayAnim = null;
    606                 }
    607             });
    608             mDelayAnim.start();
    609         }
    610         if (mListeners != null) {
    611             ArrayList<AnimatorListener> tmpListeners =
    612                     (ArrayList<AnimatorListener>) mListeners.clone();
    613             int numListeners = tmpListeners.size();
    614             for (int i = 0; i < numListeners; ++i) {
    615                 tmpListeners.get(i).onAnimationStart(this);
    616             }
    617         }
    618         if (mNodes.size() == 0 && mStartDelay == 0) {
    619             // Handle unusual case where empty AnimatorSet is started - should send out
    620             // end event immediately since the event will not be sent out at all otherwise
    621             mStarted = false;
    622             if (mListeners != null) {
    623                 ArrayList<AnimatorListener> tmpListeners =
    624                         (ArrayList<AnimatorListener>) mListeners.clone();
    625                 int numListeners = tmpListeners.size();
    626                 for (int i = 0; i < numListeners; ++i) {
    627                     tmpListeners.get(i).onAnimationEnd(this);
    628                 }
    629             }
    630         }
    631     }
    632 
    633     @Override
    634     public AnimatorSet clone() {
    635         final AnimatorSet anim = (AnimatorSet) super.clone();
    636         /*
    637          * The basic clone() operation copies all items. This doesn't work very well for
    638          * AnimatorSet, because it will copy references that need to be recreated and state
    639          * that may not apply. What we need to do now is put the clone in an uninitialized
    640          * state, with fresh, empty data structures. Then we will build up the nodes list
    641          * manually, as we clone each Node (and its animation). The clone will then be sorted,
    642          * and will populate any appropriate lists, when it is started.
    643          */
    644         final int nodeCount = mNodes.size();
    645         anim.mNeedsSort = true;
    646         anim.mTerminated = false;
    647         anim.mStarted = false;
    648         anim.mPlayingSet = new ArrayList<Animator>();
    649         anim.mNodeMap = new HashMap<Animator, Node>();
    650         anim.mNodes = new ArrayList<Node>(nodeCount);
    651         anim.mSortedNodes = new ArrayList<Node>(nodeCount);
    652         anim.mReversible = mReversible;
    653         anim.mSetListener = null;
    654 
    655         // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
    656         // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
    657         // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
    658 
    659         for (int n = 0; n < nodeCount; n++) {
    660             final Node node = mNodes.get(n);
    661             Node nodeClone = node.clone();
    662             node.mTmpClone = nodeClone;
    663             anim.mNodes.add(nodeClone);
    664             anim.mNodeMap.put(nodeClone.animation, nodeClone);
    665             // Clear out the dependencies in the clone; we'll set these up manually later
    666             nodeClone.dependencies = null;
    667             nodeClone.tmpDependencies = null;
    668             nodeClone.nodeDependents = null;
    669             nodeClone.nodeDependencies = null;
    670 
    671             // clear out any listeners that were set up by the AnimatorSet; these will
    672             // be set up when the clone's nodes are sorted
    673             final ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
    674             if (cloneListeners != null) {
    675                 for (int i = cloneListeners.size() - 1; i >= 0; i--) {
    676                     final AnimatorListener listener = cloneListeners.get(i);
    677                     if (listener instanceof AnimatorSetListener) {
    678                         cloneListeners.remove(i);
    679                     }
    680                 }
    681             }
    682         }
    683         // Now that we've cloned all of the nodes, we're ready to walk through their
    684         // dependencies, mapping the old dependencies to the new nodes
    685         for (int n = 0; n < nodeCount; n++) {
    686             final Node node = mNodes.get(n);
    687             final Node clone = node.mTmpClone;
    688             if (node.dependencies != null) {
    689                 clone.dependencies = new ArrayList<Dependency>(node.dependencies.size());
    690                 final int depSize = node.dependencies.size();
    691                 for (int i = 0; i < depSize; i ++) {
    692                     final Dependency dependency = node.dependencies.get(i);
    693                     Dependency cloneDependency = new Dependency(dependency.node.mTmpClone,
    694                             dependency.rule);
    695                     clone.dependencies.add(cloneDependency);
    696                 }
    697             }
    698             if (node.nodeDependents != null) {
    699                 clone.nodeDependents = new ArrayList<Node>(node.nodeDependents.size());
    700                 for (Node dep : node.nodeDependents) {
    701                     clone.nodeDependents.add(dep.mTmpClone);
    702                 }
    703             }
    704             if (node.nodeDependencies != null) {
    705                 clone.nodeDependencies = new ArrayList<Node>(node.nodeDependencies.size());
    706                 for (Node dep : node.nodeDependencies) {
    707                     clone.nodeDependencies.add(dep.mTmpClone);
    708                 }
    709             }
    710         }
    711         for (int n = 0; n < nodeCount; n++) {
    712             mNodes.get(n).mTmpClone = null;
    713         }
    714         return anim;
    715     }
    716 
    717     /**
    718      * This class is the mechanism by which animations are started based on events in other
    719      * animations. If an animation has multiple dependencies on other animations, then
    720      * all dependencies must be satisfied before the animation is started.
    721      */
    722     private static class DependencyListener implements AnimatorListener {
    723 
    724         private AnimatorSet mAnimatorSet;
    725 
    726         // The node upon which the dependency is based.
    727         private Node mNode;
    728 
    729         // The Dependency rule (WITH or AFTER) that the listener should wait for on
    730         // the node
    731         private int mRule;
    732 
    733         public DependencyListener(AnimatorSet animatorSet, Node node, int rule) {
    734             this.mAnimatorSet = animatorSet;
    735             this.mNode = node;
    736             this.mRule = rule;
    737         }
    738 
    739         /**
    740          * Ignore cancel events for now. We may want to handle this eventually,
    741          * to prevent follow-on animations from running when some dependency
    742          * animation is canceled.
    743          */
    744         public void onAnimationCancel(Animator animation) {
    745         }
    746 
    747         /**
    748          * An end event is received - see if this is an event we are listening for
    749          */
    750         public void onAnimationEnd(Animator animation) {
    751             if (mRule == Dependency.AFTER) {
    752                 startIfReady(animation);
    753             }
    754         }
    755 
    756         /**
    757          * Ignore repeat events for now
    758          */
    759         public void onAnimationRepeat(Animator animation) {
    760         }
    761 
    762         /**
    763          * A start event is received - see if this is an event we are listening for
    764          */
    765         public void onAnimationStart(Animator animation) {
    766             if (mRule == Dependency.WITH) {
    767                 startIfReady(animation);
    768             }
    769         }
    770 
    771         /**
    772          * Check whether the event received is one that the node was waiting for.
    773          * If so, mark it as complete and see whether it's time to start
    774          * the animation.
    775          * @param dependencyAnimation the animation that sent the event.
    776          */
    777         private void startIfReady(Animator dependencyAnimation) {
    778             if (mAnimatorSet.mTerminated) {
    779                 // if the parent AnimatorSet was canceled, then don't start any dependent anims
    780                 return;
    781             }
    782             Dependency dependencyToRemove = null;
    783             int numDependencies = mNode.tmpDependencies.size();
    784             for (int i = 0; i < numDependencies; ++i) {
    785                 Dependency dependency = mNode.tmpDependencies.get(i);
    786                 if (dependency.rule == mRule &&
    787                         dependency.node.animation == dependencyAnimation) {
    788                     // rule fired - remove the dependency and listener and check to
    789                     // see whether it's time to start the animation
    790                     dependencyToRemove = dependency;
    791                     dependencyAnimation.removeListener(this);
    792                     break;
    793                 }
    794             }
    795             mNode.tmpDependencies.remove(dependencyToRemove);
    796             if (mNode.tmpDependencies.size() == 0) {
    797                 // all dependencies satisfied: start the animation
    798                 mNode.animation.start();
    799                 mAnimatorSet.mPlayingSet.add(mNode.animation);
    800             }
    801         }
    802 
    803     }
    804 
    805     private class AnimatorSetListener implements AnimatorListener {
    806 
    807         private AnimatorSet mAnimatorSet;
    808 
    809         AnimatorSetListener(AnimatorSet animatorSet) {
    810             mAnimatorSet = animatorSet;
    811         }
    812 
    813         public void onAnimationCancel(Animator animation) {
    814             if (!mTerminated) {
    815                 // Listeners are already notified of the AnimatorSet canceling in cancel().
    816                 // The logic below only kicks in when animations end normally
    817                 if (mPlayingSet.size() == 0) {
    818                     if (mListeners != null) {
    819                         int numListeners = mListeners.size();
    820                         for (int i = 0; i < numListeners; ++i) {
    821                             mListeners.get(i).onAnimationCancel(mAnimatorSet);
    822                         }
    823                     }
    824                 }
    825             }
    826         }
    827 
    828         @SuppressWarnings("unchecked")
    829         public void onAnimationEnd(Animator animation) {
    830             animation.removeListener(this);
    831             mPlayingSet.remove(animation);
    832             Node animNode = mAnimatorSet.mNodeMap.get(animation);
    833             animNode.done = true;
    834             if (!mTerminated) {
    835                 // Listeners are already notified of the AnimatorSet ending in cancel() or
    836                 // end(); the logic below only kicks in when animations end normally
    837                 ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
    838                 boolean allDone = true;
    839                 int numSortedNodes = sortedNodes.size();
    840                 for (int i = 0; i < numSortedNodes; ++i) {
    841                     if (!sortedNodes.get(i).done) {
    842                         allDone = false;
    843                         break;
    844                     }
    845                 }
    846                 if (allDone) {
    847                     // If this was the last child animation to end, then notify listeners that this
    848                     // AnimatorSet has ended
    849                     if (mListeners != null) {
    850                         ArrayList<AnimatorListener> tmpListeners =
    851                                 (ArrayList<AnimatorListener>) mListeners.clone();
    852                         int numListeners = tmpListeners.size();
    853                         for (int i = 0; i < numListeners; ++i) {
    854                             tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
    855                         }
    856                     }
    857                     mAnimatorSet.mStarted = false;
    858                     mAnimatorSet.mPaused = false;
    859                 }
    860             }
    861         }
    862 
    863         // Nothing to do
    864         public void onAnimationRepeat(Animator animation) {
    865         }
    866 
    867         // Nothing to do
    868         public void onAnimationStart(Animator animation) {
    869         }
    870 
    871     }
    872 
    873     /**
    874      * This method sorts the current set of nodes, if needed. The sort is a simple
    875      * DependencyGraph sort, which goes like this:
    876      * - All nodes without dependencies become 'roots'
    877      * - while roots list is not null
    878      * -   for each root r
    879      * -     add r to sorted list
    880      * -     remove r as a dependency from any other node
    881      * -   any nodes with no dependencies are added to the roots list
    882      */
    883     private void sortNodes() {
    884         if (mNeedsSort) {
    885             mSortedNodes.clear();
    886             ArrayList<Node> roots = new ArrayList<Node>();
    887             int numNodes = mNodes.size();
    888             for (int i = 0; i < numNodes; ++i) {
    889                 Node node = mNodes.get(i);
    890                 if (node.dependencies == null || node.dependencies.size() == 0) {
    891                     roots.add(node);
    892                 }
    893             }
    894             ArrayList<Node> tmpRoots = new ArrayList<Node>();
    895             while (roots.size() > 0) {
    896                 int numRoots = roots.size();
    897                 for (int i = 0; i < numRoots; ++i) {
    898                     Node root = roots.get(i);
    899                     mSortedNodes.add(root);
    900                     if (root.nodeDependents != null) {
    901                         int numDependents = root.nodeDependents.size();
    902                         for (int j = 0; j < numDependents; ++j) {
    903                             Node node = root.nodeDependents.get(j);
    904                             node.nodeDependencies.remove(root);
    905                             if (node.nodeDependencies.size() == 0) {
    906                                 tmpRoots.add(node);
    907                             }
    908                         }
    909                     }
    910                 }
    911                 roots.clear();
    912                 roots.addAll(tmpRoots);
    913                 tmpRoots.clear();
    914             }
    915             mNeedsSort = false;
    916             if (mSortedNodes.size() != mNodes.size()) {
    917                 throw new IllegalStateException("Circular dependencies cannot exist"
    918                         + " in AnimatorSet");
    919             }
    920         } else {
    921             // Doesn't need sorting, but still need to add in the nodeDependencies list
    922             // because these get removed as the event listeners fire and the dependencies
    923             // are satisfied
    924             int numNodes = mNodes.size();
    925             for (int i = 0; i < numNodes; ++i) {
    926                 Node node = mNodes.get(i);
    927                 if (node.dependencies != null && node.dependencies.size() > 0) {
    928                     int numDependencies = node.dependencies.size();
    929                     for (int j = 0; j < numDependencies; ++j) {
    930                         Dependency dependency = node.dependencies.get(j);
    931                         if (node.nodeDependencies == null) {
    932                             node.nodeDependencies = new ArrayList<Node>();
    933                         }
    934                         if (!node.nodeDependencies.contains(dependency.node)) {
    935                             node.nodeDependencies.add(dependency.node);
    936                         }
    937                     }
    938                 }
    939                 // nodes are 'done' by default; they become un-done when started, and done
    940                 // again when ended
    941                 node.done = false;
    942             }
    943         }
    944     }
    945 
    946     /**
    947      * @hide
    948      */
    949     @Override
    950     public boolean canReverse() {
    951         if (!mReversible)  {
    952             return false;
    953         }
    954         // Loop to make sure all the Nodes can reverse.
    955         for (Node node : mNodes) {
    956             if (!node.animation.canReverse() || node.animation.getStartDelay() > 0) {
    957                 return false;
    958             }
    959         }
    960         return true;
    961     }
    962 
    963     /**
    964      * @hide
    965      */
    966     @Override
    967     public void reverse() {
    968         if (canReverse()) {
    969             for (Node node : mNodes) {
    970                 node.animation.reverse();
    971             }
    972         }
    973     }
    974 
    975     /**
    976      * Dependency holds information about the node that some other node is
    977      * dependent upon and the nature of that dependency.
    978      *
    979      */
    980     private static class Dependency {
    981         static final int WITH = 0; // dependent node must start with this dependency node
    982         static final int AFTER = 1; // dependent node must start when this dependency node finishes
    983 
    984         // The node that the other node with this Dependency is dependent upon
    985         public Node node;
    986 
    987         // The nature of the dependency (WITH or AFTER)
    988         public int rule;
    989 
    990         public Dependency(Node node, int rule) {
    991             this.node = node;
    992             this.rule = rule;
    993         }
    994     }
    995 
    996     /**
    997      * A Node is an embodiment of both the Animator that it wraps as well as
    998      * any dependencies that are associated with that Animation. This includes
    999      * both dependencies upon other nodes (in the dependencies list) as
   1000      * well as dependencies of other nodes upon this (in the nodeDependents list).
   1001      */
   1002     private static class Node implements Cloneable {
   1003         public Animator animation;
   1004 
   1005         /**
   1006          *  These are the dependencies that this node's animation has on other
   1007          *  nodes. For example, if this node's animation should begin with some
   1008          *  other animation ends, then there will be an item in this node's
   1009          *  dependencies list for that other animation's node.
   1010          */
   1011         public ArrayList<Dependency> dependencies = null;
   1012 
   1013         /**
   1014          * tmpDependencies is a runtime detail. We use the dependencies list for sorting.
   1015          * But we also use the list to keep track of when multiple dependencies are satisfied,
   1016          * but removing each dependency as it is satisfied. We do not want to remove
   1017          * the dependency itself from the list, because we need to retain that information
   1018          * if the AnimatorSet is launched in the future. So we create a copy of the dependency
   1019          * list when the AnimatorSet starts and use this tmpDependencies list to track the
   1020          * list of satisfied dependencies.
   1021          */
   1022         public ArrayList<Dependency> tmpDependencies = null;
   1023 
   1024         /**
   1025          * nodeDependencies is just a list of the nodes that this Node is dependent upon.
   1026          * This information is used in sortNodes(), to determine when a node is a root.
   1027          */
   1028         public ArrayList<Node> nodeDependencies = null;
   1029 
   1030         /**
   1031          * nodeDepdendents is the list of nodes that have this node as a dependency. This
   1032          * is a utility field used in sortNodes to facilitate removing this node as a
   1033          * dependency when it is a root node.
   1034          */
   1035         public ArrayList<Node> nodeDependents = null;
   1036 
   1037         /**
   1038          * Flag indicating whether the animation in this node is finished. This flag
   1039          * is used by AnimatorSet to check, as each animation ends, whether all child animations
   1040          * are done and it's time to send out an end event for the entire AnimatorSet.
   1041          */
   1042         public boolean done = false;
   1043 
   1044         /**
   1045          * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
   1046          */
   1047         private Node mTmpClone = null;
   1048 
   1049         /**
   1050          * Constructs the Node with the animation that it encapsulates. A Node has no
   1051          * dependencies by default; dependencies are added via the addDependency()
   1052          * method.
   1053          *
   1054          * @param animation The animation that the Node encapsulates.
   1055          */
   1056         public Node(Animator animation) {
   1057             this.animation = animation;
   1058         }
   1059 
   1060         /**
   1061          * Add a dependency to this Node. The dependency includes information about the
   1062          * node that this node is dependency upon and the nature of the dependency.
   1063          * @param dependency
   1064          */
   1065         public void addDependency(Dependency dependency) {
   1066             if (dependencies == null) {
   1067                 dependencies = new ArrayList<Dependency>();
   1068                 nodeDependencies = new ArrayList<Node>();
   1069             }
   1070             dependencies.add(dependency);
   1071             if (!nodeDependencies.contains(dependency.node)) {
   1072                 nodeDependencies.add(dependency.node);
   1073             }
   1074             Node dependencyNode = dependency.node;
   1075             if (dependencyNode.nodeDependents == null) {
   1076                 dependencyNode.nodeDependents = new ArrayList<Node>();
   1077             }
   1078             dependencyNode.nodeDependents.add(this);
   1079         }
   1080 
   1081         @Override
   1082         public Node clone() {
   1083             try {
   1084                 Node node = (Node) super.clone();
   1085                 node.animation = (Animator) animation.clone();
   1086                 return node;
   1087             } catch (CloneNotSupportedException e) {
   1088                throw new AssertionError();
   1089             }
   1090         }
   1091     }
   1092 
   1093     /**
   1094      * The <code>Builder</code> object is a utility class to facilitate adding animations to a
   1095      * <code>AnimatorSet</code> along with the relationships between the various animations. The
   1096      * intention of the <code>Builder</code> methods, along with the {@link
   1097      * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible
   1098      * to express the dependency relationships of animations in a natural way. Developers can also
   1099      * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
   1100      * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
   1101      * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
   1102      * <p/>
   1103      * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
   1104      * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
   1105      * <p/>
   1106      * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
   1107      * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
   1108      * <pre>
   1109      *     AnimatorSet s = new AnimatorSet();
   1110      *     s.play(anim1).with(anim2);
   1111      *     s.play(anim2).before(anim3);
   1112      *     s.play(anim4).after(anim3);
   1113      * </pre>
   1114      * <p/>
   1115      * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
   1116      * Builder#after(Animator)} are used. These are just different ways of expressing the same
   1117      * relationship and are provided to make it easier to say things in a way that is more natural,
   1118      * depending on the situation.</p>
   1119      * <p/>
   1120      * <p>It is possible to make several calls into the same <code>Builder</code> object to express
   1121      * multiple relationships. However, note that it is only the animation passed into the initial
   1122      * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
   1123      * calls to the <code>Builder</code> object. For example, the following code starts both anim2
   1124      * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
   1125      * anim3:
   1126      * <pre>
   1127      *   AnimatorSet s = new AnimatorSet();
   1128      *   s.play(anim1).before(anim2).before(anim3);
   1129      * </pre>
   1130      * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
   1131      * relationship correctly:</p>
   1132      * <pre>
   1133      *   AnimatorSet s = new AnimatorSet();
   1134      *   s.play(anim1).before(anim2);
   1135      *   s.play(anim2).before(anim3);
   1136      * </pre>
   1137      * <p/>
   1138      * <p>Note that it is possible to express relationships that cannot be resolved and will not
   1139      * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
   1140      * sense. In general, circular dependencies like this one (or more indirect ones where a depends
   1141      * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
   1142      * that can boil down to a simple, one-way relationship of animations starting with, before, and
   1143      * after other, different, animations.</p>
   1144      */
   1145     public class Builder {
   1146 
   1147         /**
   1148          * This tracks the current node being processed. It is supplied to the play() method
   1149          * of AnimatorSet and passed into the constructor of Builder.
   1150          */
   1151         private Node mCurrentNode;
   1152 
   1153         /**
   1154          * package-private constructor. Builders are only constructed by AnimatorSet, when the
   1155          * play() method is called.
   1156          *
   1157          * @param anim The animation that is the dependency for the other animations passed into
   1158          * the other methods of this Builder object.
   1159          */
   1160         Builder(Animator anim) {
   1161             mCurrentNode = mNodeMap.get(anim);
   1162             if (mCurrentNode == null) {
   1163                 mCurrentNode = new Node(anim);
   1164                 mNodeMap.put(anim, mCurrentNode);
   1165                 mNodes.add(mCurrentNode);
   1166             }
   1167         }
   1168 
   1169         /**
   1170          * Sets up the given animation to play at the same time as the animation supplied in the
   1171          * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
   1172          *
   1173          * @param anim The animation that will play when the animation supplied to the
   1174          * {@link AnimatorSet#play(Animator)} method starts.
   1175          */
   1176         public Builder with(Animator anim) {
   1177             Node node = mNodeMap.get(anim);
   1178             if (node == null) {
   1179                 node = new Node(anim);
   1180                 mNodeMap.put(anim, node);
   1181                 mNodes.add(node);
   1182             }
   1183             Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
   1184             node.addDependency(dependency);
   1185             return this;
   1186         }
   1187 
   1188         /**
   1189          * Sets up the given animation to play when the animation supplied in the
   1190          * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
   1191          * ends.
   1192          *
   1193          * @param anim The animation that will play when the animation supplied to the
   1194          * {@link AnimatorSet#play(Animator)} method ends.
   1195          */
   1196         public Builder before(Animator anim) {
   1197             mReversible = false;
   1198             Node node = mNodeMap.get(anim);
   1199             if (node == null) {
   1200                 node = new Node(anim);
   1201                 mNodeMap.put(anim, node);
   1202                 mNodes.add(node);
   1203             }
   1204             Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
   1205             node.addDependency(dependency);
   1206             return this;
   1207         }
   1208 
   1209         /**
   1210          * Sets up the given animation to play when the animation supplied in the
   1211          * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
   1212          * to start when the animation supplied in this method call ends.
   1213          *
   1214          * @param anim The animation whose end will cause the animation supplied to the
   1215          * {@link AnimatorSet#play(Animator)} method to play.
   1216          */
   1217         public Builder after(Animator anim) {
   1218             mReversible = false;
   1219             Node node = mNodeMap.get(anim);
   1220             if (node == null) {
   1221                 node = new Node(anim);
   1222                 mNodeMap.put(anim, node);
   1223                 mNodes.add(node);
   1224             }
   1225             Dependency dependency = new Dependency(node, Dependency.AFTER);
   1226             mCurrentNode.addDependency(dependency);
   1227             return this;
   1228         }
   1229 
   1230         /**
   1231          * Sets up the animation supplied in the
   1232          * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
   1233          * to play when the given amount of time elapses.
   1234          *
   1235          * @param delay The number of milliseconds that should elapse before the
   1236          * animation starts.
   1237          */
   1238         public Builder after(long delay) {
   1239             // setup dummy ValueAnimator just to run the clock
   1240             ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
   1241             anim.setDuration(delay);
   1242             after(anim);
   1243             return this;
   1244         }
   1245 
   1246     }
   1247 
   1248 }
   1249