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