AnimatorSet.java revision d7444427d9f44b6b7448d4c21edca866132c8b59
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.animation;
18
19import android.util.ArrayMap;
20
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.List;
24
25/**
26 * This class plays a set of {@link Animator} objects in the specified order. Animations
27 * can be set up to play together, in sequence, or after a specified delay.
28 *
29 * <p>There are two different approaches to adding animations to a <code>AnimatorSet</code>:
30 * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or
31 * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add
32 * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be
33 * used in conjunction with methods in the {@link AnimatorSet.Builder Builder}
34 * class to add animations
35 * one by one.</p>
36 *
37 * <p>It is possible to set up a <code>AnimatorSet</code> with circular dependencies between
38 * its animations. For example, an animation a1 could be set up to start before animation a2, a2
39 * before a3, and a3 before a1. The results of this configuration are undefined, but will typically
40 * result in none of the affected animations being played. Because of this (and because
41 * circular dependencies do not make logical sense anyway), circular dependencies
42 * should be avoided, and the dependency flow of animations should only be in one direction.
43 *
44 * <div class="special reference">
45 * <h3>Developer Guides</h3>
46 * <p>For more information about animating with {@code AnimatorSet}, read the
47 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#choreography">Property
48 * Animation</a> developer guide.</p>
49 * </div>
50 */
51public final class AnimatorSet extends Animator {
52
53    /**
54     * Internal variables
55     * NOTE: This object implements the clone() method, making a deep copy of any referenced
56     * objects. As other non-trivial fields are added to this class, make sure to add logic
57     * to clone() to make deep copies of them.
58     */
59
60    /**
61     * Tracks animations currently being played, so that we know what to
62     * cancel or end when cancel() or end() is called on this AnimatorSet
63     */
64    private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>();
65
66    /**
67     * Contains all nodes, mapped to their respective Animators. When new
68     * dependency information is added for an Animator, we want to add it
69     * to a single node representing that Animator, not create a new Node
70     * if one already exists.
71     */
72    private ArrayMap<Animator, Node> mNodeMap = new ArrayMap<Animator, Node>();
73
74    /**
75     * Set of all nodes created for this AnimatorSet. This list is used upon
76     * starting the set, and the nodes are placed in sorted order into the
77     * sortedNodes collection.
78     */
79    private ArrayList<Node> mNodes = new ArrayList<Node>();
80
81    /**
82     * The sorted list of nodes. This is the order in which the animations will
83     * be played. The details about when exactly they will be played depend
84     * on the dependency relationships of the nodes.
85     */
86    private ArrayList<Node> mSortedNodes = new ArrayList<Node>();
87
88    /**
89     * Flag indicating whether the nodes should be sorted prior to playing. This
90     * flag allows us to cache the previous sorted nodes so that if the sequence
91     * is replayed with no changes, it does not have to re-sort the nodes again.
92     */
93    private boolean mNeedsSort = true;
94
95    private AnimatorSetListener mSetListener = null;
96
97    /**
98     * Flag indicating that the AnimatorSet has been manually
99     * terminated (by calling cancel() or end()).
100     * This flag is used to avoid starting other animations when currently-playing
101     * child animations of this AnimatorSet end. It also determines whether cancel/end
102     * notifications are sent out via the normal AnimatorSetListener mechanism.
103     */
104    boolean mTerminated = false;
105
106    /**
107     * Indicates whether an AnimatorSet has been start()'d, whether or
108     * not there is a nonzero startDelay.
109     */
110    private boolean mStarted = false;
111
112    // The amount of time in ms to delay starting the animation after start() is called
113    private long mStartDelay = 0;
114
115    // Animator used for a nonzero startDelay
116    private ValueAnimator mDelayAnim = null;
117
118
119    // How long the child animations should last in ms. The default value is negative, which
120    // simply means that there is no duration set on the AnimatorSet. When a real duration is
121    // set, it is passed along to the child animations.
122    private long mDuration = -1;
123
124    // Records the interpolator for the set. Null value indicates that no interpolator
125    // was set on this AnimatorSet, so it should not be passed down to the children.
126    private TimeInterpolator mInterpolator = null;
127
128    private boolean mReversible = true;
129    /**
130     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
131     * This is equivalent to calling {@link #play(Animator)} with the first animator in the
132     * set and then {@link Builder#with(Animator)} with each of the other animators. Note that
133     * an Animator with a {@link Animator#setStartDelay(long) startDelay} will not actually
134     * start until that delay elapses, which means that if the first animator in the list
135     * supplied to this constructor has a startDelay, none of the other animators will start
136     * until that first animator's startDelay has elapsed.
137     *
138     * @param items The animations that will be started simultaneously.
139     */
140    public void playTogether(Animator... items) {
141        if (items != null) {
142            mNeedsSort = true;
143            Builder builder = play(items[0]);
144            for (int i = 1; i < items.length; ++i) {
145                builder.with(items[i]);
146            }
147        }
148    }
149
150    /**
151     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
152     *
153     * @param items The animations that will be started simultaneously.
154     */
155    public void playTogether(Collection<Animator> items) {
156        if (items != null && items.size() > 0) {
157            mNeedsSort = true;
158            Builder builder = null;
159            for (Animator anim : items) {
160                if (builder == null) {
161                    builder = play(anim);
162                } else {
163                    builder.with(anim);
164                }
165            }
166        }
167    }
168
169    /**
170     * Sets up this AnimatorSet to play each of the supplied animations when the
171     * previous animation ends.
172     *
173     * @param items The animations that will be started one after another.
174     */
175    public void playSequentially(Animator... items) {
176        if (items != null) {
177            mNeedsSort = true;
178            if (items.length == 1) {
179                play(items[0]);
180            } else {
181                mReversible = false;
182                for (int i = 0; i < items.length - 1; ++i) {
183                    play(items[i]).before(items[i+1]);
184                }
185            }
186        }
187    }
188
189    /**
190     * Sets up this AnimatorSet to play each of the supplied animations when the
191     * previous animation ends.
192     *
193     * @param items The animations that will be started one after another.
194     */
195    public void playSequentially(List<Animator> items) {
196        if (items != null && items.size() > 0) {
197            mNeedsSort = true;
198            if (items.size() == 1) {
199                play(items.get(0));
200            } else {
201                mReversible = false;
202                for (int i = 0; i < items.size() - 1; ++i) {
203                    play(items.get(i)).before(items.get(i+1));
204                }
205            }
206        }
207    }
208
209    /**
210     * Returns the current list of child Animator objects controlled by this
211     * AnimatorSet. This is a copy of the internal list; modifications to the returned list
212     * will not affect the AnimatorSet, although changes to the underlying Animator objects
213     * will affect those objects being managed by the AnimatorSet.
214     *
215     * @return ArrayList<Animator> The list of child animations of this AnimatorSet.
216     */
217    public ArrayList<Animator> getChildAnimations() {
218        ArrayList<Animator> childList = new ArrayList<Animator>();
219        for (Node node : mNodes) {
220            childList.add(node.animation);
221        }
222        return childList;
223    }
224
225    /**
226     * Sets the target object for all current {@link #getChildAnimations() child animations}
227     * of this AnimatorSet that take targets ({@link ObjectAnimator} and
228     * AnimatorSet).
229     *
230     * @param target The object being animated
231     */
232    @Override
233    public void setTarget(Object target) {
234        for (Node node : mNodes) {
235            Animator animation = node.animation;
236            if (animation instanceof AnimatorSet) {
237                ((AnimatorSet)animation).setTarget(target);
238            } else if (animation instanceof ObjectAnimator) {
239                ((ObjectAnimator)animation).setTarget(target);
240            }
241        }
242    }
243
244    /**
245     * @hide
246     */
247    @Override
248    public int getChangingConfigurations() {
249        int conf = super.getChangingConfigurations();
250        final int nodeCount = mNodes.size();
251        for (int i = 0; i < nodeCount; i ++) {
252            conf |= mNodes.get(i).animation.getChangingConfigurations();
253        }
254        return conf;
255    }
256
257    /**
258     * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
259     * of this AnimatorSet. The default value is null, which means that no interpolator
260     * is set on this AnimatorSet. Setting the interpolator to any non-null value
261     * will cause that interpolator to be set on the child animations
262     * when the set is started.
263     *
264     * @param interpolator the interpolator to be used by each child animation of this AnimatorSet
265     */
266    @Override
267    public void setInterpolator(TimeInterpolator interpolator) {
268        mInterpolator = interpolator;
269    }
270
271    @Override
272    public TimeInterpolator getInterpolator() {
273        return mInterpolator;
274    }
275
276    /**
277     * This method creates a <code>Builder</code> object, which is used to
278     * set up playing constraints. This initial <code>play()</code> method
279     * tells the <code>Builder</code> the animation that is the dependency for
280     * the succeeding commands to the <code>Builder</code>. For example,
281     * calling <code>play(a1).with(a2)</code> sets up the AnimatorSet to play
282     * <code>a1</code> and <code>a2</code> at the same time,
283     * <code>play(a1).before(a2)</code> sets up the AnimatorSet to play
284     * <code>a1</code> first, followed by <code>a2</code>, and
285     * <code>play(a1).after(a2)</code> sets up the AnimatorSet to play
286     * <code>a2</code> first, followed by <code>a1</code>.
287     *
288     * <p>Note that <code>play()</code> is the only way to tell the
289     * <code>Builder</code> the animation upon which the dependency is created,
290     * so successive calls to the various functions in <code>Builder</code>
291     * will all refer to the initial parameter supplied in <code>play()</code>
292     * as the dependency of the other animations. For example, calling
293     * <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code>
294     * and <code>a3</code> when a1 ends; it does not set up a dependency between
295     * <code>a2</code> and <code>a3</code>.</p>
296     *
297     * @param anim The animation that is the dependency used in later calls to the
298     * methods in the returned <code>Builder</code> object. A null parameter will result
299     * in a null <code>Builder</code> return value.
300     * @return Builder The object that constructs the AnimatorSet based on the dependencies
301     * outlined in the calls to <code>play</code> and the other methods in the
302     * <code>Builder</code object.
303     */
304    public Builder play(Animator anim) {
305        if (anim != null) {
306            mNeedsSort = true;
307            return new Builder(anim);
308        }
309        return null;
310    }
311
312    /**
313     * {@inheritDoc}
314     *
315     * <p>Note that canceling a <code>AnimatorSet</code> also cancels all of the animations that it
316     * is responsible for.</p>
317     */
318    @SuppressWarnings("unchecked")
319    @Override
320    public void cancel() {
321        mTerminated = true;
322        if (isStarted()) {
323            ArrayList<AnimatorListener> tmpListeners = null;
324            if (mListeners != null) {
325                tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
326                for (AnimatorListener listener : tmpListeners) {
327                    listener.onAnimationCancel(this);
328                }
329            }
330            if (mDelayAnim != null && mDelayAnim.isRunning()) {
331                // If we're currently in the startDelay period, just cancel that animator and
332                // send out the end event to all listeners
333                mDelayAnim.cancel();
334            } else  if (mSortedNodes.size() > 0) {
335                for (Node node : mSortedNodes) {
336                    node.animation.cancel();
337                }
338            }
339            if (tmpListeners != null) {
340                for (AnimatorListener listener : tmpListeners) {
341                    listener.onAnimationEnd(this);
342                }
343            }
344            mStarted = false;
345        }
346    }
347
348    /**
349     * {@inheritDoc}
350     *
351     * <p>Note that ending a <code>AnimatorSet</code> also ends all of the animations that it is
352     * responsible for.</p>
353     */
354    @Override
355    public void end() {
356        mTerminated = true;
357        if (isStarted()) {
358            if (mSortedNodes.size() != mNodes.size()) {
359                // hasn't been started yet - sort the nodes now, then end them
360                sortNodes();
361                for (Node node : mSortedNodes) {
362                    if (mSetListener == null) {
363                        mSetListener = new AnimatorSetListener(this);
364                    }
365                    node.animation.addListener(mSetListener);
366                }
367            }
368            if (mDelayAnim != null) {
369                mDelayAnim.cancel();
370            }
371            if (mSortedNodes.size() > 0) {
372                for (Node node : mSortedNodes) {
373                    node.animation.end();
374                }
375            }
376            if (mListeners != null) {
377                ArrayList<AnimatorListener> tmpListeners =
378                        (ArrayList<AnimatorListener>) mListeners.clone();
379                for (AnimatorListener listener : tmpListeners) {
380                    listener.onAnimationEnd(this);
381                }
382            }
383            mStarted = false;
384        }
385    }
386
387    /**
388     * Returns true if any of the child animations of this AnimatorSet have been started and have
389     * not yet ended.
390     * @return Whether this AnimatorSet has been started and has not yet ended.
391     */
392    @Override
393    public boolean isRunning() {
394        for (Node node : mNodes) {
395            if (node.animation.isRunning()) {
396                return true;
397            }
398        }
399        return false;
400    }
401
402    @Override
403    public boolean isStarted() {
404        return mStarted;
405    }
406
407    /**
408     * The amount of time, in milliseconds, to delay starting the animation after
409     * {@link #start()} is called.
410     *
411     * @return the number of milliseconds to delay running the animation
412     */
413    @Override
414    public long getStartDelay() {
415        return mStartDelay;
416    }
417
418    /**
419     * The amount of time, in milliseconds, to delay starting the animation after
420     * {@link #start()} is called.
421
422     * @param startDelay The amount of the delay, in milliseconds
423     */
424    @Override
425    public void setStartDelay(long startDelay) {
426        if (mStartDelay > 0) {
427            mReversible = false;
428        }
429        mStartDelay = startDelay;
430    }
431
432    /**
433     * Gets the length of each of the child animations of this AnimatorSet. This value may
434     * be less than 0, which indicates that no duration has been set on this AnimatorSet
435     * and each of the child animations will use their own duration.
436     *
437     * @return The length of the animation, in milliseconds, of each of the child
438     * animations of this AnimatorSet.
439     */
440    @Override
441    public long getDuration() {
442        return mDuration;
443    }
444
445    /**
446     * Sets the length of each of the current child animations of this AnimatorSet. By default,
447     * each child animation will use its own duration. If the duration is set on the AnimatorSet,
448     * then each child animation inherits this duration.
449     *
450     * @param duration The length of the animation, in milliseconds, of each of the child
451     * animations of this AnimatorSet.
452     */
453    @Override
454    public AnimatorSet setDuration(long duration) {
455        if (duration < 0) {
456            throw new IllegalArgumentException("duration must be a value of zero or greater");
457        }
458        // Just record the value for now - it will be used later when the AnimatorSet starts
459        mDuration = duration;
460        return this;
461    }
462
463    @Override
464    public void setupStartValues() {
465        for (Node node : mNodes) {
466            node.animation.setupStartValues();
467        }
468    }
469
470    @Override
471    public void setupEndValues() {
472        for (Node node : mNodes) {
473            node.animation.setupEndValues();
474        }
475    }
476
477    @Override
478    public void pause() {
479        boolean previouslyPaused = mPaused;
480        super.pause();
481        if (!previouslyPaused && mPaused) {
482            if (mDelayAnim != null) {
483                mDelayAnim.pause();
484            } else {
485                for (Node node : mNodes) {
486                    node.animation.pause();
487                }
488            }
489        }
490    }
491
492    @Override
493    public void resume() {
494        boolean previouslyPaused = mPaused;
495        super.resume();
496        if (previouslyPaused && !mPaused) {
497            if (mDelayAnim != null) {
498                mDelayAnim.resume();
499            } else {
500                for (Node node : mNodes) {
501                    node.animation.resume();
502                }
503            }
504        }
505    }
506
507    /**
508     * {@inheritDoc}
509     *
510     * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which
511     * it is responsible. The details of when exactly those animations are started depends on
512     * the dependency relationships that have been set up between the animations.
513     */
514    @SuppressWarnings("unchecked")
515    @Override
516    public void start() {
517        mTerminated = false;
518        mStarted = true;
519        mPaused = false;
520
521        for (Node node : mNodes) {
522            node.animation.setAllowRunningAsynchronously(false);
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 ArrayMap<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 = animation.clone();
1099                node.done = false;
1100                return node;
1101            } catch (CloneNotSupportedException e) {
1102               throw new AssertionError();
1103            }
1104        }
1105    }
1106
1107    /**
1108     * The <code>Builder</code> object is a utility class to facilitate adding animations to a
1109     * <code>AnimatorSet</code> along with the relationships between the various animations. The
1110     * intention of the <code>Builder</code> methods, along with the {@link
1111     * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible
1112     * to express the dependency relationships of animations in a natural way. Developers can also
1113     * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
1114     * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
1115     * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
1116     * <p/>
1117     * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
1118     * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
1119     * <p/>
1120     * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
1121     * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
1122     * <pre>
1123     *     AnimatorSet s = new AnimatorSet();
1124     *     s.play(anim1).with(anim2);
1125     *     s.play(anim2).before(anim3);
1126     *     s.play(anim4).after(anim3);
1127     * </pre>
1128     * <p/>
1129     * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
1130     * Builder#after(Animator)} are used. These are just different ways of expressing the same
1131     * relationship and are provided to make it easier to say things in a way that is more natural,
1132     * depending on the situation.</p>
1133     * <p/>
1134     * <p>It is possible to make several calls into the same <code>Builder</code> object to express
1135     * multiple relationships. However, note that it is only the animation passed into the initial
1136     * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
1137     * calls to the <code>Builder</code> object. For example, the following code starts both anim2
1138     * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
1139     * anim3:
1140     * <pre>
1141     *   AnimatorSet s = new AnimatorSet();
1142     *   s.play(anim1).before(anim2).before(anim3);
1143     * </pre>
1144     * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
1145     * relationship correctly:</p>
1146     * <pre>
1147     *   AnimatorSet s = new AnimatorSet();
1148     *   s.play(anim1).before(anim2);
1149     *   s.play(anim2).before(anim3);
1150     * </pre>
1151     * <p/>
1152     * <p>Note that it is possible to express relationships that cannot be resolved and will not
1153     * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
1154     * sense. In general, circular dependencies like this one (or more indirect ones where a depends
1155     * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
1156     * that can boil down to a simple, one-way relationship of animations starting with, before, and
1157     * after other, different, animations.</p>
1158     */
1159    public class Builder {
1160
1161        /**
1162         * This tracks the current node being processed. It is supplied to the play() method
1163         * of AnimatorSet and passed into the constructor of Builder.
1164         */
1165        private Node mCurrentNode;
1166
1167        /**
1168         * package-private constructor. Builders are only constructed by AnimatorSet, when the
1169         * play() method is called.
1170         *
1171         * @param anim The animation that is the dependency for the other animations passed into
1172         * the other methods of this Builder object.
1173         */
1174        Builder(Animator anim) {
1175            mCurrentNode = mNodeMap.get(anim);
1176            if (mCurrentNode == null) {
1177                mCurrentNode = new Node(anim);
1178                mNodeMap.put(anim, mCurrentNode);
1179                mNodes.add(mCurrentNode);
1180            }
1181        }
1182
1183        /**
1184         * Sets up the given animation to play at the same time as the animation supplied in the
1185         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
1186         *
1187         * @param anim The animation that will play when the animation supplied to the
1188         * {@link AnimatorSet#play(Animator)} method starts.
1189         */
1190        public Builder with(Animator anim) {
1191            Node node = mNodeMap.get(anim);
1192            if (node == null) {
1193                node = new Node(anim);
1194                mNodeMap.put(anim, node);
1195                mNodes.add(node);
1196            }
1197            Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
1198            node.addDependency(dependency);
1199            return this;
1200        }
1201
1202        /**
1203         * Sets up the given animation to play when the animation supplied in the
1204         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1205         * ends.
1206         *
1207         * @param anim The animation that will play when the animation supplied to the
1208         * {@link AnimatorSet#play(Animator)} method ends.
1209         */
1210        public Builder before(Animator anim) {
1211            mReversible = false;
1212            Node node = mNodeMap.get(anim);
1213            if (node == null) {
1214                node = new Node(anim);
1215                mNodeMap.put(anim, node);
1216                mNodes.add(node);
1217            }
1218            Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
1219            node.addDependency(dependency);
1220            return this;
1221        }
1222
1223        /**
1224         * Sets up the given animation to play when the animation supplied in the
1225         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1226         * to start when the animation supplied in this method call ends.
1227         *
1228         * @param anim The animation whose end will cause the animation supplied to the
1229         * {@link AnimatorSet#play(Animator)} method to play.
1230         */
1231        public Builder after(Animator anim) {
1232            mReversible = false;
1233            Node node = mNodeMap.get(anim);
1234            if (node == null) {
1235                node = new Node(anim);
1236                mNodeMap.put(anim, node);
1237                mNodes.add(node);
1238            }
1239            Dependency dependency = new Dependency(node, Dependency.AFTER);
1240            mCurrentNode.addDependency(dependency);
1241            return this;
1242        }
1243
1244        /**
1245         * Sets up the animation supplied in the
1246         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1247         * to play when the given amount of time elapses.
1248         *
1249         * @param delay The number of milliseconds that should elapse before the
1250         * animation starts.
1251         */
1252        public Builder after(long delay) {
1253            // setup dummy ValueAnimator just to run the clock
1254            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
1255            anim.setDuration(delay);
1256            after(anim);
1257            return this;
1258        }
1259
1260    }
1261
1262}
1263