AnimatorSet.java revision 49db4242b134ffee79392670f9e434f6e3c7cec7
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.
412     * @return Whether this AnimatorSet has been started and has not yet ended.
413     */
414    @Override
415    public boolean isRunning() {
416        int size = mNodes.size();
417        for (int i = 0; i < size; i++) {
418            if (mNodes.get(i).mAnimation.isRunning()) {
419                return true;
420            }
421        }
422        return false;
423    }
424
425    @Override
426    public boolean isStarted() {
427        return mStarted;
428    }
429
430    /**
431     * The amount of time, in milliseconds, to delay starting the animation after
432     * {@link #start()} is called.
433     *
434     * @return the number of milliseconds to delay running the animation
435     */
436    @Override
437    public long getStartDelay() {
438        return mStartDelay;
439    }
440
441    /**
442     * The amount of time, in milliseconds, to delay starting the animation after
443     * {@link #start()} is called.
444
445     * @param startDelay The amount of the delay, in milliseconds
446     */
447    @Override
448    public void setStartDelay(long startDelay) {
449        if (mStartDelay > 0) {
450            mReversible = false;
451        }
452        long delta = startDelay - mStartDelay;
453        if (delta == 0) {
454            return;
455        }
456        mStartDelay = startDelay;
457        if (!mDependencyDirty) {
458            // Dependency graph already constructed, update all the nodes' start/end time
459            int size = mNodes.size();
460            for (int i = 0; i < size; i++) {
461                Node node = mNodes.get(i);
462                if (node == mRootNode) {
463                    node.mEndTime = mStartDelay;
464                } else {
465                    node.mStartTime = node.mStartTime == DURATION_INFINITE ?
466                            DURATION_INFINITE : node.mStartTime + delta;
467                    node.mEndTime = node.mEndTime == DURATION_INFINITE ?
468                            DURATION_INFINITE : node.mEndTime + delta;
469                }
470            }
471            // Update total duration, if necessary.
472            if (mTotalDuration != DURATION_INFINITE) {
473                mTotalDuration += delta;
474            }
475        }
476    }
477
478    /**
479     * Gets the length of each of the child animations of this AnimatorSet. This value may
480     * be less than 0, which indicates that no duration has been set on this AnimatorSet
481     * and each of the child animations will use their own duration.
482     *
483     * @return The length of the animation, in milliseconds, of each of the child
484     * animations of this AnimatorSet.
485     */
486    @Override
487    public long getDuration() {
488        return mDuration;
489    }
490
491    /**
492     * Sets the length of each of the current child animations of this AnimatorSet. By default,
493     * each child animation will use its own duration. If the duration is set on the AnimatorSet,
494     * then each child animation inherits this duration.
495     *
496     * @param duration The length of the animation, in milliseconds, of each of the child
497     * animations of this AnimatorSet.
498     */
499    @Override
500    public AnimatorSet setDuration(long duration) {
501        if (duration < 0) {
502            throw new IllegalArgumentException("duration must be a value of zero or greater");
503        }
504        mDependencyDirty = true;
505        // Just record the value for now - it will be used later when the AnimatorSet starts
506        mDuration = duration;
507        return this;
508    }
509
510    @Override
511    public void setupStartValues() {
512        int size = mNodes.size();
513        for (int i = 0; i < size; i++) {
514            Node node = mNodes.get(i);
515            node.mAnimation.setupStartValues();
516        }
517    }
518
519    @Override
520    public void setupEndValues() {
521        int size = mNodes.size();
522        for (int i = 0; i < size; i++) {
523            Node node = mNodes.get(i);
524            node.mAnimation.setupEndValues();
525        }
526    }
527
528    @Override
529    public void pause() {
530        boolean previouslyPaused = mPaused;
531        super.pause();
532        if (!previouslyPaused && mPaused) {
533            if (mDelayAnim != null) {
534                mDelayAnim.pause();
535            } else {
536                int size = mNodes.size();
537                for (int i = 0; i < size; i++) {
538                    Node node = mNodes.get(i);
539                    node.mAnimation.pause();
540                }
541            }
542        }
543    }
544
545    @Override
546    public void resume() {
547        boolean previouslyPaused = mPaused;
548        super.resume();
549        if (previouslyPaused && !mPaused) {
550            if (mDelayAnim != null) {
551                mDelayAnim.resume();
552            } else {
553                int size = mNodes.size();
554                for (int i = 0; i < size; i++) {
555                    Node node = mNodes.get(i);
556                    node.mAnimation.resume();
557                }
558            }
559        }
560    }
561
562    /**
563     * {@inheritDoc}
564     *
565     * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which
566     * it is responsible. The details of when exactly those animations are started depends on
567     * the dependency relationships that have been set up between the animations.
568     */
569    @SuppressWarnings("unchecked")
570    @Override
571    public void start() {
572        mTerminated = false;
573        mStarted = true;
574        mPaused = false;
575
576        int size = mNodes.size();
577        for (int i = 0; i < size; i++) {
578            Node node = mNodes.get(i);
579            node.mEnded = false;
580            node.mAnimation.setAllowRunningAsynchronously(false);
581        }
582
583        if (mInterpolator != null) {
584            for (int i = 0; i < size; i++) {
585                Node node = mNodes.get(i);
586                node.mAnimation.setInterpolator(mInterpolator);
587            }
588        }
589
590        updateAnimatorsDuration();
591        createDependencyGraph();
592
593        // Now that all dependencies are set up, start the animations that should be started.
594        start(mRootNode);
595        if (mListeners != null) {
596            ArrayList<AnimatorListener> tmpListeners =
597                    (ArrayList<AnimatorListener>) mListeners.clone();
598            int numListeners = tmpListeners.size();
599            for (int i = 0; i < numListeners; ++i) {
600                tmpListeners.get(i).onAnimationStart(this);
601            }
602        }
603        if (mNodes.size() == 0 && mStartDelay == 0) {
604            // Handle unusual case where empty AnimatorSet is started - should send out
605            // end event immediately since the event will not be sent out at all otherwise
606            mStarted = false;
607            if (mListeners != null) {
608                ArrayList<AnimatorListener> tmpListeners =
609                        (ArrayList<AnimatorListener>) mListeners.clone();
610                int numListeners = tmpListeners.size();
611                for (int i = 0; i < numListeners; ++i) {
612                    tmpListeners.get(i).onAnimationEnd(this);
613                }
614            }
615        }
616    }
617
618    private void updateAnimatorsDuration() {
619        if (mDuration >= 0) {
620            // If the duration was set on this AnimatorSet, pass it along to all child animations
621            int size = mNodes.size();
622            for (int i = 0; i < size; i++) {
623                Node node = mNodes.get(i);
624                // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
625                // insert "play-after" delays
626                node.mAnimation.setDuration(mDuration);
627            }
628        }
629        mDelayAnim.setDuration(mStartDelay);
630    }
631
632    void start(final Node node) {
633        final Animator anim = node.mAnimation;
634        mPlayingSet.add(anim);
635        anim.addListener(mSetListener);
636        anim.start();
637    }
638
639    @Override
640    public AnimatorSet clone() {
641        final AnimatorSet anim = (AnimatorSet) super.clone();
642        /*
643         * The basic clone() operation copies all items. This doesn't work very well for
644         * AnimatorSet, because it will copy references that need to be recreated and state
645         * that may not apply. What we need to do now is put the clone in an uninitialized
646         * state, with fresh, empty data structures. Then we will build up the nodes list
647         * manually, as we clone each Node (and its animation). The clone will then be sorted,
648         * and will populate any appropriate lists, when it is started.
649         */
650        final int nodeCount = mNodes.size();
651        anim.mTerminated = false;
652        anim.mStarted = false;
653        anim.mPlayingSet = new ArrayList<Animator>();
654        anim.mNodeMap = new ArrayMap<Animator, Node>();
655        anim.mNodes = new ArrayList<Node>(nodeCount);
656        anim.mReversible = mReversible;
657        anim.mSetListener = new AnimatorSetListener(anim);
658
659        // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
660        // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
661        // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
662
663        for (int n = 0; n < nodeCount; n++) {
664            final Node node = mNodes.get(n);
665            Node nodeClone = node.clone();
666            node.mTmpClone = nodeClone;
667            anim.mNodes.add(nodeClone);
668            anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
669
670            // clear out any listeners that were set up by the AnimatorSet
671            final ArrayList<AnimatorListener> cloneListeners = nodeClone.mAnimation.getListeners();
672            if (cloneListeners != null) {
673                for (int i = cloneListeners.size() - 1; i >= 0; i--) {
674                    final AnimatorListener listener = cloneListeners.get(i);
675                    if (listener instanceof AnimatorSetListener) {
676                        cloneListeners.remove(i);
677                    }
678                }
679            }
680        }
681
682        anim.mRootNode = mRootNode.mTmpClone;
683        anim.mDelayAnim = (ValueAnimator) anim.mRootNode.mAnimation;
684
685        // Now that we've cloned all of the nodes, we're ready to walk through their
686        // dependencies, mapping the old dependencies to the new nodes
687        for (int i = 0; i < nodeCount; i++) {
688            Node node = mNodes.get(i);
689            // Update dependencies for node's clone
690            node.mTmpClone.mLatestParent = node.mLatestParent == null ?
691                    null : node.mLatestParent.mTmpClone;
692            int size = node.mChildNodes == null ? 0 : node.mChildNodes.size();
693            for (int j = 0; j < size; j++) {
694                node.mTmpClone.mChildNodes.set(j, node.mChildNodes.get(j).mTmpClone);
695            }
696            size = node.mSiblings == null ? 0 : node.mSiblings.size();
697            for (int j = 0; j < size; j++) {
698                node.mTmpClone.mSiblings.set(j, node.mSiblings.get(j).mTmpClone);
699            }
700            size = node.mParents == null ? 0 : node.mParents.size();
701            for (int j = 0; j < size; j++) {
702                node.mTmpClone.mParents.set(j, node.mParents.get(j).mTmpClone);
703            }
704        }
705
706        for (int n = 0; n < nodeCount; n++) {
707            mNodes.get(n).mTmpClone = null;
708        }
709        return anim;
710    }
711
712
713    private static class AnimatorSetListener implements AnimatorListener {
714
715        private AnimatorSet mAnimatorSet;
716
717        AnimatorSetListener(AnimatorSet animatorSet) {
718            mAnimatorSet = animatorSet;
719        }
720
721        public void onAnimationCancel(Animator animation) {
722
723            if (!mAnimatorSet.mTerminated) {
724                // Listeners are already notified of the AnimatorSet canceling in cancel().
725                // The logic below only kicks in when animations end normally
726                if (mAnimatorSet.mPlayingSet.size() == 0) {
727                    ArrayList<AnimatorListener> listeners = mAnimatorSet.mListeners;
728                    if (listeners != null) {
729                        int numListeners = listeners.size();
730                        for (int i = 0; i < numListeners; ++i) {
731                            listeners.get(i).onAnimationCancel(mAnimatorSet);
732                        }
733                    }
734                }
735            }
736        }
737
738        @SuppressWarnings("unchecked")
739        public void onAnimationEnd(Animator animation) {
740            animation.removeListener(this);
741            mAnimatorSet.mPlayingSet.remove(animation);
742            Node animNode = mAnimatorSet.mNodeMap.get(animation);
743            animNode.mEnded = true;
744
745            if (!mAnimatorSet.mTerminated) {
746                List<Node> children = animNode.mChildNodes;
747                // Start children animations, if any.
748                int childrenSize = children == null ? 0 : children.size();
749                for (int i = 0; i < childrenSize; i++) {
750                    if (children.get(i).mLatestParent == animNode) {
751                        mAnimatorSet.start(children.get(i));
752                    }
753                }
754                // Listeners are already notified of the AnimatorSet ending in cancel() or
755                // end(); the logic below only kicks in when animations end normally
756                boolean allDone = true;
757                // Traverse the tree and find if there's any unfinished node
758                int size = mAnimatorSet.mNodes.size();
759                for (int i = 0; i < size; i++) {
760                    if (!mAnimatorSet.mNodes.get(i).mEnded) {
761                        allDone = false;
762                        break;
763                    }
764                }
765                if (allDone) {
766                    // If this was the last child animation to end, then notify listeners that this
767                    // AnimatorSet has ended
768                    if (mAnimatorSet.mListeners != null) {
769                        ArrayList<AnimatorListener> tmpListeners =
770                                (ArrayList<AnimatorListener>) mAnimatorSet.mListeners.clone();
771                        int numListeners = tmpListeners.size();
772                        for (int i = 0; i < numListeners; ++i) {
773                            tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
774                        }
775                    }
776                    mAnimatorSet.mStarted = false;
777                    mAnimatorSet.mPaused = false;
778                }
779            }
780        }
781
782        // Nothing to do
783        public void onAnimationRepeat(Animator animation) {
784        }
785
786        // Nothing to do
787        public void onAnimationStart(Animator animation) {
788        }
789
790    }
791
792    /**
793     * @hide
794     */
795    @Override
796    public boolean canReverse() {
797        if (!mReversible)  {
798            return false;
799        }
800        // Loop to make sure all the Nodes can reverse.
801        int size = mNodes.size();
802        for (int i = 0; i < size; i++) {
803            Node node = mNodes.get(i);
804            if (!node.mAnimation.canReverse() || node.mAnimation.getStartDelay() > 0) {
805                return false;
806            }
807        }
808        return true;
809    }
810
811    /**
812     * @hide
813     */
814    @Override
815    public void reverse() {
816        if (canReverse()) {
817            int size = mNodes.size();
818            for (int i = 0; i < size; i++) {
819                Node node = mNodes.get(i);
820                node.mAnimation.reverse();
821            }
822        }
823    }
824
825    @Override
826    public String toString() {
827        String returnVal = "AnimatorSet@" + Integer.toHexString(hashCode()) + "{";
828        int size = mNodes.size();
829        for (int i = 0; i < size; i++) {
830            Node node = mNodes.get(i);
831            returnVal += "\n    " + node.mAnimation.toString();
832        }
833        return returnVal + "\n}";
834    }
835
836    private void printChildCount() {
837        // Print out the child count through a level traverse.
838        ArrayList<Node> list = new ArrayList<>(mNodes.size());
839        list.add(mRootNode);
840        Log.d(TAG, "Current tree: ");
841        int index = 0;
842        while (index < list.size()) {
843            int listSize = list.size();
844            StringBuilder builder = new StringBuilder();
845            for (; index < listSize; index++) {
846                Node node = list.get(index);
847                int num = 0;
848                if (node.mChildNodes != null) {
849                    for (int i = 0; i < node.mChildNodes.size(); i++) {
850                        Node child = node.mChildNodes.get(i);
851                        if (child.mLatestParent == node) {
852                            num++;
853                            list.add(child);
854                        }
855                    }
856                }
857                builder.append(" ");
858                builder.append(num);
859            }
860            Log.d(TAG, builder.toString());
861        }
862    }
863
864    private void createDependencyGraph() {
865        if (!mDependencyDirty) {
866            // Check whether any duration of the child animations has changed
867            boolean durationChanged = false;
868            for (int i = 0; i < mNodes.size(); i++) {
869                Animator anim = mNodes.get(i).mAnimation;
870                if (mNodes.get(i).mTotalDuration != anim.getTotalDuration()) {
871                    durationChanged = true;
872                    break;
873                }
874            }
875            if (!durationChanged) {
876                return;
877            }
878        }
879
880        mDependencyDirty = false;
881        // Traverse all the siblings and make sure they have all the parents
882        int size = mNodes.size();
883        for (int i = 0; i < size; i++) {
884            mNodes.get(i).mParentsAdded = false;
885        }
886        for (int i = 0; i < size; i++) {
887            Node node = mNodes.get(i);
888            if (node.mParentsAdded) {
889                continue;
890            }
891
892            node.mParentsAdded = true;
893            if (node.mSiblings == null) {
894                continue;
895            }
896
897            // Find all the siblings
898            findSiblings(node, node.mSiblings);
899            node.mSiblings.remove(node);
900
901            // Get parents from all siblings
902            int siblingSize = node.mSiblings.size();
903            for (int j = 0; j < siblingSize; j++) {
904                node.addParents(node.mSiblings.get(j).mParents);
905            }
906
907            // Now make sure all siblings share the same set of parents
908            for (int j = 0; j < siblingSize; j++) {
909                Node sibling = node.mSiblings.get(j);
910                sibling.addParents(node.mParents);
911                sibling.mParentsAdded = true;
912            }
913        }
914
915        for (int i = 0; i < size; i++) {
916            Node node = mNodes.get(i);
917            if (node != mRootNode && node.mParents == null) {
918                node.addParent(mRootNode);
919            }
920        }
921
922        // Do a DFS on the tree
923        ArrayList<Node> visited = new ArrayList<Node>(mNodes.size());
924        // Assign start/end time
925        mRootNode.mStartTime = 0;
926        mRootNode.mEndTime = mDelayAnim.getDuration();
927        updatePlayTime(mRootNode, visited);
928
929        long maxEndTime = 0;
930        for (int i = 0; i < size; i++) {
931            Node node = mNodes.get(i);
932            node.mTotalDuration = node.mAnimation.getTotalDuration();
933            if (node.mEndTime == DURATION_INFINITE) {
934                maxEndTime = DURATION_INFINITE;
935                break;
936            } else {
937                maxEndTime = node.mEndTime > maxEndTime ? node.mEndTime : maxEndTime;
938            }
939        }
940        mTotalDuration = maxEndTime;
941    }
942
943    /**
944     * Based on parent's start/end time, calculate children's start/end time. If cycle exists in
945     * the graph, all the nodes on the cycle will be marked to start at {@link #DURATION_INFINITE},
946     * meaning they will ever play.
947     */
948    private void updatePlayTime(Node parent,  ArrayList<Node> visited) {
949        if (parent.mChildNodes == null) {
950            if (parent == mRootNode) {
951                // All the animators are in a cycle
952                for (int i = 0; i < mNodes.size(); i++) {
953                    Node node = mNodes.get(i);
954                    if (node != mRootNode) {
955                        node.mStartTime = DURATION_INFINITE;
956                        node.mEndTime = DURATION_INFINITE;
957                    }
958                }
959            }
960            return;
961        }
962
963        visited.add(parent);
964        int childrenSize = parent.mChildNodes.size();
965        for (int i = 0; i < childrenSize; i++) {
966            Node child = parent.mChildNodes.get(i);
967            int index = visited.indexOf(child);
968            if (index >= 0) {
969                // Child has been visited, cycle found. Mark all the nodes in the cycle.
970                for (int j = index; j < visited.size(); j++) {
971                    visited.get(j).mLatestParent = null;
972                    visited.get(j).mStartTime = DURATION_INFINITE;
973                    visited.get(j).mEndTime = DURATION_INFINITE;
974                }
975                child.mStartTime = DURATION_INFINITE;
976                child.mEndTime = DURATION_INFINITE;
977                child.mLatestParent = null;
978                Log.w(TAG, "Cycle found in AnimatorSet: " + this);
979                continue;
980            }
981
982            if (child.mStartTime != DURATION_INFINITE) {
983                if (parent.mEndTime == DURATION_INFINITE) {
984                    child.mLatestParent = parent;
985                    child.mStartTime = DURATION_INFINITE;
986                    child.mEndTime = DURATION_INFINITE;
987                } else {
988                    if (parent.mEndTime >= child.mStartTime) {
989                        child.mLatestParent = parent;
990                        child.mStartTime = parent.mEndTime;
991                    }
992
993                    long duration = child.mAnimation.getTotalDuration();
994                    child.mEndTime = duration == DURATION_INFINITE ?
995                            DURATION_INFINITE : child.mStartTime + duration;
996                }
997            }
998            updatePlayTime(child, visited);
999        }
1000        visited.remove(parent);
1001    }
1002
1003    // Recursively find all the siblings
1004    private void findSiblings(Node node, ArrayList<Node> siblings) {
1005        if (!siblings.contains(node)) {
1006            siblings.add(node);
1007            if (node.mSiblings == null) {
1008                return;
1009            }
1010            for (int i = 0; i < node.mSiblings.size(); i++) {
1011                findSiblings(node.mSiblings.get(i), siblings);
1012            }
1013        }
1014    }
1015
1016    /**
1017     * @hide
1018     */
1019    @Override
1020    public long getTotalDuration() {
1021        updateAnimatorsDuration();
1022        createDependencyGraph();
1023        return mTotalDuration;
1024    }
1025
1026    private Node getNodeForAnimation(Animator anim) {
1027        Node node = mNodeMap.get(anim);
1028        if (node == null) {
1029            node = new Node(anim);
1030            mNodeMap.put(anim, node);
1031            mNodes.add(node);
1032        }
1033        return node;
1034    }
1035
1036    /**
1037     * A Node is an embodiment of both the Animator that it wraps as well as
1038     * any dependencies that are associated with that Animation. This includes
1039     * both dependencies upon other nodes (in the dependencies list) as
1040     * well as dependencies of other nodes upon this (in the nodeDependents list).
1041     */
1042    private static class Node implements Cloneable {
1043        Animator mAnimation;
1044
1045        /**
1046         * Child nodes are the nodes associated with animations that will be played immediately
1047         * after current node.
1048         */
1049        ArrayList<Node> mChildNodes = null;
1050
1051        /**
1052         * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
1053         */
1054        private Node mTmpClone = null;
1055
1056        /**
1057         * Flag indicating whether the animation in this node is finished. This flag
1058         * is used by AnimatorSet to check, as each animation ends, whether all child animations
1059         * are mEnded and it's time to send out an end event for the entire AnimatorSet.
1060         */
1061        boolean mEnded = false;
1062
1063        /**
1064         * Nodes with animations that are defined to play simultaneously with the animation
1065         * associated with this current node.
1066         */
1067        ArrayList<Node> mSiblings;
1068
1069        /**
1070         * Parent nodes are the nodes with animations preceding current node's animation. Parent
1071         * nodes here are derived from user defined animation sequence.
1072         */
1073        ArrayList<Node> mParents;
1074
1075        /**
1076         * Latest parent is the parent node associated with a animation that finishes after all
1077         * the other parents' animations.
1078         */
1079        Node mLatestParent = null;
1080
1081        boolean mParentsAdded = false;
1082        long mStartTime = 0;
1083        long mEndTime = 0;
1084        long mTotalDuration = 0;
1085
1086        /**
1087         * Constructs the Node with the animation that it encapsulates. A Node has no
1088         * dependencies by default; dependencies are added via the addDependency()
1089         * method.
1090         *
1091         * @param animation The animation that the Node encapsulates.
1092         */
1093        public Node(Animator animation) {
1094            this.mAnimation = animation;
1095        }
1096
1097        @Override
1098        public Node clone() {
1099            try {
1100                Node node = (Node) super.clone();
1101                node.mAnimation = mAnimation.clone();
1102                if (mChildNodes != null) {
1103                    node.mChildNodes = new ArrayList<>(mChildNodes);
1104                }
1105                if (mSiblings != null) {
1106                    node.mSiblings = new ArrayList<>(mSiblings);
1107                }
1108                if (mParents != null) {
1109                    node.mParents = new ArrayList<>(mParents);
1110                }
1111                node.mEnded = false;
1112                return node;
1113            } catch (CloneNotSupportedException e) {
1114               throw new AssertionError();
1115            }
1116        }
1117
1118        void addChild(Node node) {
1119            if (mChildNodes == null) {
1120                mChildNodes = new ArrayList<>();
1121            }
1122            if (!mChildNodes.contains(node)) {
1123                mChildNodes.add(node);
1124                node.addParent(this);
1125            }
1126        }
1127
1128        public void addSibling(Node node) {
1129            if (mSiblings == null) {
1130                mSiblings = new ArrayList<Node>();
1131            }
1132            if (!mSiblings.contains(node)) {
1133                mSiblings.add(node);
1134                node.addSibling(this);
1135            }
1136        }
1137
1138        public void addParent(Node node) {
1139            if (mParents == null) {
1140                mParents =  new ArrayList<Node>();
1141            }
1142            if (!mParents.contains(node)) {
1143                mParents.add(node);
1144                node.addChild(this);
1145            }
1146        }
1147
1148        public void addParents(ArrayList<Node> parents) {
1149            if (parents == null) {
1150                return;
1151            }
1152            int size = parents.size();
1153            for (int i = 0; i < size; i++) {
1154                addParent(parents.get(i));
1155            }
1156        }
1157    }
1158
1159    /**
1160     * The <code>Builder</code> object is a utility class to facilitate adding animations to a
1161     * <code>AnimatorSet</code> along with the relationships between the various animations. The
1162     * intention of the <code>Builder</code> methods, along with the {@link
1163     * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible
1164     * to express the dependency relationships of animations in a natural way. Developers can also
1165     * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
1166     * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
1167     * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
1168     * <p/>
1169     * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
1170     * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
1171     * <p/>
1172     * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
1173     * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
1174     * <pre>
1175     *     AnimatorSet s = new AnimatorSet();
1176     *     s.play(anim1).with(anim2);
1177     *     s.play(anim2).before(anim3);
1178     *     s.play(anim4).after(anim3);
1179     * </pre>
1180     * <p/>
1181     * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
1182     * Builder#after(Animator)} are used. These are just different ways of expressing the same
1183     * relationship and are provided to make it easier to say things in a way that is more natural,
1184     * depending on the situation.</p>
1185     * <p/>
1186     * <p>It is possible to make several calls into the same <code>Builder</code> object to express
1187     * multiple relationships. However, note that it is only the animation passed into the initial
1188     * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
1189     * calls to the <code>Builder</code> object. For example, the following code starts both anim2
1190     * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
1191     * anim3:
1192     * <pre>
1193     *   AnimatorSet s = new AnimatorSet();
1194     *   s.play(anim1).before(anim2).before(anim3);
1195     * </pre>
1196     * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
1197     * relationship correctly:</p>
1198     * <pre>
1199     *   AnimatorSet s = new AnimatorSet();
1200     *   s.play(anim1).before(anim2);
1201     *   s.play(anim2).before(anim3);
1202     * </pre>
1203     * <p/>
1204     * <p>Note that it is possible to express relationships that cannot be resolved and will not
1205     * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
1206     * sense. In general, circular dependencies like this one (or more indirect ones where a depends
1207     * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
1208     * that can boil down to a simple, one-way relationship of animations starting with, before, and
1209     * after other, different, animations.</p>
1210     */
1211    public class Builder {
1212
1213        /**
1214         * This tracks the current node being processed. It is supplied to the play() method
1215         * of AnimatorSet and passed into the constructor of Builder.
1216         */
1217        private Node mCurrentNode;
1218
1219        /**
1220         * package-private constructor. Builders are only constructed by AnimatorSet, when the
1221         * play() method is called.
1222         *
1223         * @param anim The animation that is the dependency for the other animations passed into
1224         * the other methods of this Builder object.
1225         */
1226        Builder(Animator anim) {
1227            mDependencyDirty = true;
1228            mCurrentNode = getNodeForAnimation(anim);
1229        }
1230
1231        /**
1232         * Sets up the given animation to play at the same time as the animation supplied in the
1233         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
1234         *
1235         * @param anim The animation that will play when the animation supplied to the
1236         * {@link AnimatorSet#play(Animator)} method starts.
1237         */
1238        public Builder with(Animator anim) {
1239            Node node = getNodeForAnimation(anim);
1240            mCurrentNode.addSibling(node);
1241            return this;
1242        }
1243
1244        /**
1245         * Sets up the given animation to play when the animation supplied in the
1246         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1247         * ends.
1248         *
1249         * @param anim The animation that will play when the animation supplied to the
1250         * {@link AnimatorSet#play(Animator)} method ends.
1251         */
1252        public Builder before(Animator anim) {
1253            mReversible = false;
1254            Node node = getNodeForAnimation(anim);
1255            mCurrentNode.addChild(node);
1256            return this;
1257        }
1258
1259        /**
1260         * Sets up the given animation to play when the animation supplied in the
1261         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1262         * to start when the animation supplied in this method call ends.
1263         *
1264         * @param anim The animation whose end will cause the animation supplied to the
1265         * {@link AnimatorSet#play(Animator)} method to play.
1266         */
1267        public Builder after(Animator anim) {
1268            mReversible = false;
1269            Node node = getNodeForAnimation(anim);
1270            mCurrentNode.addParent(node);
1271            return this;
1272        }
1273
1274        /**
1275         * Sets up the animation supplied in the
1276         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
1277         * to play when the given amount of time elapses.
1278         *
1279         * @param delay The number of milliseconds that should elapse before the
1280         * animation starts.
1281         */
1282        public Builder after(long delay) {
1283            // setup dummy ValueAnimator just to run the clock
1284            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
1285            anim.setDuration(delay);
1286            after(anim);
1287            return this;
1288        }
1289
1290    }
1291
1292}
1293