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