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