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