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 
17 package android.animation;
18 
19 import android.app.ActivityThread;
20 import android.app.Application;
21 import android.os.Build;
22 import android.util.ArrayMap;
23 import android.util.Log;
24 
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import 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  */
55 public 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 
AnimatorSet()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      */
playTogether(Animator... items)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      */
playTogether(Collection<Animator> items)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      */
playSequentially(Animator... items)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      */
playSequentially(List<Animator> items)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      */
getChildAnimations()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
setTarget(Object target)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
getChangingConfigurations()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
setInterpolator(TimeInterpolator interpolator)300     public void setInterpolator(TimeInterpolator interpolator) {
301         mInterpolator = interpolator;
302     }
303 
304     @Override
getInterpolator()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      */
play(Animator anim)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
cancel()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
end()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      */
endRemainingAnimations()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
isRunning()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
isStarted()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
getStartDelay()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
setStartDelay(long startDelay)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
getDuration()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
setDuration(long duration)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
setupStartValues()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
setupEndValues()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
pause()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
resume()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
start()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 
updateAnimatorsDuration()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 
start(final Node node)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
clone()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 
AnimatorSetListener(AnimatorSet animatorSet)759         AnimatorSetListener(AnimatorSet animatorSet) {
760             mAnimatorSet = animatorSet;
761         }
762 
onAnimationCancel(Animator animation)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")
onAnimationEnd(Animator animation)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
onAnimationRepeat(Animator animation)788         public void onAnimationRepeat(Animator animation) {
789         }
790 
791         // Nothing to do
onAnimationStart(Animator animation)792         public void onAnimationStart(Animator animation) {
793         }
794 
795     }
796 
onChildAnimatorEnded(Animator animation)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
canReverse()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
reverse()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
toString()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 
printChildCount()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 
createDependencyGraph()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      */
updatePlayTime(Node parent, ArrayList<Node> visited)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
findSiblings(Node node, ArrayList<Node> 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 calculate
1068      * dynamically.
1069      * @return whether all the animators in the set are supposed to play together
1070      */
shouldPlayTogether()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.size() == mNodes.size() - 1;
1076     }
1077 
1078     @Override
getTotalDuration()1079     public long getTotalDuration() {
1080         updateAnimatorsDuration();
1081         createDependencyGraph();
1082         return mTotalDuration;
1083     }
1084 
getNodeForAnimation(Animator anim)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          */
Node(Animator animation)1152         public Node(Animator animation) {
1153             this.mAnimation = animation;
1154         }
1155 
1156         @Override
clone()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 
addChild(Node node)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 
addSibling(Node node)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 
addParent(Node node)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 
addParents(ArrayList<Node> parents)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          */
Builder(Animator anim)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          */
with(Animator anim)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          */
before(Animator anim)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          */
after(Animator anim)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          */
after(long delay)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