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