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