AnimatorSet.java revision 0084e370955cfa1efbf8ab447ac5e71a5529f5d3
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            copyDurationScaleInfoTo(node.animation);
523        }
524
525        if (mDuration >= 0) {
526            // If the duration was set on this AnimatorSet, pass it along to all child animations
527            for (Node node : mNodes) {
528                // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
529                // insert "play-after" delays
530                node.animation.setDuration(mDuration);
531            }
532        }
533        if (mInterpolator != null) {
534            for (Node node : mNodes) {
535                node.animation.setInterpolator(mInterpolator);
536            }
537        }
538        // First, sort the nodes (if necessary). This will ensure that sortedNodes
539        // contains the animation nodes in the correct order.
540        sortNodes();
541
542        int numSortedNodes = mSortedNodes.size();
543        for (int i = 0; i < numSortedNodes; ++i) {
544            Node node = mSortedNodes.get(i);
545            // First, clear out the old listeners
546            ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
547            if (oldListeners != null && oldListeners.size() > 0) {
548                final ArrayList<AnimatorListener> clonedListeners = new
549                        ArrayList<AnimatorListener>(oldListeners);
550
551                for (AnimatorListener listener : clonedListeners) {
552                    if (listener instanceof DependencyListener ||
553                            listener instanceof AnimatorSetListener) {
554                        node.animation.removeListener(listener);
555                    }
556                }
557            }
558        }
559
560        // nodesToStart holds the list of nodes to be started immediately. We don't want to
561        // start the animations in the loop directly because we first need to set up
562        // dependencies on all of the nodes. For example, we don't want to start an animation
563        // when some other animation also wants to start when the first animation begins.
564        final ArrayList<Node> nodesToStart = new ArrayList<Node>();
565        for (int i = 0; i < numSortedNodes; ++i) {
566            Node node = mSortedNodes.get(i);
567            if (mSetListener == null) {
568                mSetListener = new AnimatorSetListener(this);
569            }
570            if (node.dependencies == null || node.dependencies.size() == 0) {
571                nodesToStart.add(node);
572            } else {
573                int numDependencies = node.dependencies.size();
574                for (int j = 0; j < numDependencies; ++j) {
575                    Dependency dependency = node.dependencies.get(j);
576                    dependency.node.animation.addListener(
577                            new DependencyListener(this, node, dependency.rule));
578                }
579                node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone();
580            }
581            node.animation.addListener(mSetListener);
582        }
583        // Now that all dependencies are set up, start the animations that should be started.
584        if (mStartDelay <= 0) {
585            for (Node node : nodesToStart) {
586                node.animation.start();
587                mPlayingSet.add(node.animation);
588            }
589        } else {
590            mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
591            mDelayAnim.setDuration(mStartDelay);
592            mDelayAnim.addListener(new AnimatorListenerAdapter() {
593                boolean canceled = false;
594                public void onAnimationCancel(Animator anim) {
595                    canceled = true;
596                }
597                public void onAnimationEnd(Animator anim) {
598                    if (!canceled) {
599                        int numNodes = nodesToStart.size();
600                        for (int i = 0; i < numNodes; ++i) {
601                            Node node = nodesToStart.get(i);
602                            node.animation.start();
603                            mPlayingSet.add(node.animation);
604                        }
605                    }
606                    mDelayAnim = null;
607                }
608            });
609            mDelayAnim.start();
610        }
611        if (mListeners != null) {
612            ArrayList<AnimatorListener> tmpListeners =
613                    (ArrayList<AnimatorListener>) mListeners.clone();
614            int numListeners = tmpListeners.size();
615            for (int i = 0; i < numListeners; ++i) {
616                tmpListeners.get(i).onAnimationStart(this);
617            }
618        }
619        if (mNodes.size() == 0 && mStartDelay == 0) {
620            // Handle unusual case where empty AnimatorSet is started - should send out
621            // end event immediately since the event will not be sent out at all otherwise
622            mStarted = false;
623            if (mListeners != null) {
624                ArrayList<AnimatorListener> tmpListeners =
625                        (ArrayList<AnimatorListener>) mListeners.clone();
626                int numListeners = tmpListeners.size();
627                for (int i = 0; i < numListeners; ++i) {
628                    tmpListeners.get(i).onAnimationEnd(this);
629                }
630            }
631        }
632    }
633
634    @Override
635    public AnimatorSet clone() {
636        final AnimatorSet anim = (AnimatorSet) super.clone();
637        /*
638         * The basic clone() operation copies all items. This doesn't work very well for
639         * AnimatorSet, because it will copy references that need to be recreated and state
640         * that may not apply. What we need to do now is put the clone in an uninitialized
641         * state, with fresh, empty data structures. Then we will build up the nodes list
642         * manually, as we clone each Node (and its animation). The clone will then be sorted,
643         * and will populate any appropriate lists, when it is started.
644         */
645        final int nodeCount = mNodes.size();
646        anim.mNeedsSort = true;
647        anim.mTerminated = false;
648        anim.mStarted = false;
649        anim.mPlayingSet = new ArrayList<Animator>();
650        anim.mNodeMap = new HashMap<Animator, Node>();
651        anim.mNodes = new ArrayList<Node>(nodeCount);
652        anim.mSortedNodes = new ArrayList<Node>(nodeCount);
653        anim.mReversible = mReversible;
654        anim.mSetListener = null;
655
656        // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
657        // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
658        // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
659
660        for (int n = 0; n < nodeCount; n++) {
661            final Node node = mNodes.get(n);
662            Node nodeClone = node.clone();
663            node.mTmpClone = nodeClone;
664            anim.mNodes.add(nodeClone);
665            anim.mNodeMap.put(nodeClone.animation, nodeClone);
666            // Clear out the dependencies in the clone; we'll set these up manually later
667            nodeClone.dependencies = null;
668            nodeClone.tmpDependencies = null;
669            nodeClone.nodeDependents = null;
670            nodeClone.nodeDependencies = null;
671
672            // clear out any listeners that were set up by the AnimatorSet; these will
673            // be set up when the clone's nodes are sorted
674            final ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
675            if (cloneListeners != null) {
676                for (int i = cloneListeners.size() - 1; i >= 0; i--) {
677                    final AnimatorListener listener = cloneListeners.get(i);
678                    if (listener instanceof AnimatorSetListener) {
679                        cloneListeners.remove(i);
680                    }
681                }
682            }
683        }
684        // Now that we've cloned all of the nodes, we're ready to walk through their
685        // dependencies, mapping the old dependencies to the new nodes
686        for (int n = 0; n < nodeCount; n++) {
687            final Node node = mNodes.get(n);
688            final Node clone = node.mTmpClone;
689            if (node.dependencies != null) {
690                clone.dependencies = new ArrayList<Dependency>(node.dependencies.size());
691                final int depSize = node.dependencies.size();
692                for (int i = 0; i < depSize; i ++) {
693                    final Dependency dependency = node.dependencies.get(i);
694                    Dependency cloneDependency = new Dependency(dependency.node.mTmpClone,
695                            dependency.rule);
696                    clone.dependencies.add(cloneDependency);
697                }
698            }
699            if (node.nodeDependents != null) {
700                clone.nodeDependents = new ArrayList<Node>(node.nodeDependents.size());
701                for (Node dep : node.nodeDependents) {
702                    clone.nodeDependents.add(dep.mTmpClone);
703                }
704            }
705            if (node.nodeDependencies != null) {
706                clone.nodeDependencies = new ArrayList<Node>(node.nodeDependencies.size());
707                for (Node dep : node.nodeDependencies) {
708                    clone.nodeDependencies.add(dep.mTmpClone);
709                }
710            }
711        }
712        for (int n = 0; n < nodeCount; n++) {
713            mNodes.get(n).mTmpClone = null;
714        }
715        return anim;
716    }
717
718    /**
719     * This class is the mechanism by which animations are started based on events in other
720     * animations. If an animation has multiple dependencies on other animations, then
721     * all dependencies must be satisfied before the animation is started.
722     */
723    private static class DependencyListener implements AnimatorListener {
724
725        private AnimatorSet mAnimatorSet;
726
727        // The node upon which the dependency is based.
728        private Node mNode;
729
730        // The Dependency rule (WITH or AFTER) that the listener should wait for on
731        // the node
732        private int mRule;
733
734        public DependencyListener(AnimatorSet animatorSet, Node node, int rule) {
735            this.mAnimatorSet = animatorSet;
736            this.mNode = node;
737            this.mRule = rule;
738        }
739
740        /**
741         * Ignore cancel events for now. We may want to handle this eventually,
742         * to prevent follow-on animations from running when some dependency
743         * animation is canceled.
744         */
745        public void onAnimationCancel(Animator animation) {
746        }
747
748        /**
749         * An end event is received - see if this is an event we are listening for
750         */
751        public void onAnimationEnd(Animator animation) {
752            if (mRule == Dependency.AFTER) {
753                startIfReady(animation);
754            }
755        }
756
757        /**
758         * Ignore repeat events for now
759         */
760        public void onAnimationRepeat(Animator animation) {
761        }
762
763        /**
764         * A start event is received - see if this is an event we are listening for
765         */
766        public void onAnimationStart(Animator animation) {
767            if (mRule == Dependency.WITH) {
768                startIfReady(animation);
769            }
770        }
771
772        /**
773         * Check whether the event received is one that the node was waiting for.
774         * If so, mark it as complete and see whether it's time to start
775         * the animation.
776         * @param dependencyAnimation the animation that sent the event.
777         */
778        private void startIfReady(Animator dependencyAnimation) {
779            if (mAnimatorSet.mTerminated) {
780                // if the parent AnimatorSet was canceled, then don't start any dependent anims
781                return;
782            }
783            Dependency dependencyToRemove = null;
784            int numDependencies = mNode.tmpDependencies.size();
785            for (int i = 0; i < numDependencies; ++i) {
786                Dependency dependency = mNode.tmpDependencies.get(i);
787                if (dependency.rule == mRule &&
788                        dependency.node.animation == dependencyAnimation) {
789                    // rule fired - remove the dependency and listener and check to
790                    // see whether it's time to start the animation
791                    dependencyToRemove = dependency;
792                    dependencyAnimation.removeListener(this);
793                    break;
794                }
795            }
796            mNode.tmpDependencies.remove(dependencyToRemove);
797            if (mNode.tmpDependencies.size() == 0) {
798                // all dependencies satisfied: start the animation
799                mNode.animation.start();
800                mAnimatorSet.mPlayingSet.add(mNode.animation);
801            }
802        }
803
804    }
805
806    private class AnimatorSetListener implements AnimatorListener {
807
808        private AnimatorSet mAnimatorSet;
809
810        AnimatorSetListener(AnimatorSet animatorSet) {
811            mAnimatorSet = animatorSet;
812        }
813
814        public void onAnimationCancel(Animator animation) {
815            if (!mTerminated) {
816                // Listeners are already notified of the AnimatorSet canceling in cancel().
817                // The logic below only kicks in when animations end normally
818                if (mPlayingSet.size() == 0) {
819                    if (mListeners != null) {
820                        int numListeners = mListeners.size();
821                        for (int i = 0; i < numListeners; ++i) {
822                            mListeners.get(i).onAnimationCancel(mAnimatorSet);
823                        }
824                    }
825                }
826            }
827        }
828
829        @SuppressWarnings("unchecked")
830        public void onAnimationEnd(Animator animation) {
831            animation.removeListener(this);
832            mPlayingSet.remove(animation);
833            Node animNode = mAnimatorSet.mNodeMap.get(animation);
834            animNode.done = true;
835            if (!mTerminated) {
836                // Listeners are already notified of the AnimatorSet ending in cancel() or
837                // end(); the logic below only kicks in when animations end normally
838                ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
839                boolean allDone = true;
840                int numSortedNodes = sortedNodes.size();
841                for (int i = 0; i < numSortedNodes; ++i) {
842                    if (!sortedNodes.get(i).done) {
843                        allDone = false;
844                        break;
845                    }
846                }
847                if (allDone) {
848                    // If this was the last child animation to end, then notify listeners that this
849                    // AnimatorSet has ended
850                    if (mListeners != null) {
851                        ArrayList<AnimatorListener> tmpListeners =
852                                (ArrayList<AnimatorListener>) mListeners.clone();
853                        int numListeners = tmpListeners.size();
854                        for (int i = 0; i < numListeners; ++i) {
855                            tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
856                        }
857                    }
858                    mAnimatorSet.mStarted = false;
859                    mAnimatorSet.mPaused = false;
860                }
861            }
862        }
863
864        // Nothing to do
865        public void onAnimationRepeat(Animator animation) {
866        }
867
868        // Nothing to do
869        public void onAnimationStart(Animator animation) {
870        }
871
872    }
873
874    /**
875     * This method sorts the current set of nodes, if needed. The sort is a simple
876     * DependencyGraph sort, which goes like this:
877     * - All nodes without dependencies become 'roots'
878     * - while roots list is not null
879     * -   for each root r
880     * -     add r to sorted list
881     * -     remove r as a dependency from any other node
882     * -   any nodes with no dependencies are added to the roots list
883     */
884    private void sortNodes() {
885        if (mNeedsSort) {
886            mSortedNodes.clear();
887            ArrayList<Node> roots = new ArrayList<Node>();
888            int numNodes = mNodes.size();
889            for (int i = 0; i < numNodes; ++i) {
890                Node node = mNodes.get(i);
891                if (node.dependencies == null || node.dependencies.size() == 0) {
892                    roots.add(node);
893                }
894            }
895            ArrayList<Node> tmpRoots = new ArrayList<Node>();
896            while (roots.size() > 0) {
897                int numRoots = roots.size();
898                for (int i = 0; i < numRoots; ++i) {
899                    Node root = roots.get(i);
900                    mSortedNodes.add(root);
901                    if (root.nodeDependents != null) {
902                        int numDependents = root.nodeDependents.size();
903                        for (int j = 0; j < numDependents; ++j) {
904                            Node node = root.nodeDependents.get(j);
905                            node.nodeDependencies.remove(root);
906                            if (node.nodeDependencies.size() == 0) {
907                                tmpRoots.add(node);
908                            }
909                        }
910                    }
911                }
912                roots.clear();
913                roots.addAll(tmpRoots);
914                tmpRoots.clear();
915            }
916            mNeedsSort = false;
917            if (mSortedNodes.size() != mNodes.size()) {
918                throw new IllegalStateException("Circular dependencies cannot exist"
919                        + " in AnimatorSet");
920            }
921        } else {
922            // Doesn't need sorting, but still need to add in the nodeDependencies list
923            // because these get removed as the event listeners fire and the dependencies
924            // are satisfied
925            int numNodes = mNodes.size();
926            for (int i = 0; i < numNodes; ++i) {
927                Node node = mNodes.get(i);
928                if (node.dependencies != null && node.dependencies.size() > 0) {
929                    int numDependencies = node.dependencies.size();
930                    for (int j = 0; j < numDependencies; ++j) {
931                        Dependency dependency = node.dependencies.get(j);
932                        if (node.nodeDependencies == null) {
933                            node.nodeDependencies = new ArrayList<Node>();
934                        }
935                        if (!node.nodeDependencies.contains(dependency.node)) {
936                            node.nodeDependencies.add(dependency.node);
937                        }
938                    }
939                }
940                // nodes are 'done' by default; they become un-done when started, and done
941                // again when ended
942                node.done = false;
943            }
944        }
945    }
946
947    /**
948     * @hide
949     */
950    @Override
951    public boolean canReverse() {
952        if (!mReversible)  {
953            return false;
954        }
955        // Loop to make sure all the Nodes can reverse.
956        for (Node node : mNodes) {
957            if (!node.animation.canReverse() || node.animation.getStartDelay() > 0) {
958                return false;
959            }
960        }
961        return true;
962    }
963
964    /**
965     * @hide
966     */
967    @Override
968    public void reverse() {
969        if (canReverse()) {
970            for (Node node : mNodes) {
971                node.animation.reverse();
972            }
973        }
974    }
975
976    @Override
977    public String toString() {
978        String returnVal = "AnimatorSet@" + Integer.toHexString(hashCode()) + "{";
979        boolean prevNeedsSort = mNeedsSort;
980        sortNodes();
981        mNeedsSort = prevNeedsSort;
982        for (Node node : mSortedNodes) {
983            returnVal += "\n    " + node.animation.toString();
984        }
985        return returnVal + "\n}";
986    }
987
988    /**
989     * Dependency holds information about the node that some other node is
990     * dependent upon and the nature of that dependency.
991     *
992     */
993    private static class Dependency {
994        static final int WITH = 0; // dependent node must start with this dependency node
995        static final int AFTER = 1; // dependent node must start when this dependency node finishes
996
997        // The node that the other node with this Dependency is dependent upon
998        public Node node;
999
1000        // The nature of the dependency (WITH or AFTER)
1001        public int rule;
1002
1003        public Dependency(Node node, int rule) {
1004            this.node = node;
1005            this.rule = rule;
1006        }
1007    }
1008
1009    /**
1010     * A Node is an embodiment of both the Animator that it wraps as well as
1011     * any dependencies that are associated with that Animation. This includes
1012     * both dependencies upon other nodes (in the dependencies list) as
1013     * well as dependencies of other nodes upon this (in the nodeDependents list).
1014     */
1015    private static class Node implements Cloneable {
1016        public Animator animation;
1017
1018        /**
1019         *  These are the dependencies that this node's animation has on other
1020         *  nodes. For example, if this node's animation should begin with some
1021         *  other animation ends, then there will be an item in this node's
1022         *  dependencies list for that other animation's node.
1023         */
1024        public ArrayList<Dependency> dependencies = null;
1025
1026        /**
1027         * tmpDependencies is a runtime detail. We use the dependencies list for sorting.
1028         * But we also use the list to keep track of when multiple dependencies are satisfied,
1029         * but removing each dependency as it is satisfied. We do not want to remove
1030         * the dependency itself from the list, because we need to retain that information
1031         * if the AnimatorSet is launched in the future. So we create a copy of the dependency
1032         * list when the AnimatorSet starts and use this tmpDependencies list to track the
1033         * list of satisfied dependencies.
1034         */
1035        public ArrayList<Dependency> tmpDependencies = null;
1036
1037        /**
1038         * nodeDependencies is just a list of the nodes that this Node is dependent upon.
1039         * This information is used in sortNodes(), to determine when a node is a root.
1040         */
1041        public ArrayList<Node> nodeDependencies = null;
1042
1043        /**
1044         * nodeDepdendents is the list of nodes that have this node as a dependency. This
1045         * is a utility field used in sortNodes to facilitate removing this node as a
1046         * dependency when it is a root node.
1047         */
1048        public ArrayList<Node> nodeDependents = null;
1049
1050        /**
1051         * Flag indicating whether the animation in this node is finished. This flag
1052         * is used by AnimatorSet to check, as each animation ends, whether all child animations
1053         * are done and it's time to send out an end event for the entire AnimatorSet.
1054         */
1055        public boolean done = false;
1056
1057        /**
1058         * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
1059         */
1060        private Node mTmpClone = null;
1061
1062        /**
1063         * Constructs the Node with the animation that it encapsulates. A Node has no
1064         * dependencies by default; dependencies are added via the addDependency()
1065         * method.
1066         *
1067         * @param animation The animation that the Node encapsulates.
1068         */
1069        public Node(Animator animation) {
1070            this.animation = animation;
1071        }
1072
1073        /**
1074         * Add a dependency to this Node. The dependency includes information about the
1075         * node that this node is dependency upon and the nature of the dependency.
1076         * @param dependency
1077         */
1078        public void addDependency(Dependency dependency) {
1079            if (dependencies == null) {
1080                dependencies = new ArrayList<Dependency>();
1081                nodeDependencies = new ArrayList<Node>();
1082            }
1083            dependencies.add(dependency);
1084            if (!nodeDependencies.contains(dependency.node)) {
1085                nodeDependencies.add(dependency.node);
1086            }
1087            Node dependencyNode = dependency.node;
1088            if (dependencyNode.nodeDependents == null) {
1089                dependencyNode.nodeDependents = new ArrayList<Node>();
1090            }
1091            dependencyNode.nodeDependents.add(this);
1092        }
1093
1094        @Override
1095        public Node clone() {
1096            try {
1097                Node node = (Node) super.clone();
1098                node.animation = (Animator) animation.clone();
1099                return node;
1100            } catch (CloneNotSupportedException e) {
1101               throw new AssertionError();
1102            }
1103        }
1104    }
1105
1106    /**
1107     * The <code>Builder</code> object is a utility class to facilitate adding animations to a
1108     * <code>AnimatorSet</code> along with the relationships between the various animations. The
1109     * intention of the <code>Builder</code> methods, along with the {@link
1110     * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible
1111     * to express the dependency relationships of animations in a natural way. Developers can also
1112     * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
1113     * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
1114     * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
1115     * <p/>
1116     * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
1117     * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
1118     * <p/>
1119     * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
1120     * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
1121     * <pre>
1122     *     AnimatorSet s = new AnimatorSet();
1123     *     s.play(anim1).with(anim2);
1124     *     s.play(anim2).before(anim3);
1125     *     s.play(anim4).after(anim3);
1126     * </pre>
1127     * <p/>
1128     * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
1129     * Builder#after(Animator)} are used. These are just different ways of expressing the same
1130     * relationship and are provided to make it easier to say things in a way that is more natural,
1131     * depending on the situation.</p>
1132     * <p/>
1133     * <p>It is possible to make several calls into the same <code>Builder</code> object to express
1134     * multiple relationships. However, note that it is only the animation passed into the initial
1135     * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
1136     * calls to the <code>Builder</code> object. For example, the following code starts both anim2
1137     * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
1138     * anim3:
1139     * <pre>
1140     *   AnimatorSet s = new AnimatorSet();
1141     *   s.play(anim1).before(anim2).before(anim3);
1142     * </pre>
1143     * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
1144     * relationship correctly:</p>
1145     * <pre>
1146     *   AnimatorSet s = new AnimatorSet();
1147     *   s.play(anim1).before(anim2);
1148     *   s.play(anim2).before(anim3);
1149     * </pre>
1150     * <p/>
1151     * <p>Note that it is possible to express relationships that cannot be resolved and will not
1152     * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
1153     * sense. In general, circular dependencies like this one (or more indirect ones where a depends
1154     * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
1155     * that can boil down to a simple, one-way relationship of animations starting with, before, and
1156     * after other, different, animations.</p>
1157     */
1158    public class Builder {
1159
1160        /**
1161         * This tracks the current node being processed. It is supplied to the play() method
1162         * of AnimatorSet and passed into the constructor of Builder.
1163         */
1164        private Node mCurrentNode;
1165
1166        /**
1167         * package-private constructor. Builders are only constructed by AnimatorSet, when the
1168         * play() method is called.
1169         *
1170         * @param anim The animation that is the dependency for the other animations passed into
1171         * the other methods of this Builder object.
1172         */
1173        Builder(Animator anim) {
1174            mCurrentNode = mNodeMap.get(anim);
1175            if (mCurrentNode == null) {
1176                mCurrentNode = new Node(anim);
1177                mNodeMap.put(anim, mCurrentNode);
1178                mNodes.add(mCurrentNode);
1179            }
1180        }
1181
1182        /**
1183         * Sets up the given animation to play at the same time as the animation supplied in the
1184         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
1185         *
1186         * @param anim The animation that will play when the animation supplied to the
1187         * {@link AnimatorSet#play(Animator)} method starts.
1188         */
1189        public Builder with(Animator anim) {
1190            Node node = mNodeMap.get(anim);
1191            if (node == null) {
1192                node = new Node(anim);
1193                mNodeMap.put(anim, node);
1194                mNodes.add(node);
1195            }
1196            Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
1197            node.addDependency(dependency);
1198            return this;
1199        }
1200
1201        /**
1202         * Sets up the given animation to play when the animation supplied in the
1203         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1204         * ends.
1205         *
1206         * @param anim The animation that will play when the animation supplied to the
1207         * {@link AnimatorSet#play(Animator)} method ends.
1208         */
1209        public Builder before(Animator anim) {
1210            mReversible = false;
1211            Node node = mNodeMap.get(anim);
1212            if (node == null) {
1213                node = new Node(anim);
1214                mNodeMap.put(anim, node);
1215                mNodes.add(node);
1216            }
1217            Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
1218            node.addDependency(dependency);
1219            return this;
1220        }
1221
1222        /**
1223         * Sets up the given animation to play when the animation supplied in the
1224         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1225         * to start when the animation supplied in this method call ends.
1226         *
1227         * @param anim The animation whose end will cause the animation supplied to the
1228         * {@link AnimatorSet#play(Animator)} method to play.
1229         */
1230        public Builder after(Animator anim) {
1231            mReversible = false;
1232            Node node = mNodeMap.get(anim);
1233            if (node == null) {
1234                node = new Node(anim);
1235                mNodeMap.put(anim, node);
1236                mNodes.add(node);
1237            }
1238            Dependency dependency = new Dependency(node, Dependency.AFTER);
1239            mCurrentNode.addDependency(dependency);
1240            return this;
1241        }
1242
1243        /**
1244         * Sets up the animation supplied in the
1245         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1246         * to play when the given amount of time elapses.
1247         *
1248         * @param delay The number of milliseconds that should elapse before the
1249         * animation starts.
1250         */
1251        public Builder after(long delay) {
1252            // setup dummy ValueAnimator just to run the clock
1253            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
1254            anim.setDuration(delay);
1255            after(anim);
1256            return this;
1257        }
1258
1259    }
1260
1261}
1262