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