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