AnimatorSet.java revision c4bb185d41cfb960ed9a3178a4f8974c351abdb0
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;
20import android.util.Log;
21
22import java.util.ArrayList;
23import java.util.Collection;
24import java.util.List;
25
26/**
27 * This class plays a set of {@link Animator} objects in the specified order. Animations
28 * can be set up to play together, in sequence, or after a specified delay.
29 *
30 * <p>There are two different approaches to adding animations to a <code>AnimatorSet</code>:
31 * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or
32 * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add
33 * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be
34 * used in conjunction with methods in the {@link AnimatorSet.Builder Builder}
35 * class to add animations
36 * one by one.</p>
37 *
38 * <p>It is possible to set up a <code>AnimatorSet</code> with circular dependencies between
39 * its animations. For example, an animation a1 could be set up to start before animation a2, a2
40 * before a3, and a3 before a1. The results of this configuration are undefined, but will typically
41 * result in none of the affected animations being played. Because of this (and because
42 * circular dependencies do not make logical sense anyway), circular dependencies
43 * should be avoided, and the dependency flow of animations should only be in one direction.
44 *
45 * <div class="special reference">
46 * <h3>Developer Guides</h3>
47 * <p>For more information about animating with {@code AnimatorSet}, read the
48 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#choreography">Property
49 * Animation</a> developer guide.</p>
50 * </div>
51 */
52public final class AnimatorSet extends Animator {
53
54    private static final String TAG = "AnimatorSet";
55    /**
56     * Internal variables
57     * NOTE: This object implements the clone() method, making a deep copy of any referenced
58     * objects. As other non-trivial fields are added to this class, make sure to add logic
59     * to clone() to make deep copies of them.
60     */
61
62    /**
63     * Tracks animations currently being played, so that we know what to
64     * cancel or end when cancel() or end() is called on this AnimatorSet
65     */
66    private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>();
67
68    /**
69     * Contains all nodes, mapped to their respective Animators. When new
70     * dependency information is added for an Animator, we want to add it
71     * to a single node representing that Animator, not create a new Node
72     * if one already exists.
73     */
74    private ArrayMap<Animator, Node> mNodeMap = new ArrayMap<Animator, Node>();
75
76    /**
77     * Set of all nodes created for this AnimatorSet. This list is used upon
78     * starting the set, and the nodes are placed in sorted order into the
79     * sortedNodes collection.
80     */
81    private ArrayList<Node> mNodes = new ArrayList<Node>();
82
83    /**
84     * Animator Listener that tracks the lifecycle of each Animator in the set. It will be added
85     * to each Animator before they start and removed after they end.
86     */
87    private AnimatorSetListener mSetListener = new AnimatorSetListener(this);
88
89    /**
90     * Flag indicating that the AnimatorSet has been manually
91     * terminated (by calling cancel() or end()).
92     * This flag is used to avoid starting other animations when currently-playing
93     * child animations of this AnimatorSet end. It also determines whether cancel/end
94     * notifications are sent out via the normal AnimatorSetListener mechanism.
95     */
96    private boolean mTerminated = false;
97
98    /**
99     * Tracks whether any change has been made to the AnimatorSet, which is then used to
100     * determine whether the dependency graph should be re-constructed.
101     */
102    private boolean mDependencyDirty = false;
103
104    /**
105     * Indicates whether an AnimatorSet has been start()'d, whether or
106     * not there is a nonzero startDelay.
107     */
108    private boolean mStarted = false;
109
110    // The amount of time in ms to delay starting the animation after start() is called
111    private long mStartDelay = 0;
112
113    // Animator used for a nonzero startDelay
114    private ValueAnimator mDelayAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(0);
115
116    // Root of the dependency tree of all the animators in the set. In this tree, parent-child
117    // relationship captures the order of animation (i.e. parent and child will play sequentially),
118    // and sibling relationship indicates "with" relationship, as sibling animators start at the
119    // same time.
120    private Node mRootNode = new Node(mDelayAnim);
121
122    // How long the child animations should last in ms. The default value is negative, which
123    // simply means that there is no duration set on the AnimatorSet. When a real duration is
124    // set, it is passed along to the child animations.
125    private long mDuration = -1;
126
127    // Records the interpolator for the set. Null value indicates that no interpolator
128    // was set on this AnimatorSet, so it should not be passed down to the children.
129    private TimeInterpolator mInterpolator = null;
130
131    // Whether the AnimatorSet can be reversed.
132    private boolean mReversible = true;
133    // The total duration of finishing all the Animators in the set.
134    private long mTotalDuration = 0;
135
136    public AnimatorSet() {
137        super();
138        mNodeMap.put(mDelayAnim, mRootNode);
139        mNodes.add(mRootNode);
140    }
141
142    /**
143     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
144     * This is equivalent to calling {@link #play(Animator)} with the first animator in the
145     * set and then {@link Builder#with(Animator)} with each of the other animators. Note that
146     * an Animator with a {@link Animator#setStartDelay(long) startDelay} will not actually
147     * start until that delay elapses, which means that if the first animator in the list
148     * supplied to this constructor has a startDelay, none of the other animators will start
149     * until that first animator's startDelay has elapsed.
150     *
151     * @param items The animations that will be started simultaneously.
152     */
153    public void playTogether(Animator... items) {
154        if (items != null) {
155            Builder builder = play(items[0]);
156            for (int i = 1; i < items.length; ++i) {
157                builder.with(items[i]);
158            }
159        }
160    }
161
162    /**
163     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
164     *
165     * @param items The animations that will be started simultaneously.
166     */
167    public void playTogether(Collection<Animator> items) {
168        if (items != null && items.size() > 0) {
169            Builder builder = null;
170            for (Animator anim : items) {
171                if (builder == null) {
172                    builder = play(anim);
173                } else {
174                    builder.with(anim);
175                }
176            }
177        }
178    }
179
180    /**
181     * Sets up this AnimatorSet to play each of the supplied animations when the
182     * previous animation ends.
183     *
184     * @param items The animations that will be started one after another.
185     */
186    public void playSequentially(Animator... items) {
187        if (items != null) {
188            if (items.length == 1) {
189                play(items[0]);
190            } else {
191                mReversible = false;
192                for (int i = 0; i < items.length - 1; ++i) {
193                    play(items[i]).before(items[i + 1]);
194                }
195            }
196        }
197    }
198
199    /**
200     * Sets up this AnimatorSet to play each of the supplied animations when the
201     * previous animation ends.
202     *
203     * @param items The animations that will be started one after another.
204     */
205    public void playSequentially(List<Animator> items) {
206        if (items != null && items.size() > 0) {
207            if (items.size() == 1) {
208                play(items.get(0));
209            } else {
210                mReversible = false;
211                for (int i = 0; i < items.size() - 1; ++i) {
212                    play(items.get(i)).before(items.get(i + 1));
213                }
214            }
215        }
216    }
217
218    /**
219     * Returns the current list of child Animator objects controlled by this
220     * AnimatorSet. This is a copy of the internal list; modifications to the returned list
221     * will not affect the AnimatorSet, although changes to the underlying Animator objects
222     * will affect those objects being managed by the AnimatorSet.
223     *
224     * @return ArrayList<Animator> The list of child animations of this AnimatorSet.
225     */
226    public ArrayList<Animator> getChildAnimations() {
227        ArrayList<Animator> childList = new ArrayList<Animator>();
228        int size = mNodes.size();
229        for (int i = 0; i < size; i++) {
230            Node node = mNodes.get(i);
231            if (node != mRootNode) {
232                childList.add(node.mAnimation);
233            }
234        }
235        return childList;
236    }
237
238    /**
239     * Sets the target object for all current {@link #getChildAnimations() child animations}
240     * of this AnimatorSet that take targets ({@link ObjectAnimator} and
241     * AnimatorSet).
242     *
243     * @param target The object being animated
244     */
245    @Override
246    public void setTarget(Object target) {
247        int size = mNodes.size();
248        for (int i = 0; i < size; i++) {
249            Node node = mNodes.get(i);
250            Animator animation = node.mAnimation;
251            if (animation instanceof AnimatorSet) {
252                ((AnimatorSet)animation).setTarget(target);
253            } else if (animation instanceof ObjectAnimator) {
254                ((ObjectAnimator)animation).setTarget(target);
255            }
256        }
257    }
258
259    /**
260     * @hide
261     */
262    @Override
263    public int getChangingConfigurations() {
264        int conf = super.getChangingConfigurations();
265        final int nodeCount = mNodes.size();
266        for (int i = 0; i < nodeCount; i ++) {
267            conf |= mNodes.get(i).mAnimation.getChangingConfigurations();
268        }
269        return conf;
270    }
271
272    /**
273     * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
274     * of this AnimatorSet. The default value is null, which means that no interpolator
275     * is set on this AnimatorSet. Setting the interpolator to any non-null value
276     * will cause that interpolator to be set on the child animations
277     * when the set is started.
278     *
279     * @param interpolator the interpolator to be used by each child animation of this AnimatorSet
280     */
281    @Override
282    public void setInterpolator(TimeInterpolator interpolator) {
283        mInterpolator = interpolator;
284    }
285
286    @Override
287    public TimeInterpolator getInterpolator() {
288        return mInterpolator;
289    }
290
291    /**
292     * This method creates a <code>Builder</code> object, which is used to
293     * set up playing constraints. This initial <code>play()</code> method
294     * tells the <code>Builder</code> the animation that is the dependency for
295     * the succeeding commands to the <code>Builder</code>. For example,
296     * calling <code>play(a1).with(a2)</code> sets up the AnimatorSet to play
297     * <code>a1</code> and <code>a2</code> at the same time,
298     * <code>play(a1).before(a2)</code> sets up the AnimatorSet to play
299     * <code>a1</code> first, followed by <code>a2</code>, and
300     * <code>play(a1).after(a2)</code> sets up the AnimatorSet to play
301     * <code>a2</code> first, followed by <code>a1</code>.
302     *
303     * <p>Note that <code>play()</code> is the only way to tell the
304     * <code>Builder</code> the animation upon which the dependency is created,
305     * so successive calls to the various functions in <code>Builder</code>
306     * will all refer to the initial parameter supplied in <code>play()</code>
307     * as the dependency of the other animations. For example, calling
308     * <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code>
309     * and <code>a3</code> when a1 ends; it does not set up a dependency between
310     * <code>a2</code> and <code>a3</code>.</p>
311     *
312     * @param anim The animation that is the dependency used in later calls to the
313     * methods in the returned <code>Builder</code> object. A null parameter will result
314     * in a null <code>Builder</code> return value.
315     * @return Builder The object that constructs the AnimatorSet based on the dependencies
316     * outlined in the calls to <code>play</code> and the other methods in the
317     * <code>Builder</code object.
318     */
319    public Builder play(Animator anim) {
320        if (anim != null) {
321            return new Builder(anim);
322        }
323        return null;
324    }
325
326    /**
327     * {@inheritDoc}
328     *
329     * <p>Note that canceling a <code>AnimatorSet</code> also cancels all of the animations that it
330     * is responsible for.</p>
331     */
332    @SuppressWarnings("unchecked")
333    @Override
334    public void cancel() {
335        mTerminated = true;
336        if (isStarted()) {
337            ArrayList<AnimatorListener> tmpListeners = null;
338            if (mListeners != null) {
339                tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
340                int size = tmpListeners.size();
341                for (int i = 0; i < size; i++) {
342                    tmpListeners.get(i).onAnimationCancel(this);
343                }
344            }
345            ArrayList<Animator> playingSet = new ArrayList<>(mPlayingSet);
346            int setSize = playingSet.size();
347            for (int i = 0; i < setSize; i++) {
348                playingSet.get(i).cancel();
349            }
350            if (tmpListeners != null) {
351                int size = tmpListeners.size();
352                for (int i = 0; i < size; i++) {
353                    tmpListeners.get(i).onAnimationEnd(this);
354                }
355            }
356            mStarted = false;
357        }
358    }
359
360    /**
361     * {@inheritDoc}
362     *
363     * <p>Note that ending a <code>AnimatorSet</code> also ends all of the animations that it is
364     * responsible for.</p>
365     */
366    @Override
367    public void end() {
368        mTerminated = true;
369        if (isStarted()) {
370            endRemainingAnimations();
371        }
372        if (mListeners != null) {
373            ArrayList<AnimatorListener> tmpListeners =
374                    (ArrayList<AnimatorListener>) mListeners.clone();
375            for (int i = 0; i < tmpListeners.size(); i++) {
376                tmpListeners.get(i).onAnimationEnd(this);
377            }
378        }
379        mStarted = false;
380    }
381
382    /**
383     * Iterate the animations that haven't finished or haven't started, and end them.
384     */
385    private void endRemainingAnimations() {
386        ArrayList<Animator> remainingList = new ArrayList<Animator>(mNodes.size());
387        remainingList.addAll(mPlayingSet);
388
389        int index = 0;
390        while (index < remainingList.size()) {
391            Animator anim = remainingList.get(index);
392            anim.end();
393            index++;
394            Node node = mNodeMap.get(anim);
395            if (node.mChildNodes != null) {
396                int childSize = node.mChildNodes.size();
397                for (int i = 0; i < childSize; i++) {
398                    Node child = node.mChildNodes.get(i);
399                    if (child.mLatestParent != node) {
400                        continue;
401                    }
402                    remainingList.add(child.mAnimation);
403                }
404            }
405        }
406    }
407
408
409    /**
410     * Returns true if any of the child animations of this AnimatorSet have been started and have
411     * not yet ended. Child animations will not be started until the AnimatorSet has gone past
412     * its initial delay set through {@link #setStartDelay(long)}.
413     *
414     * @return Whether this AnimatorSet has gone past the initial delay, and at least one child
415     *         animation has been started and not yet ended.
416     */
417    @Override
418    public boolean isRunning() {
419        int size = mNodes.size();
420        for (int i = 0; i < size; i++) {
421            Node node = mNodes.get(i);
422            if (node != mRootNode && node.mAnimation.isStarted()) {
423                return true;
424            }
425        }
426        return false;
427    }
428
429    @Override
430    public boolean isStarted() {
431        return mStarted;
432    }
433
434    /**
435     * The amount of time, in milliseconds, to delay starting the animation after
436     * {@link #start()} is called.
437     *
438     * @return the number of milliseconds to delay running the animation
439     */
440    @Override
441    public long getStartDelay() {
442        return mStartDelay;
443    }
444
445    /**
446     * The amount of time, in milliseconds, to delay starting the animation after
447     * {@link #start()} is called.
448
449     * @param startDelay The amount of the delay, in milliseconds
450     */
451    @Override
452    public void setStartDelay(long startDelay) {
453        if (mStartDelay > 0) {
454            mReversible = false;
455        }
456        long delta = startDelay - mStartDelay;
457        if (delta == 0) {
458            return;
459        }
460        mStartDelay = startDelay;
461        if (!mDependencyDirty) {
462            // Dependency graph already constructed, update all the nodes' start/end time
463            int size = mNodes.size();
464            for (int i = 0; i < size; i++) {
465                Node node = mNodes.get(i);
466                if (node == mRootNode) {
467                    node.mEndTime = mStartDelay;
468                } else {
469                    node.mStartTime = node.mStartTime == DURATION_INFINITE ?
470                            DURATION_INFINITE : node.mStartTime + delta;
471                    node.mEndTime = node.mEndTime == DURATION_INFINITE ?
472                            DURATION_INFINITE : node.mEndTime + delta;
473                }
474            }
475            // Update total duration, if necessary.
476            if (mTotalDuration != DURATION_INFINITE) {
477                mTotalDuration += delta;
478            }
479        }
480    }
481
482    /**
483     * Gets the length of each of the child animations of this AnimatorSet. This value may
484     * be less than 0, which indicates that no duration has been set on this AnimatorSet
485     * and each of the child animations will use their own duration.
486     *
487     * @return The length of the animation, in milliseconds, of each of the child
488     * animations of this AnimatorSet.
489     */
490    @Override
491    public long getDuration() {
492        return mDuration;
493    }
494
495    /**
496     * Sets the length of each of the current child animations of this AnimatorSet. By default,
497     * each child animation will use its own duration. If the duration is set on the AnimatorSet,
498     * then each child animation inherits this duration.
499     *
500     * @param duration The length of the animation, in milliseconds, of each of the child
501     * animations of this AnimatorSet.
502     */
503    @Override
504    public AnimatorSet setDuration(long duration) {
505        if (duration < 0) {
506            throw new IllegalArgumentException("duration must be a value of zero or greater");
507        }
508        mDependencyDirty = true;
509        // Just record the value for now - it will be used later when the AnimatorSet starts
510        mDuration = duration;
511        return this;
512    }
513
514    @Override
515    public void setupStartValues() {
516        int size = mNodes.size();
517        for (int i = 0; i < size; i++) {
518            Node node = mNodes.get(i);
519            if (node != mRootNode) {
520                node.mAnimation.setupStartValues();
521            }
522        }
523    }
524
525    @Override
526    public void setupEndValues() {
527        int size = mNodes.size();
528        for (int i = 0; i < size; i++) {
529            Node node = mNodes.get(i);
530            if (node != mRootNode) {
531                node.mAnimation.setupEndValues();
532            }
533        }
534    }
535
536    @Override
537    public void pause() {
538        boolean previouslyPaused = mPaused;
539        super.pause();
540        if (!previouslyPaused && mPaused) {
541            if (mDelayAnim != null) {
542                mDelayAnim.pause();
543            } else {
544                int size = mNodes.size();
545                for (int i = 0; i < size; i++) {
546                    Node node = mNodes.get(i);
547                    if (node != mRootNode) {
548                        node.mAnimation.pause();
549                    }
550                }
551            }
552        }
553    }
554
555    @Override
556    public void resume() {
557        boolean previouslyPaused = mPaused;
558        super.resume();
559        if (previouslyPaused && !mPaused) {
560            if (mDelayAnim != null) {
561                mDelayAnim.resume();
562            } else {
563                int size = mNodes.size();
564                for (int i = 0; i < size; i++) {
565                    Node node = mNodes.get(i);
566                    if (node != mRootNode) {
567                        node.mAnimation.resume();
568                    }
569                }
570            }
571        }
572    }
573
574    /**
575     * {@inheritDoc}
576     *
577     * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which
578     * it is responsible. The details of when exactly those animations are started depends on
579     * the dependency relationships that have been set up between the animations.
580     */
581    @SuppressWarnings("unchecked")
582    @Override
583    public void start() {
584        mTerminated = false;
585        mStarted = true;
586        mPaused = false;
587
588        int size = mNodes.size();
589        for (int i = 0; i < size; i++) {
590            Node node = mNodes.get(i);
591            node.mEnded = false;
592            node.mAnimation.setAllowRunningAsynchronously(false);
593        }
594
595        if (mInterpolator != null) {
596            for (int i = 0; i < size; i++) {
597                Node node = mNodes.get(i);
598                node.mAnimation.setInterpolator(mInterpolator);
599            }
600        }
601
602        updateAnimatorsDuration();
603        createDependencyGraph();
604
605        // Now that all dependencies are set up, start the animations that should be started.
606        boolean setIsEmpty = false;
607        if (mStartDelay > 0) {
608            start(mRootNode);
609        } else if (mNodes.size() > 1) {
610            // No delay, but there are other animators in the set
611            onChildAnimatorEnded(mDelayAnim);
612        } else {
613            // Set is empty, no delay, no other animation. Skip to end in this case
614            setIsEmpty = true;
615        }
616
617        if (mListeners != null) {
618            ArrayList<AnimatorListener> tmpListeners =
619                    (ArrayList<AnimatorListener>) mListeners.clone();
620            int numListeners = tmpListeners.size();
621            for (int i = 0; i < numListeners; ++i) {
622                tmpListeners.get(i).onAnimationStart(this);
623            }
624        }
625        if (setIsEmpty) {
626            // In the case of empty AnimatorSet, we will trigger the onAnimationEnd() right away.
627            onChildAnimatorEnded(mDelayAnim);
628        }
629    }
630
631    private void updateAnimatorsDuration() {
632        if (mDuration >= 0) {
633            // If the duration was set on this AnimatorSet, pass it along to all child animations
634            int size = mNodes.size();
635            for (int i = 0; i < size; i++) {
636                Node node = mNodes.get(i);
637                // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
638                // insert "play-after" delays
639                node.mAnimation.setDuration(mDuration);
640            }
641        }
642        mDelayAnim.setDuration(mStartDelay);
643    }
644
645    void start(final Node node) {
646        final Animator anim = node.mAnimation;
647        mPlayingSet.add(anim);
648        anim.addListener(mSetListener);
649        anim.start();
650    }
651
652    @Override
653    public AnimatorSet clone() {
654        final AnimatorSet anim = (AnimatorSet) super.clone();
655        /*
656         * The basic clone() operation copies all items. This doesn't work very well for
657         * AnimatorSet, because it will copy references that need to be recreated and state
658         * that may not apply. What we need to do now is put the clone in an uninitialized
659         * state, with fresh, empty data structures. Then we will build up the nodes list
660         * manually, as we clone each Node (and its animation). The clone will then be sorted,
661         * and will populate any appropriate lists, when it is started.
662         */
663        final int nodeCount = mNodes.size();
664        anim.mTerminated = false;
665        anim.mStarted = false;
666        anim.mPlayingSet = new ArrayList<Animator>();
667        anim.mNodeMap = new ArrayMap<Animator, Node>();
668        anim.mNodes = new ArrayList<Node>(nodeCount);
669        anim.mReversible = mReversible;
670        anim.mSetListener = new AnimatorSetListener(anim);
671
672        // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
673        // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
674        // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
675
676        for (int n = 0; n < nodeCount; n++) {
677            final Node node = mNodes.get(n);
678            Node nodeClone = node.clone();
679            node.mTmpClone = nodeClone;
680            anim.mNodes.add(nodeClone);
681            anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
682
683            // clear out any listeners that were set up by the AnimatorSet
684            final ArrayList<AnimatorListener> cloneListeners = nodeClone.mAnimation.getListeners();
685            if (cloneListeners != null) {
686                for (int i = cloneListeners.size() - 1; i >= 0; i--) {
687                    final AnimatorListener listener = cloneListeners.get(i);
688                    if (listener instanceof AnimatorSetListener) {
689                        cloneListeners.remove(i);
690                    }
691                }
692            }
693        }
694
695        anim.mRootNode = mRootNode.mTmpClone;
696        anim.mDelayAnim = (ValueAnimator) anim.mRootNode.mAnimation;
697
698        // Now that we've cloned all of the nodes, we're ready to walk through their
699        // dependencies, mapping the old dependencies to the new nodes
700        for (int i = 0; i < nodeCount; i++) {
701            Node node = mNodes.get(i);
702            // Update dependencies for node's clone
703            node.mTmpClone.mLatestParent = node.mLatestParent == null ?
704                    null : node.mLatestParent.mTmpClone;
705            int size = node.mChildNodes == null ? 0 : node.mChildNodes.size();
706            for (int j = 0; j < size; j++) {
707                node.mTmpClone.mChildNodes.set(j, node.mChildNodes.get(j).mTmpClone);
708            }
709            size = node.mSiblings == null ? 0 : node.mSiblings.size();
710            for (int j = 0; j < size; j++) {
711                node.mTmpClone.mSiblings.set(j, node.mSiblings.get(j).mTmpClone);
712            }
713            size = node.mParents == null ? 0 : node.mParents.size();
714            for (int j = 0; j < size; j++) {
715                node.mTmpClone.mParents.set(j, node.mParents.get(j).mTmpClone);
716            }
717        }
718
719        for (int n = 0; n < nodeCount; n++) {
720            mNodes.get(n).mTmpClone = null;
721        }
722        return anim;
723    }
724
725
726    private static class AnimatorSetListener implements AnimatorListener {
727
728        private AnimatorSet mAnimatorSet;
729
730        AnimatorSetListener(AnimatorSet animatorSet) {
731            mAnimatorSet = animatorSet;
732        }
733
734        public void onAnimationCancel(Animator animation) {
735
736            if (!mAnimatorSet.mTerminated) {
737                // Listeners are already notified of the AnimatorSet canceling in cancel().
738                // The logic below only kicks in when animations end normally
739                if (mAnimatorSet.mPlayingSet.size() == 0) {
740                    ArrayList<AnimatorListener> listeners = mAnimatorSet.mListeners;
741                    if (listeners != null) {
742                        int numListeners = listeners.size();
743                        for (int i = 0; i < numListeners; ++i) {
744                            listeners.get(i).onAnimationCancel(mAnimatorSet);
745                        }
746                    }
747                }
748            }
749        }
750
751        @SuppressWarnings("unchecked")
752        public void onAnimationEnd(Animator animation) {
753            animation.removeListener(this);
754            mAnimatorSet.mPlayingSet.remove(animation);
755            mAnimatorSet.onChildAnimatorEnded(animation);
756        }
757
758        // Nothing to do
759        public void onAnimationRepeat(Animator animation) {
760        }
761
762        // Nothing to do
763        public void onAnimationStart(Animator animation) {
764        }
765
766    }
767
768    private void onChildAnimatorEnded(Animator animation) {
769        Node animNode = mNodeMap.get(animation);
770        animNode.mEnded = true;
771
772        if (!mTerminated) {
773            List<Node> children = animNode.mChildNodes;
774            // Start children animations, if any.
775            int childrenSize = children == null ? 0 : children.size();
776            for (int i = 0; i < childrenSize; i++) {
777                if (children.get(i).mLatestParent == animNode) {
778                    start(children.get(i));
779                }
780            }
781            // Listeners are already notified of the AnimatorSet ending in cancel() or
782            // end(); the logic below only kicks in when animations end normally
783            boolean allDone = true;
784            // Traverse the tree and find if there's any unfinished node
785            int size = mNodes.size();
786            for (int i = 0; i < size; i++) {
787                if (!mNodes.get(i).mEnded) {
788                    allDone = false;
789                    break;
790                }
791            }
792            if (allDone) {
793                // If this was the last child animation to end, then notify listeners that this
794                // AnimatorSet has ended
795                if (mListeners != null) {
796                    ArrayList<AnimatorListener> tmpListeners =
797                            (ArrayList<AnimatorListener>) mListeners.clone();
798                    int numListeners = tmpListeners.size();
799                    for (int i = 0; i < numListeners; ++i) {
800                        tmpListeners.get(i).onAnimationEnd(this);
801                    }
802                }
803                mStarted = false;
804                mPaused = false;
805            }
806        }
807    }
808
809    /**
810     * AnimatorSet is only reversible when the set contains no sequential animation, and no child
811     * animators have a start delay.
812     * @hide
813     */
814    @Override
815    public boolean canReverse() {
816        if (!mReversible)  {
817            return false;
818        }
819        // Loop to make sure all the Nodes can reverse.
820        int size = mNodes.size();
821        for (int i = 0; i < size; i++) {
822            Node node = mNodes.get(i);
823            if (!node.mAnimation.canReverse() || node.mAnimation.getStartDelay() > 0) {
824                return false;
825            }
826        }
827        return true;
828    }
829
830    /**
831     * @hide
832     */
833    @Override
834    public void reverse() {
835        if (canReverse()) {
836            int size = mNodes.size();
837            for (int i = 0; i < size; i++) {
838                Node node = mNodes.get(i);
839                node.mAnimation.reverse();
840            }
841        }
842    }
843
844    @Override
845    public String toString() {
846        String returnVal = "AnimatorSet@" + Integer.toHexString(hashCode()) + "{";
847        int size = mNodes.size();
848        for (int i = 0; i < size; i++) {
849            Node node = mNodes.get(i);
850            returnVal += "\n    " + node.mAnimation.toString();
851        }
852        return returnVal + "\n}";
853    }
854
855    private void printChildCount() {
856        // Print out the child count through a level traverse.
857        ArrayList<Node> list = new ArrayList<>(mNodes.size());
858        list.add(mRootNode);
859        Log.d(TAG, "Current tree: ");
860        int index = 0;
861        while (index < list.size()) {
862            int listSize = list.size();
863            StringBuilder builder = new StringBuilder();
864            for (; index < listSize; index++) {
865                Node node = list.get(index);
866                int num = 0;
867                if (node.mChildNodes != null) {
868                    for (int i = 0; i < node.mChildNodes.size(); i++) {
869                        Node child = node.mChildNodes.get(i);
870                        if (child.mLatestParent == node) {
871                            num++;
872                            list.add(child);
873                        }
874                    }
875                }
876                builder.append(" ");
877                builder.append(num);
878            }
879            Log.d(TAG, builder.toString());
880        }
881    }
882
883    private void createDependencyGraph() {
884        if (!mDependencyDirty) {
885            // Check whether any duration of the child animations has changed
886            boolean durationChanged = false;
887            for (int i = 0; i < mNodes.size(); i++) {
888                Animator anim = mNodes.get(i).mAnimation;
889                if (mNodes.get(i).mTotalDuration != anim.getTotalDuration()) {
890                    durationChanged = true;
891                    break;
892                }
893            }
894            if (!durationChanged) {
895                return;
896            }
897        }
898
899        mDependencyDirty = false;
900        // Traverse all the siblings and make sure they have all the parents
901        int size = mNodes.size();
902        for (int i = 0; i < size; i++) {
903            mNodes.get(i).mParentsAdded = false;
904        }
905        for (int i = 0; i < size; i++) {
906            Node node = mNodes.get(i);
907            if (node.mParentsAdded) {
908                continue;
909            }
910
911            node.mParentsAdded = true;
912            if (node.mSiblings == null) {
913                continue;
914            }
915
916            // Find all the siblings
917            findSiblings(node, node.mSiblings);
918            node.mSiblings.remove(node);
919
920            // Get parents from all siblings
921            int siblingSize = node.mSiblings.size();
922            for (int j = 0; j < siblingSize; j++) {
923                node.addParents(node.mSiblings.get(j).mParents);
924            }
925
926            // Now make sure all siblings share the same set of parents
927            for (int j = 0; j < siblingSize; j++) {
928                Node sibling = node.mSiblings.get(j);
929                sibling.addParents(node.mParents);
930                sibling.mParentsAdded = true;
931            }
932        }
933
934        for (int i = 0; i < size; i++) {
935            Node node = mNodes.get(i);
936            if (node != mRootNode && node.mParents == null) {
937                node.addParent(mRootNode);
938            }
939        }
940
941        // Do a DFS on the tree
942        ArrayList<Node> visited = new ArrayList<Node>(mNodes.size());
943        // Assign start/end time
944        mRootNode.mStartTime = 0;
945        mRootNode.mEndTime = mDelayAnim.getDuration();
946        updatePlayTime(mRootNode, visited);
947
948        long maxEndTime = 0;
949        for (int i = 0; i < size; i++) {
950            Node node = mNodes.get(i);
951            node.mTotalDuration = node.mAnimation.getTotalDuration();
952            if (node.mEndTime == DURATION_INFINITE) {
953                maxEndTime = DURATION_INFINITE;
954                break;
955            } else {
956                maxEndTime = node.mEndTime > maxEndTime ? node.mEndTime : maxEndTime;
957            }
958        }
959        mTotalDuration = maxEndTime;
960    }
961
962    /**
963     * Based on parent's start/end time, calculate children's start/end time. If cycle exists in
964     * the graph, all the nodes on the cycle will be marked to start at {@link #DURATION_INFINITE},
965     * meaning they will ever play.
966     */
967    private void updatePlayTime(Node parent,  ArrayList<Node> visited) {
968        if (parent.mChildNodes == null) {
969            if (parent == mRootNode) {
970                // All the animators are in a cycle
971                for (int i = 0; i < mNodes.size(); i++) {
972                    Node node = mNodes.get(i);
973                    if (node != mRootNode) {
974                        node.mStartTime = DURATION_INFINITE;
975                        node.mEndTime = DURATION_INFINITE;
976                    }
977                }
978            }
979            return;
980        }
981
982        visited.add(parent);
983        int childrenSize = parent.mChildNodes.size();
984        for (int i = 0; i < childrenSize; i++) {
985            Node child = parent.mChildNodes.get(i);
986            int index = visited.indexOf(child);
987            if (index >= 0) {
988                // Child has been visited, cycle found. Mark all the nodes in the cycle.
989                for (int j = index; j < visited.size(); j++) {
990                    visited.get(j).mLatestParent = null;
991                    visited.get(j).mStartTime = DURATION_INFINITE;
992                    visited.get(j).mEndTime = DURATION_INFINITE;
993                }
994                child.mStartTime = DURATION_INFINITE;
995                child.mEndTime = DURATION_INFINITE;
996                child.mLatestParent = null;
997                Log.w(TAG, "Cycle found in AnimatorSet: " + this);
998                continue;
999            }
1000
1001            if (child.mStartTime != DURATION_INFINITE) {
1002                if (parent.mEndTime == DURATION_INFINITE) {
1003                    child.mLatestParent = parent;
1004                    child.mStartTime = DURATION_INFINITE;
1005                    child.mEndTime = DURATION_INFINITE;
1006                } else {
1007                    if (parent.mEndTime >= child.mStartTime) {
1008                        child.mLatestParent = parent;
1009                        child.mStartTime = parent.mEndTime;
1010                    }
1011
1012                    long duration = child.mAnimation.getTotalDuration();
1013                    child.mEndTime = duration == DURATION_INFINITE ?
1014                            DURATION_INFINITE : child.mStartTime + duration;
1015                }
1016            }
1017            updatePlayTime(child, visited);
1018        }
1019        visited.remove(parent);
1020    }
1021
1022    // Recursively find all the siblings
1023    private void findSiblings(Node node, ArrayList<Node> siblings) {
1024        if (!siblings.contains(node)) {
1025            siblings.add(node);
1026            if (node.mSiblings == null) {
1027                return;
1028            }
1029            for (int i = 0; i < node.mSiblings.size(); i++) {
1030                findSiblings(node.mSiblings.get(i), siblings);
1031            }
1032        }
1033    }
1034
1035    /**
1036     * @hide
1037     * TODO: For animatorSet defined in XML, we can use a flag to indicate what the play order
1038     * if defined (i.e. sequential or together), then we can use the flag instead of calculate
1039     * dynamically.
1040     * @return whether all the animators in the set are supposed to play together
1041     */
1042    public boolean shouldPlayTogether() {
1043        updateAnimatorsDuration();
1044        createDependencyGraph();
1045        // All the child nodes are set out to play right after the delay animation
1046        return mRootNode.mChildNodes.size() == mNodes.size() - 1;
1047    }
1048
1049    @Override
1050    public long getTotalDuration() {
1051        updateAnimatorsDuration();
1052        createDependencyGraph();
1053        return mTotalDuration;
1054    }
1055
1056    private Node getNodeForAnimation(Animator anim) {
1057        Node node = mNodeMap.get(anim);
1058        if (node == null) {
1059            node = new Node(anim);
1060            mNodeMap.put(anim, node);
1061            mNodes.add(node);
1062        }
1063        return node;
1064    }
1065
1066    /**
1067     * A Node is an embodiment of both the Animator that it wraps as well as
1068     * any dependencies that are associated with that Animation. This includes
1069     * both dependencies upon other nodes (in the dependencies list) as
1070     * well as dependencies of other nodes upon this (in the nodeDependents list).
1071     */
1072    private static class Node implements Cloneable {
1073        Animator mAnimation;
1074
1075        /**
1076         * Child nodes are the nodes associated with animations that will be played immediately
1077         * after current node.
1078         */
1079        ArrayList<Node> mChildNodes = null;
1080
1081        /**
1082         * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
1083         */
1084        private Node mTmpClone = null;
1085
1086        /**
1087         * Flag indicating whether the animation in this node is finished. This flag
1088         * is used by AnimatorSet to check, as each animation ends, whether all child animations
1089         * are mEnded and it's time to send out an end event for the entire AnimatorSet.
1090         */
1091        boolean mEnded = false;
1092
1093        /**
1094         * Nodes with animations that are defined to play simultaneously with the animation
1095         * associated with this current node.
1096         */
1097        ArrayList<Node> mSiblings;
1098
1099        /**
1100         * Parent nodes are the nodes with animations preceding current node's animation. Parent
1101         * nodes here are derived from user defined animation sequence.
1102         */
1103        ArrayList<Node> mParents;
1104
1105        /**
1106         * Latest parent is the parent node associated with a animation that finishes after all
1107         * the other parents' animations.
1108         */
1109        Node mLatestParent = null;
1110
1111        boolean mParentsAdded = false;
1112        long mStartTime = 0;
1113        long mEndTime = 0;
1114        long mTotalDuration = 0;
1115
1116        /**
1117         * Constructs the Node with the animation that it encapsulates. A Node has no
1118         * dependencies by default; dependencies are added via the addDependency()
1119         * method.
1120         *
1121         * @param animation The animation that the Node encapsulates.
1122         */
1123        public Node(Animator animation) {
1124            this.mAnimation = animation;
1125        }
1126
1127        @Override
1128        public Node clone() {
1129            try {
1130                Node node = (Node) super.clone();
1131                node.mAnimation = mAnimation.clone();
1132                if (mChildNodes != null) {
1133                    node.mChildNodes = new ArrayList<>(mChildNodes);
1134                }
1135                if (mSiblings != null) {
1136                    node.mSiblings = new ArrayList<>(mSiblings);
1137                }
1138                if (mParents != null) {
1139                    node.mParents = new ArrayList<>(mParents);
1140                }
1141                node.mEnded = false;
1142                return node;
1143            } catch (CloneNotSupportedException e) {
1144               throw new AssertionError();
1145            }
1146        }
1147
1148        void addChild(Node node) {
1149            if (mChildNodes == null) {
1150                mChildNodes = new ArrayList<>();
1151            }
1152            if (!mChildNodes.contains(node)) {
1153                mChildNodes.add(node);
1154                node.addParent(this);
1155            }
1156        }
1157
1158        public void addSibling(Node node) {
1159            if (mSiblings == null) {
1160                mSiblings = new ArrayList<Node>();
1161            }
1162            if (!mSiblings.contains(node)) {
1163                mSiblings.add(node);
1164                node.addSibling(this);
1165            }
1166        }
1167
1168        public void addParent(Node node) {
1169            if (mParents == null) {
1170                mParents =  new ArrayList<Node>();
1171            }
1172            if (!mParents.contains(node)) {
1173                mParents.add(node);
1174                node.addChild(this);
1175            }
1176        }
1177
1178        public void addParents(ArrayList<Node> parents) {
1179            if (parents == null) {
1180                return;
1181            }
1182            int size = parents.size();
1183            for (int i = 0; i < size; i++) {
1184                addParent(parents.get(i));
1185            }
1186        }
1187    }
1188
1189    /**
1190     * The <code>Builder</code> object is a utility class to facilitate adding animations to a
1191     * <code>AnimatorSet</code> along with the relationships between the various animations. The
1192     * intention of the <code>Builder</code> methods, along with the {@link
1193     * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible
1194     * to express the dependency relationships of animations in a natural way. Developers can also
1195     * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
1196     * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
1197     * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
1198     * <p/>
1199     * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
1200     * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
1201     * <p/>
1202     * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
1203     * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
1204     * <pre>
1205     *     AnimatorSet s = new AnimatorSet();
1206     *     s.play(anim1).with(anim2);
1207     *     s.play(anim2).before(anim3);
1208     *     s.play(anim4).after(anim3);
1209     * </pre>
1210     * <p/>
1211     * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
1212     * Builder#after(Animator)} are used. These are just different ways of expressing the same
1213     * relationship and are provided to make it easier to say things in a way that is more natural,
1214     * depending on the situation.</p>
1215     * <p/>
1216     * <p>It is possible to make several calls into the same <code>Builder</code> object to express
1217     * multiple relationships. However, note that it is only the animation passed into the initial
1218     * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
1219     * calls to the <code>Builder</code> object. For example, the following code starts both anim2
1220     * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
1221     * anim3:
1222     * <pre>
1223     *   AnimatorSet s = new AnimatorSet();
1224     *   s.play(anim1).before(anim2).before(anim3);
1225     * </pre>
1226     * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
1227     * relationship correctly:</p>
1228     * <pre>
1229     *   AnimatorSet s = new AnimatorSet();
1230     *   s.play(anim1).before(anim2);
1231     *   s.play(anim2).before(anim3);
1232     * </pre>
1233     * <p/>
1234     * <p>Note that it is possible to express relationships that cannot be resolved and will not
1235     * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
1236     * sense. In general, circular dependencies like this one (or more indirect ones where a depends
1237     * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
1238     * that can boil down to a simple, one-way relationship of animations starting with, before, and
1239     * after other, different, animations.</p>
1240     */
1241    public class Builder {
1242
1243        /**
1244         * This tracks the current node being processed. It is supplied to the play() method
1245         * of AnimatorSet and passed into the constructor of Builder.
1246         */
1247        private Node mCurrentNode;
1248
1249        /**
1250         * package-private constructor. Builders are only constructed by AnimatorSet, when the
1251         * play() method is called.
1252         *
1253         * @param anim The animation that is the dependency for the other animations passed into
1254         * the other methods of this Builder object.
1255         */
1256        Builder(Animator anim) {
1257            mDependencyDirty = true;
1258            mCurrentNode = getNodeForAnimation(anim);
1259        }
1260
1261        /**
1262         * Sets up the given animation to play at the same time as the animation supplied in the
1263         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
1264         *
1265         * @param anim The animation that will play when the animation supplied to the
1266         * {@link AnimatorSet#play(Animator)} method starts.
1267         */
1268        public Builder with(Animator anim) {
1269            Node node = getNodeForAnimation(anim);
1270            mCurrentNode.addSibling(node);
1271            return this;
1272        }
1273
1274        /**
1275         * Sets up the given animation to play when the animation supplied in the
1276         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1277         * ends.
1278         *
1279         * @param anim The animation that will play when the animation supplied to the
1280         * {@link AnimatorSet#play(Animator)} method ends.
1281         */
1282        public Builder before(Animator anim) {
1283            mReversible = false;
1284            Node node = getNodeForAnimation(anim);
1285            mCurrentNode.addChild(node);
1286            return this;
1287        }
1288
1289        /**
1290         * Sets up the given animation to play when the animation supplied in the
1291         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1292         * to start when the animation supplied in this method call ends.
1293         *
1294         * @param anim The animation whose end will cause the animation supplied to the
1295         * {@link AnimatorSet#play(Animator)} method to play.
1296         */
1297        public Builder after(Animator anim) {
1298            mReversible = false;
1299            Node node = getNodeForAnimation(anim);
1300            mCurrentNode.addParent(node);
1301            return this;
1302        }
1303
1304        /**
1305         * Sets up the animation supplied in the
1306         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1307         * to play when the given amount of time elapses.
1308         *
1309         * @param delay The number of milliseconds that should elapse before the
1310         * animation starts.
1311         */
1312        public Builder after(long delay) {
1313            // setup dummy ValueAnimator just to run the clock
1314            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
1315            anim.setDuration(delay);
1316            after(anim);
1317            return this;
1318        }
1319
1320    }
1321
1322}
1323