AnimatorSet.java revision d7444427d9f44b6b7448d4c21edca866132c8b59
117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase/*
217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Copyright (C) 2010 The Android Open Source Project
317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Licensed under the Apache License, Version 2.0 (the "License");
517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * you may not use this file except in compliance with the License.
617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * You may obtain a copy of the License at
717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *      http://www.apache.org/licenses/LICENSE-2.0
917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
1017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Unless required by applicable law or agreed to in writing, software
1117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * distributed under the License is distributed on an "AS IS" BASIS,
1217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * See the License for the specific language governing permissions and
1417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * limitations under the License.
1517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */
1617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
1717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haasepackage android.animation;
1817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
19d7444427d9f44b6b7448d4c21edca866132c8b59Doris Liuimport android.util.ArrayMap;
20d7444427d9f44b6b7448d4c21edca866132c8b59Doris Liu
2117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haaseimport java.util.ArrayList;
2237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haaseimport java.util.Collection;
2337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haaseimport java.util.List;
2417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
2517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase/**
26a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * This class plays a set of {@link Animator} objects in the specified order. Animations
2717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * can be set up to play together, in sequence, or after a specified delay.
2817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
29a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>There are two different approaches to adding animations to a <code>AnimatorSet</code>:
30a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or
31a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add
32a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be
33a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * used in conjunction with methods in the {@link AnimatorSet.Builder Builder}
3417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * class to add animations
3517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * one by one.</p>
3617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
37a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>It is possible to set up a <code>AnimatorSet</code> with circular dependencies between
3817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * its animations. For example, an animation a1 could be set up to start before animation a2, a2
3917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * before a3, and a3 before a1. The results of this configuration are undefined, but will typically
4017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * result in none of the affected animations being played. Because of this (and because
4117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * circular dependencies do not make logical sense anyway), circular dependencies
4217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * should be avoided, and the dependency flow of animations should only be in one direction.
433aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez *
443aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <div class="special reference">
453aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <h3>Developer Guides</h3>
463aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <p>For more information about animating with {@code AnimatorSet}, read the
473aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#choreography">Property
483aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * Animation</a> developer guide.</p>
493aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45Joe Fernandez * </div>
5017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */
51a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic final class AnimatorSet extends Animator {
5217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
5317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
5449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * Internal variables
5549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * NOTE: This object implements the clone() method, making a deep copy of any referenced
5649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * objects. As other non-trivial fields are added to this class, make sure to add logic
5749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * to clone() to make deep copies of them.
5849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     */
5949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
6049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    /**
613b69b6f0be85d1f97c1e6824cf986777ba4e5d00Chet Haase     * Tracks animations currently being played, so that we know what to
62a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * cancel or end when cancel() or end() is called on this AnimatorSet
6317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
64a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>();
6517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
6617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
67a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Contains all nodes, mapped to their respective Animators. When new
68a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * dependency information is added for an Animator, we want to add it
69a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * to a single node representing that Animator, not create a new Node
7017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * if one already exists.
7117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
72d7444427d9f44b6b7448d4c21edca866132c8b59Doris Liu    private ArrayMap<Animator, Node> mNodeMap = new ArrayMap<Animator, Node>();
7317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
7417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
75a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Set of all nodes created for this AnimatorSet. This list is used upon
76a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * starting the set, and the nodes are placed in sorted order into the
7717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * sortedNodes collection.
7817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
7949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private ArrayList<Node> mNodes = new ArrayList<Node>();
8017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
8117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
8217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * The sorted list of nodes. This is the order in which the animations will
8317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * be played. The details about when exactly they will be played depend
8417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * on the dependency relationships of the nodes.
8517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
8649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private ArrayList<Node> mSortedNodes = new ArrayList<Node>();
8717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
8817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
8917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * Flag indicating whether the nodes should be sorted prior to playing. This
9017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * flag allows us to cache the previous sorted nodes so that if the sequence
9117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * is replayed with no changes, it does not have to re-sort the nodes again.
9217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
9317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private boolean mNeedsSort = true;
9417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
95a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private AnimatorSetListener mSetListener = null;
9617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
9717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
987dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase     * Flag indicating that the AnimatorSet has been manually
997dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase     * terminated (by calling cancel() or end()).
100010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase     * This flag is used to avoid starting other animations when currently-playing
1017dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase     * child animations of this AnimatorSet end. It also determines whether cancel/end
1027dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase     * notifications are sent out via the normal AnimatorSetListener mechanism.
103010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase     */
1047dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase    boolean mTerminated = false;
105010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
1068b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    /**
1078b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * Indicates whether an AnimatorSet has been start()'d, whether or
1088b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * not there is a nonzero startDelay.
1098b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     */
1108b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    private boolean mStarted = false;
1118b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase
11221cd1389d2ef218b20994b617c57af120841a57fChet Haase    // The amount of time in ms to delay starting the animation after start() is called
11321cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mStartDelay = 0;
11421cd1389d2ef218b20994b617c57af120841a57fChet Haase
115e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase    // Animator used for a nonzero startDelay
116e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase    private ValueAnimator mDelayAnim = null;
117e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase
11821cd1389d2ef218b20994b617c57af120841a57fChet Haase
11921cd1389d2ef218b20994b617c57af120841a57fChet Haase    // How long the child animations should last in ms. The default value is negative, which
120a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    // simply means that there is no duration set on the AnimatorSet. When a real duration is
12121cd1389d2ef218b20994b617c57af120841a57fChet Haase    // set, it is passed along to the child animations.
12221cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mDuration = -1;
12321cd1389d2ef218b20994b617c57af120841a57fChet Haase
124430742f09063574271e6c4091de13b9b9e762514Chet Haase    // Records the interpolator for the set. Null value indicates that no interpolator
125430742f09063574271e6c4091de13b9b9e762514Chet Haase    // was set on this AnimatorSet, so it should not be passed down to the children.
126430742f09063574271e6c4091de13b9b9e762514Chet Haase    private TimeInterpolator mInterpolator = null;
127430742f09063574271e6c4091de13b9b9e762514Chet Haase
1287bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    private boolean mReversible = true;
129010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase    /**
130a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
131430742f09063574271e6c4091de13b9b9e762514Chet Haase     * This is equivalent to calling {@link #play(Animator)} with the first animator in the
132430742f09063574271e6c4091de13b9b9e762514Chet Haase     * set and then {@link Builder#with(Animator)} with each of the other animators. Note that
133430742f09063574271e6c4091de13b9b9e762514Chet Haase     * an Animator with a {@link Animator#setStartDelay(long) startDelay} will not actually
134430742f09063574271e6c4091de13b9b9e762514Chet Haase     * start until that delay elapses, which means that if the first animator in the list
135430742f09063574271e6c4091de13b9b9e762514Chet Haase     * supplied to this constructor has a startDelay, none of the other animators will start
136430742f09063574271e6c4091de13b9b9e762514Chet Haase     * until that first animator's startDelay has elapsed.
13717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
138a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @param items The animations that will be started simultaneously.
13917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
140a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public void playTogether(Animator... items) {
141a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        if (items != null) {
14217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
143a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Builder builder = play(items[0]);
144a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            for (int i = 1; i < items.length; ++i) {
145a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                builder.with(items[i]);
14617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
14717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
14817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
14917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
15017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
15137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
15237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     *
15337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * @param items The animations that will be started simultaneously.
15437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     */
15537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    public void playTogether(Collection<Animator> items) {
15637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase        if (items != null && items.size() > 0) {
15737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            mNeedsSort = true;
15837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            Builder builder = null;
15937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            for (Animator anim : items) {
16037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                if (builder == null) {
16137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                    builder = play(anim);
16237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                } else {
16337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                    builder.with(anim);
16437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                }
16537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            }
16637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase        }
16737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    }
16837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase
16937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    /**
170a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets up this AnimatorSet to play each of the supplied animations when the
17117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * previous animation ends.
17217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
17337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * @param items The animations that will be started one after another.
17417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
175a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public void playSequentially(Animator... items) {
176a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        if (items != null) {
17717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
178a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (items.length == 1) {
179a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                play(items[0]);
18017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            } else {
1817bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui                mReversible = false;
182a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                for (int i = 0; i < items.length - 1; ++i) {
183a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    play(items[i]).before(items[i+1]);
18417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
18517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
18617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
18717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
18817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
18917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
19037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * Sets up this AnimatorSet to play each of the supplied animations when the
19137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * previous animation ends.
19237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     *
19337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * @param items The animations that will be started one after another.
19437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     */
19537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    public void playSequentially(List<Animator> items) {
19637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase        if (items != null && items.size() > 0) {
19737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            mNeedsSort = true;
19837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            if (items.size() == 1) {
19937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                play(items.get(0));
20037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            } else {
2017bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui                mReversible = false;
20237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                for (int i = 0; i < items.size() - 1; ++i) {
20337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                    play(items.get(i)).before(items.get(i+1));
20437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                }
20537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            }
20637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase        }
20737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    }
20837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase
20937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    /**
210a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Returns the current list of child Animator objects controlled by this
211a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet. This is a copy of the internal list; modifications to the returned list
212a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * will not affect the AnimatorSet, although changes to the underlying Animator objects
213a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * will affect those objects being managed by the AnimatorSet.
214f54a8d7c479485174941c38f151ea7083c658da3Chet Haase     *
215a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return ArrayList<Animator> The list of child animations of this AnimatorSet.
216f54a8d7c479485174941c38f151ea7083c658da3Chet Haase     */
217a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public ArrayList<Animator> getChildAnimations() {
218a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        ArrayList<Animator> childList = new ArrayList<Animator>();
219f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        for (Node node : mNodes) {
220f54a8d7c479485174941c38f151ea7083c658da3Chet Haase            childList.add(node.animation);
221f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        }
222f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        return childList;
223f54a8d7c479485174941c38f151ea7083c658da3Chet Haase    }
224f54a8d7c479485174941c38f151ea7083c658da3Chet Haase
225f54a8d7c479485174941c38f151ea7083c658da3Chet Haase    /**
226811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     * Sets the target object for all current {@link #getChildAnimations() child animations}
227a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * of this AnimatorSet that take targets ({@link ObjectAnimator} and
228a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet).
229811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     *
230811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     * @param target The object being animated
231811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     */
23221cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
233811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    public void setTarget(Object target) {
234811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase        for (Node node : mNodes) {
235a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Animator animation = node.animation;
236a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (animation instanceof AnimatorSet) {
237a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                ((AnimatorSet)animation).setTarget(target);
238a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            } else if (animation instanceof ObjectAnimator) {
239a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                ((ObjectAnimator)animation).setTarget(target);
240811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase            }
241811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase        }
242811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    }
243811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase
244811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    /**
245d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar     * @hide
246d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar     */
247d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    @Override
248d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    public int getChangingConfigurations() {
249d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        int conf = super.getChangingConfigurations();
250d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final int nodeCount = mNodes.size();
251d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        for (int i = 0; i < nodeCount; i ++) {
252d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            conf |= mNodes.get(i).animation.getChangingConfigurations();
253d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        }
254d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        return conf;
255d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    }
256d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar
257d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar    /**
258e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase     * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
259430742f09063574271e6c4091de13b9b9e762514Chet Haase     * of this AnimatorSet. The default value is null, which means that no interpolator
260430742f09063574271e6c4091de13b9b9e762514Chet Haase     * is set on this AnimatorSet. Setting the interpolator to any non-null value
261430742f09063574271e6c4091de13b9b9e762514Chet Haase     * will cause that interpolator to be set on the child animations
262430742f09063574271e6c4091de13b9b9e762514Chet Haase     * when the set is started.
26321cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
264a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @param interpolator the interpolator to be used by each child animation of this AnimatorSet
26521cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
26621cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
267e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase    public void setInterpolator(TimeInterpolator interpolator) {
268430742f09063574271e6c4091de13b9b9e762514Chet Haase        mInterpolator = interpolator;
269430742f09063574271e6c4091de13b9b9e762514Chet Haase    }
270430742f09063574271e6c4091de13b9b9e762514Chet Haase
271430742f09063574271e6c4091de13b9b9e762514Chet Haase    @Override
272430742f09063574271e6c4091de13b9b9e762514Chet Haase    public TimeInterpolator getInterpolator() {
273430742f09063574271e6c4091de13b9b9e762514Chet Haase        return mInterpolator;
27421cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
27521cd1389d2ef218b20994b617c57af120841a57fChet Haase
27621cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
27717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This method creates a <code>Builder</code> object, which is used to
27817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * set up playing constraints. This initial <code>play()</code> method
27917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * tells the <code>Builder</code> the animation that is the dependency for
28017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * the succeeding commands to the <code>Builder</code>. For example,
281a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * calling <code>play(a1).with(a2)</code> sets up the AnimatorSet to play
28217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a1</code> and <code>a2</code> at the same time,
283a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>play(a1).before(a2)</code> sets up the AnimatorSet to play
28417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a1</code> first, followed by <code>a2</code>, and
285a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>play(a1).after(a2)</code> sets up the AnimatorSet to play
28617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a2</code> first, followed by <code>a1</code>.
28717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
28817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>Note that <code>play()</code> is the only way to tell the
28917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>Builder</code> the animation upon which the dependency is created,
29017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * so successive calls to the various functions in <code>Builder</code>
29117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * will all refer to the initial parameter supplied in <code>play()</code>
29217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * as the dependency of the other animations. For example, calling
29317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code>
29417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * and <code>a3</code> when a1 ends; it does not set up a dependency between
29517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a2</code> and <code>a3</code>.</p>
29617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
29717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * @param anim The animation that is the dependency used in later calls to the
29817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * methods in the returned <code>Builder</code> object. A null parameter will result
29917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * in a null <code>Builder</code> return value.
300a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return Builder The object that constructs the AnimatorSet based on the dependencies
30117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * outlined in the calls to <code>play</code> and the other methods in the
30217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>Builder</code object.
30317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
304a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public Builder play(Animator anim) {
30517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (anim != null) {
30617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
30717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            return new Builder(anim);
30817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
30917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        return null;
31017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
31117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
31217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
31317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
31417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
3158b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * <p>Note that canceling a <code>AnimatorSet</code> also cancels all of the animations that it
3168b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * is responsible for.</p>
31717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
31817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @SuppressWarnings("unchecked")
31917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
32017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void cancel() {
3217dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase        mTerminated = true;
3228b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        if (isStarted()) {
3237dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            ArrayList<AnimatorListener> tmpListeners = null;
324e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            if (mListeners != null) {
3257dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
326e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                for (AnimatorListener listener : tmpListeners) {
3277dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    listener.onAnimationCancel(this);
328e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                }
329e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            }
3307dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mDelayAnim != null && mDelayAnim.isRunning()) {
3317dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // If we're currently in the startDelay period, just cancel that animator and
3327dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // send out the end event to all listeners
3337dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                mDelayAnim.cancel();
3347dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            } else  if (mSortedNodes.size() > 0) {
3357dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (Node node : mSortedNodes) {
3367dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    node.animation.cancel();
3377dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                }
3387dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            }
3397dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (tmpListeners != null) {
3407dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (AnimatorListener listener : tmpListeners) {
3417dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    listener.onAnimationEnd(this);
3427dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                }
34317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
3448b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            mStarted = false;
34517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
34617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
34717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
34817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
34917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
35017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
351a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Note that ending a <code>AnimatorSet</code> also ends all of the animations that it is
35217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * responsible for.</p>
35317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
35417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
35517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void end() {
3567dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase        mTerminated = true;
3578b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        if (isStarted()) {
3587dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mSortedNodes.size() != mNodes.size()) {
3597dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // hasn't been started yet - sort the nodes now, then end them
3607dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                sortNodes();
3617dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (Node node : mSortedNodes) {
3627dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (mSetListener == null) {
3637dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        mSetListener = new AnimatorSetListener(this);
3647dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    }
3657dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    node.animation.addListener(mSetListener);
3661e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase                }
3671e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase            }
3687dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mDelayAnim != null) {
3697dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                mDelayAnim.cancel();
3707dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            }
3717dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mSortedNodes.size() > 0) {
3727dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (Node node : mSortedNodes) {
3737dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    node.animation.end();
3747dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                }
3757dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            }
3767dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mListeners != null) {
3777dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                ArrayList<AnimatorListener> tmpListeners =
3787dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        (ArrayList<AnimatorListener>) mListeners.clone();
3797dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (AnimatorListener listener : tmpListeners) {
3807dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    listener.onAnimationEnd(this);
3817dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                }
38217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
3838b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            mStarted = false;
38417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
38517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
38617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
38717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
3888b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * Returns true if any of the child animations of this AnimatorSet have been started and have
3898b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * not yet ended.
390a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return Whether this AnimatorSet has been started and has not yet ended.
391673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase     */
392673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    @Override
393673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    public boolean isRunning() {
394673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase        for (Node node : mNodes) {
395673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase            if (node.animation.isRunning()) {
396673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase                return true;
397673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase            }
398673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase        }
3998b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        return false;
4008b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    }
4018b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase
4028b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    @Override
4038b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    public boolean isStarted() {
4048b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        return mStarted;
405673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    }
406673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase
407673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    /**
40821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The amount of time, in milliseconds, to delay starting the animation after
40921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * {@link #start()} is called.
41021cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
41121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return the number of milliseconds to delay running the animation
41221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
41321cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
41421cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getStartDelay() {
41521cd1389d2ef218b20994b617c57af120841a57fChet Haase        return mStartDelay;
41621cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
41721cd1389d2ef218b20994b617c57af120841a57fChet Haase
41821cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
41921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The amount of time, in milliseconds, to delay starting the animation after
42021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * {@link #start()} is called.
42121cd1389d2ef218b20994b617c57af120841a57fChet Haase
42221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param startDelay The amount of the delay, in milliseconds
42321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
42421cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
42521cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void setStartDelay(long startDelay) {
4267bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        if (mStartDelay > 0) {
4277bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            mReversible = false;
4287bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        }
42921cd1389d2ef218b20994b617c57af120841a57fChet Haase        mStartDelay = startDelay;
43021cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
43121cd1389d2ef218b20994b617c57af120841a57fChet Haase
43221cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
433a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Gets the length of each of the child animations of this AnimatorSet. This value may
434a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * be less than 0, which indicates that no duration has been set on this AnimatorSet
43521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * and each of the child animations will use their own duration.
43621cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
43721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return The length of the animation, in milliseconds, of each of the child
438a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * animations of this AnimatorSet.
43921cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
44021cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
44121cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getDuration() {
44221cd1389d2ef218b20994b617c57af120841a57fChet Haase        return mDuration;
44321cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
44421cd1389d2ef218b20994b617c57af120841a57fChet Haase
44521cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
446a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets the length of each of the current child animations of this AnimatorSet. By default,
447a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * each child animation will use its own duration. If the duration is set on the AnimatorSet,
44821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * then each child animation inherits this duration.
44921cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
45021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param duration The length of the animation, in milliseconds, of each of the child
451a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * animations of this AnimatorSet.
45221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
45321cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
4542794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public AnimatorSet setDuration(long duration) {
45521cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (duration < 0) {
45621cd1389d2ef218b20994b617c57af120841a57fChet Haase            throw new IllegalArgumentException("duration must be a value of zero or greater");
45721cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
458c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase        // Just record the value for now - it will be used later when the AnimatorSet starts
45921cd1389d2ef218b20994b617c57af120841a57fChet Haase        mDuration = duration;
4602794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        return this;
46121cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
46221cd1389d2ef218b20994b617c57af120841a57fChet Haase
4632970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    @Override
4642970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    public void setupStartValues() {
4652970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        for (Node node : mNodes) {
4662970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            node.animation.setupStartValues();
4672970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        }
4682970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    }
4692970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase
4702970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    @Override
4712970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    public void setupEndValues() {
4722970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        for (Node node : mNodes) {
4732970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            node.animation.setupEndValues();
4742970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        }
4752970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    }
4762970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase
4778aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase    @Override
4788aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase    public void pause() {
4798aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        boolean previouslyPaused = mPaused;
4808aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        super.pause();
4818aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        if (!previouslyPaused && mPaused) {
4828aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase            if (mDelayAnim != null) {
4838aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                mDelayAnim.pause();
4848aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase            } else {
4858aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                for (Node node : mNodes) {
4868aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                    node.animation.pause();
4878aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                }
4888aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase            }
4898aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        }
4908aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase    }
4918aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase
4928aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase    @Override
4938aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase    public void resume() {
4948aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        boolean previouslyPaused = mPaused;
4958aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        super.resume();
4968aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        if (previouslyPaused && !mPaused) {
4978aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase            if (mDelayAnim != null) {
4988aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                mDelayAnim.resume();
4998aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase            } else {
5008aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                for (Node node : mNodes) {
5018aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                    node.animation.resume();
5028aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                }
5038aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase            }
5048aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        }
5058aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase    }
5068aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase
50721cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
50817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
50917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
510a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which
51117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * it is responsible. The details of when exactly those animations are started depends on
51217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * the dependency relationships that have been set up between the animations.
51317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
51417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @SuppressWarnings("unchecked")
51517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
51617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void start() {
5177dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase        mTerminated = false;
5188b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        mStarted = true;
5198aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase        mPaused = false;
520010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
521f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck        for (Node node : mNodes) {
522f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck            node.animation.setAllowRunningAsynchronously(false);
523f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck        }
524f5945a0c8bb868f978d9d0d22043a8b44464a86eJohn Reck
525c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase        if (mDuration >= 0) {
526c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase            // If the duration was set on this AnimatorSet, pass it along to all child animations
527c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase            for (Node node : mNodes) {
528c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase                // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
529c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase                // insert "play-after" delays
530c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase                node.animation.setDuration(mDuration);
531c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase            }
532c299a3384171e36fc9ab6d1011d8a589a7f344d1Chet Haase        }
533430742f09063574271e6c4091de13b9b9e762514Chet Haase        if (mInterpolator != null) {
534430742f09063574271e6c4091de13b9b9e762514Chet Haase            for (Node node : mNodes) {
535430742f09063574271e6c4091de13b9b9e762514Chet Haase                node.animation.setInterpolator(mInterpolator);
536430742f09063574271e6c4091de13b9b9e762514Chet Haase            }
537430742f09063574271e6c4091de13b9b9e762514Chet Haase        }
5387bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        // First, sort the nodes (if necessary). This will ensure that sortedNodes
53917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // contains the animation nodes in the correct order.
54017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        sortNodes();
54117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
542e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase        int numSortedNodes = mSortedNodes.size();
543e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase        for (int i = 0; i < numSortedNodes; ++i) {
544e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            Node node = mSortedNodes.get(i);
545e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            // First, clear out the old listeners
546e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
547e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            if (oldListeners != null && oldListeners.size() > 0) {
548d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen                final ArrayList<AnimatorListener> clonedListeners = new
549d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen                        ArrayList<AnimatorListener>(oldListeners);
550d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen
551d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen                for (AnimatorListener listener : clonedListeners) {
5527dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (listener instanceof DependencyListener ||
5537dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                            listener instanceof AnimatorSetListener) {
554e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                        node.animation.removeListener(listener);
555e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                    }
556e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                }
557e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            }
558e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase        }
559e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase
56017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // nodesToStart holds the list of nodes to be started immediately. We don't want to
56117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // start the animations in the loop directly because we first need to set up
56217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // dependencies on all of the nodes. For example, we don't want to start an animation
56317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // when some other animation also wants to start when the first animation begins.
56421cd1389d2ef218b20994b617c57af120841a57fChet Haase        final ArrayList<Node> nodesToStart = new ArrayList<Node>();
5657c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        for (int i = 0; i < numSortedNodes; ++i) {
5667c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            Node node = mSortedNodes.get(i);
567a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (mSetListener == null) {
568a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                mSetListener = new AnimatorSetListener(this);
56917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
57017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node.dependencies == null || node.dependencies.size() == 0) {
57117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodesToStart.add(node);
57217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            } else {
5737c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                int numDependencies = node.dependencies.size();
5747c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                for (int j = 0; j < numDependencies; ++j) {
5757c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Dependency dependency = node.dependencies.get(j);
57617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependency.node.animation.addListener(
577010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                            new DependencyListener(this, node, dependency.rule));
57817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
57917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone();
58017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
581a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            node.animation.addListener(mSetListener);
58217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
58317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Now that all dependencies are set up, start the animations that should be started.
58421cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (mStartDelay <= 0) {
58521cd1389d2ef218b20994b617c57af120841a57fChet Haase            for (Node node : nodesToStart) {
58621cd1389d2ef218b20994b617c57af120841a57fChet Haase                node.animation.start();
58721cd1389d2ef218b20994b617c57af120841a57fChet Haase                mPlayingSet.add(node.animation);
58821cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
58921cd1389d2ef218b20994b617c57af120841a57fChet Haase        } else {
590e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
591e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            mDelayAnim.setDuration(mStartDelay);
592e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            mDelayAnim.addListener(new AnimatorListenerAdapter() {
593e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                boolean canceled = false;
594e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                public void onAnimationCancel(Animator anim) {
595e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                    canceled = true;
596e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                }
597a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                public void onAnimationEnd(Animator anim) {
598e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                    if (!canceled) {
599e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                        int numNodes = nodesToStart.size();
600e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                        for (int i = 0; i < numNodes; ++i) {
601e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                            Node node = nodesToStart.get(i);
602e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                            node.animation.start();
603e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                            mPlayingSet.add(node.animation);
604e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                        }
60521cd1389d2ef218b20994b617c57af120841a57fChet Haase                    }
6068aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                    mDelayAnim = null;
60721cd1389d2ef218b20994b617c57af120841a57fChet Haase                }
60821cd1389d2ef218b20994b617c57af120841a57fChet Haase            });
609e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            mDelayAnim.start();
61017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
61117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (mListeners != null) {
612a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ArrayList<AnimatorListener> tmpListeners =
613a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    (ArrayList<AnimatorListener>) mListeners.clone();
6147c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            int numListeners = tmpListeners.size();
6157c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            for (int i = 0; i < numListeners; ++i) {
6167c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                tmpListeners.get(i).onAnimationStart(this);
6178b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            }
6188b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        }
6198b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        if (mNodes.size() == 0 && mStartDelay == 0) {
6208b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            // Handle unusual case where empty AnimatorSet is started - should send out
6218b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            // end event immediately since the event will not be sent out at all otherwise
6228b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            mStarted = false;
6238b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            if (mListeners != null) {
6248b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                ArrayList<AnimatorListener> tmpListeners =
6258b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                        (ArrayList<AnimatorListener>) mListeners.clone();
6268b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                int numListeners = tmpListeners.size();
6278b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                for (int i = 0; i < numListeners; ++i) {
6282970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase                    tmpListeners.get(i).onAnimationEnd(this);
6292970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase                }
63017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
63117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
63217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
63317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
63449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    @Override
635a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public AnimatorSet clone() {
636a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        final AnimatorSet anim = (AnimatorSet) super.clone();
63749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        /*
63849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * The basic clone() operation copies all items. This doesn't work very well for
639a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * AnimatorSet, because it will copy references that need to be recreated and state
64049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * that may not apply. What we need to do now is put the clone in an uninitialized
64149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * state, with fresh, empty data structures. Then we will build up the nodes list
64249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * manually, as we clone each Node (and its animation). The clone will then be sorted,
64349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * and will populate any appropriate lists, when it is started.
64449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         */
645d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        final int nodeCount = mNodes.size();
64649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        anim.mNeedsSort = true;
6477dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase        anim.mTerminated = false;
6488b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        anim.mStarted = false;
649a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        anim.mPlayingSet = new ArrayList<Animator>();
650d7444427d9f44b6b7448d4c21edca866132c8b59Doris Liu        anim.mNodeMap = new ArrayMap<Animator, Node>();
651d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        anim.mNodes = new ArrayList<Node>(nodeCount);
652d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        anim.mSortedNodes = new ArrayList<Node>(nodeCount);
6537bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        anim.mReversible = mReversible;
6546f6578e81c1df207da47e2e1337382341f271206Chet Haase        anim.mSetListener = null;
65549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
65649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
657a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
65849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
659d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar
660d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        for (int n = 0; n < nodeCount; n++) {
661d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            final Node node = mNodes.get(n);
66249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            Node nodeClone = node.clone();
663d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            node.mTmpClone = nodeClone;
66449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            anim.mNodes.add(nodeClone);
66549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            anim.mNodeMap.put(nodeClone.animation, nodeClone);
66649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            // Clear out the dependencies in the clone; we'll set these up manually later
66749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.dependencies = null;
66849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.tmpDependencies = null;
66949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.nodeDependents = null;
67049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.nodeDependencies = null;
671d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar
672a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            // clear out any listeners that were set up by the AnimatorSet; these will
67349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            // be set up when the clone's nodes are sorted
674d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            final ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
67549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            if (cloneListeners != null) {
676d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                for (int i = cloneListeners.size() - 1; i >= 0; i--) {
677d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    final AnimatorListener listener = cloneListeners.get(i);
678a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    if (listener instanceof AnimatorSetListener) {
679d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                        cloneListeners.remove(i);
68049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    }
68149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                }
68249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            }
68349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
68449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // Now that we've cloned all of the nodes, we're ready to walk through their
68549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // dependencies, mapping the old dependencies to the new nodes
686d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        for (int n = 0; n < nodeCount; n++) {
687d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            final Node node = mNodes.get(n);
688d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            final Node clone = node.mTmpClone;
68949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            if (node.dependencies != null) {
690d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                clone.dependencies = new ArrayList<Dependency>(node.dependencies.size());
691d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                final int depSize = node.dependencies.size();
692d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                for (int i = 0; i < depSize; i ++) {
693d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    final Dependency dependency = node.dependencies.get(i);
694d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    Dependency cloneDependency = new Dependency(dependency.node.mTmpClone,
69549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                            dependency.rule);
696d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    clone.dependencies.add(cloneDependency);
697d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                }
698d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
699d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (node.nodeDependents != null) {
700d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                clone.nodeDependents = new ArrayList<Node>(node.nodeDependents.size());
701d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                for (Node dep : node.nodeDependents) {
702d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    clone.nodeDependents.add(dep.mTmpClone);
703d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                }
704d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            }
705d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            if (node.nodeDependencies != null) {
706d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                clone.nodeDependencies = new ArrayList<Node>(node.nodeDependencies.size());
707d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                for (Node dep : node.nodeDependencies) {
708d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar                    clone.nodeDependencies.add(dep.mTmpClone);
70949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                }
71049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            }
71149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
712d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        for (int n = 0; n < nodeCount; n++) {
713d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar            mNodes.get(n).mTmpClone = null;
714d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        }
71549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        return anim;
71649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    }
71749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
71817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
71917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This class is the mechanism by which animations are started based on events in other
72017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * animations. If an animation has multiple dependencies on other animations, then
72117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * all dependencies must be satisfied before the animation is started.
72217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
723a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private static class DependencyListener implements AnimatorListener {
72417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
725a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private AnimatorSet mAnimatorSet;
726010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
72717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The node upon which the dependency is based.
72817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private Node mNode;
72917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
73017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The Dependency rule (WITH or AFTER) that the listener should wait for on
73117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // the node
73217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private int mRule;
73317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
734a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public DependencyListener(AnimatorSet animatorSet, Node node, int rule) {
735a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            this.mAnimatorSet = animatorSet;
73617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.mNode = node;
73717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.mRule = rule;
73817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
73917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
74017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
741010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * Ignore cancel events for now. We may want to handle this eventually,
742010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * to prevent follow-on animations from running when some dependency
743010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * animation is canceled.
74417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
745a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationCancel(Animator animation) {
74617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
74717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
74817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
74917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * An end event is received - see if this is an event we are listening for
75017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
751a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationEnd(Animator animation) {
75217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mRule == Dependency.AFTER) {
75317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                startIfReady(animation);
75417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
75517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
75617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
75717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
75817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Ignore repeat events for now
75917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
760a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationRepeat(Animator animation) {
76117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
76217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
76317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
76417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * A start event is received - see if this is an event we are listening for
76517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
766a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationStart(Animator animation) {
76717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mRule == Dependency.WITH) {
76817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                startIfReady(animation);
76917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
77017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
77117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
77217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
77317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Check whether the event received is one that the node was waiting for.
77417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * If so, mark it as complete and see whether it's time to start
77517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the animation.
77617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param dependencyAnimation the animation that sent the event.
77717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
778a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private void startIfReady(Animator dependencyAnimation) {
7797dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mAnimatorSet.mTerminated) {
780a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                // if the parent AnimatorSet was canceled, then don't start any dependent anims
781010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                return;
782010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase            }
78317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependencyToRemove = null;
7847c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            int numDependencies = mNode.tmpDependencies.size();
7857c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            for (int i = 0; i < numDependencies; ++i) {
7867c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                Dependency dependency = mNode.tmpDependencies.get(i);
78717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (dependency.rule == mRule &&
78817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        dependency.node.animation == dependencyAnimation) {
78917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    // rule fired - remove the dependency and listener and check to
79017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    // see whether it's time to start the animation
79117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependencyToRemove = dependency;
79217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependencyAnimation.removeListener(this);
79317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    break;
79417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
79517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
79617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNode.tmpDependencies.remove(dependencyToRemove);
79717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mNode.tmpDependencies.size() == 0) {
79817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                // all dependencies satisfied: start the animation
79917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNode.animation.start();
800a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                mAnimatorSet.mPlayingSet.add(mNode.animation);
80117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
80217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
80317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
80417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
80517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
806a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private class AnimatorSetListener implements AnimatorListener {
80717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
808a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private AnimatorSet mAnimatorSet;
80917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
810a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        AnimatorSetListener(AnimatorSet animatorSet) {
811a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            mAnimatorSet = animatorSet;
81217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
81317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
814a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationCancel(Animator animation) {
8157dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (!mTerminated) {
8167dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // Listeners are already notified of the AnimatorSet canceling in cancel().
8177dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // The logic below only kicks in when animations end normally
8187dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                if (mPlayingSet.size() == 0) {
8197dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (mListeners != null) {
8207dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        int numListeners = mListeners.size();
8217dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        for (int i = 0; i < numListeners; ++i) {
8227dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                            mListeners.get(i).onAnimationCancel(mAnimatorSet);
8237dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        }
82417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
82517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
82617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
82717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
82817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
82917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        @SuppressWarnings("unchecked")
830a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationEnd(Animator animation) {
83117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            animation.removeListener(this);
83217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mPlayingSet.remove(animation);
833a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Node animNode = mAnimatorSet.mNodeMap.get(animation);
8341e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase            animNode.done = true;
8357dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (!mTerminated) {
8367dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // Listeners are already notified of the AnimatorSet ending in cancel() or
8377dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // end(); the logic below only kicks in when animations end normally
8387dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
8397dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                boolean allDone = true;
8407dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                int numSortedNodes = sortedNodes.size();
8417dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (int i = 0; i < numSortedNodes; ++i) {
8427dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (!sortedNodes.get(i).done) {
8437dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        allDone = false;
8447dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        break;
8457dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    }
846a6e4a1757728efc91627ece602b0899d75303659Chet Haase                }
8477dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                if (allDone) {
8487dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    // If this was the last child animation to end, then notify listeners that this
8497dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    // AnimatorSet has ended
8507dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (mListeners != null) {
8517dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        ArrayList<AnimatorListener> tmpListeners =
8527dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                                (ArrayList<AnimatorListener>) mListeners.clone();
8537dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        int numListeners = tmpListeners.size();
8547dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        for (int i = 0; i < numListeners; ++i) {
8557dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                            tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
8567dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        }
85717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
8588b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                    mAnimatorSet.mStarted = false;
8598aa1ffb0ed292891030992c65df4e5dc8bd37524Chet Haase                    mAnimatorSet.mPaused = false;
86017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
86117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
86217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
86317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
86417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Nothing to do
865a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationRepeat(Animator animation) {
86617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
86717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
86817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Nothing to do
869a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationStart(Animator animation) {
87017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
87117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
87217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
87317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
87417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
87517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This method sorts the current set of nodes, if needed. The sort is a simple
87617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * DependencyGraph sort, which goes like this:
87717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * - All nodes without dependencies become 'roots'
87817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * - while roots list is not null
87917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -   for each root r
88017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -     add r to sorted list
88117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -     remove r as a dependency from any other node
88217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -   any nodes with no dependencies are added to the roots list
88317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
88417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private void sortNodes() {
88517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (mNeedsSort) {
88617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mSortedNodes.clear();
88717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            ArrayList<Node> roots = new ArrayList<Node>();
8887c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            int numNodes = mNodes.size();
8897c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            for (int i = 0; i < numNodes; ++i) {
8907c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                Node node = mNodes.get(i);
89117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (node.dependencies == null || node.dependencies.size() == 0) {
89217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    roots.add(node);
89317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
89417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
89517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            ArrayList<Node> tmpRoots = new ArrayList<Node>();
89617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            while (roots.size() > 0) {
8977c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                int numRoots = roots.size();
8987c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                for (int i = 0; i < numRoots; ++i) {
8997c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Node root = roots.get(i);
90017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    mSortedNodes.add(root);
90117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    if (root.nodeDependents != null) {
9027c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                        int numDependents = root.nodeDependents.size();
9037c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                        for (int j = 0; j < numDependents; ++j) {
9047c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                            Node node = root.nodeDependents.get(j);
90517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies.remove(root);
90617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            if (node.nodeDependencies.size() == 0) {
90717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                                tmpRoots.add(node);
90817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            }
90917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
91017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
91117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
912010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                roots.clear();
91317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                roots.addAll(tmpRoots);
91417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                tmpRoots.clear();
91517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
91617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = false;
91717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mSortedNodes.size() != mNodes.size()) {
91817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                throw new IllegalStateException("Circular dependencies cannot exist"
919a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                        + " in AnimatorSet");
92017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
92117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        } else {
92217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // Doesn't need sorting, but still need to add in the nodeDependencies list
92317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // because these get removed as the event listeners fire and the dependencies
92417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // are satisfied
9257c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            int numNodes = mNodes.size();
9267c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            for (int i = 0; i < numNodes; ++i) {
9277c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                Node node = mNodes.get(i);
92817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (node.dependencies != null && node.dependencies.size() > 0) {
9297c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    int numDependencies = node.dependencies.size();
9307c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    for (int j = 0; j < numDependencies; ++j) {
9317c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                        Dependency dependency = node.dependencies.get(j);
93217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        if (node.nodeDependencies == null) {
93317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies = new ArrayList<Node>();
93417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
93517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        if (!node.nodeDependencies.contains(dependency.node)) {
93617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies.add(dependency.node);
93717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
93817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
93917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
9407dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // nodes are 'done' by default; they become un-done when started, and done
9417dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // again when ended
9421e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase                node.done = false;
94317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
94417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
94517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
94617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
94717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
9487bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui     * @hide
9497bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui     */
9507bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    @Override
9517bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    public boolean canReverse() {
9527bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        if (!mReversible)  {
9537bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            return false;
9547bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        }
9557bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        // Loop to make sure all the Nodes can reverse.
9567bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        for (Node node : mNodes) {
9577bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            if (!node.animation.canReverse() || node.animation.getStartDelay() > 0) {
9587bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui                return false;
9597bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            }
9607bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        }
9617bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        return true;
9627bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    }
9637bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui
9647bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    /**
9657bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui     * @hide
9667bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui     */
9677bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    @Override
9687bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    public void reverse() {
9697bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        if (canReverse()) {
9707bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            for (Node node : mNodes) {
9717bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui                node.animation.reverse();
9727bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            }
9737bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui        }
9747bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    }
9757bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui
976d430753cba09acb07af8b313286f247c78a41a32Chet Haase    @Override
977d430753cba09acb07af8b313286f247c78a41a32Chet Haase    public String toString() {
978d430753cba09acb07af8b313286f247c78a41a32Chet Haase        String returnVal = "AnimatorSet@" + Integer.toHexString(hashCode()) + "{";
979d430753cba09acb07af8b313286f247c78a41a32Chet Haase        boolean prevNeedsSort = mNeedsSort;
980d430753cba09acb07af8b313286f247c78a41a32Chet Haase        sortNodes();
981d430753cba09acb07af8b313286f247c78a41a32Chet Haase        mNeedsSort = prevNeedsSort;
982d430753cba09acb07af8b313286f247c78a41a32Chet Haase        for (Node node : mSortedNodes) {
983d430753cba09acb07af8b313286f247c78a41a32Chet Haase            returnVal += "\n    " + node.animation.toString();
984d430753cba09acb07af8b313286f247c78a41a32Chet Haase        }
985d430753cba09acb07af8b313286f247c78a41a32Chet Haase        return returnVal + "\n}";
986d430753cba09acb07af8b313286f247c78a41a32Chet Haase    }
987d430753cba09acb07af8b313286f247c78a41a32Chet Haase
9887bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui    /**
98917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * Dependency holds information about the node that some other node is
99017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * dependent upon and the nature of that dependency.
99117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
99217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
99317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private static class Dependency {
99417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        static final int WITH = 0; // dependent node must start with this dependency node
99517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        static final int AFTER = 1; // dependent node must start when this dependency node finishes
99617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
99717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The node that the other node with this Dependency is dependent upon
99817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public Node node;
99917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
100017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The nature of the dependency (WITH or AFTER)
100117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public int rule;
100217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
100317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public Dependency(Node node, int rule) {
100417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.node = node;
100517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.rule = rule;
100617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
100717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
100817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
100917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
1010a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * A Node is an embodiment of both the Animator that it wraps as well as
101117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * any dependencies that are associated with that Animation. This includes
101217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * both dependencies upon other nodes (in the dependencies list) as
101317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * well as dependencies of other nodes upon this (in the nodeDependents list).
101417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
101549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private static class Node implements Cloneable {
1016a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public Animator animation;
101717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
101817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
101917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  These are the dependencies that this node's animation has on other
102017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  nodes. For example, if this node's animation should begin with some
102117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  other animation ends, then there will be an item in this node's
102217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  dependencies list for that other animation's node.
102317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
102417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Dependency> dependencies = null;
102517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
102617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
102717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * tmpDependencies is a runtime detail. We use the dependencies list for sorting.
102817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * But we also use the list to keep track of when multiple dependencies are satisfied,
102917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * but removing each dependency as it is satisfied. We do not want to remove
103017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the dependency itself from the list, because we need to retain that information
1031a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * if the AnimatorSet is launched in the future. So we create a copy of the dependency
1032a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * list when the AnimatorSet starts and use this tmpDependencies list to track the
103317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * list of satisfied dependencies.
103417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
103517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Dependency> tmpDependencies = null;
103617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
103717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
103817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * nodeDependencies is just a list of the nodes that this Node is dependent upon.
103917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * This information is used in sortNodes(), to determine when a node is a root.
104017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
104117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Node> nodeDependencies = null;
104217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
104317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
104417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * nodeDepdendents is the list of nodes that have this node as a dependency. This
104517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * is a utility field used in sortNodes to facilitate removing this node as a
104617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * dependency when it is a root node.
104717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
104817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Node> nodeDependents = null;
104917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
105017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
10511e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase         * Flag indicating whether the animation in this node is finished. This flag
1052a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * is used by AnimatorSet to check, as each animation ends, whether all child animations
1053a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * are done and it's time to send out an end event for the entire AnimatorSet.
10541e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase         */
10551e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase        public boolean done = false;
10561e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase
10571e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase        /**
1058d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar         * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
1059d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar         */
1060d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        private Node mTmpClone = null;
1061d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar
1062d422dc358f0100106dc07d7b903201eb9b043b11Yigit Boyar        /**
106317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Constructs the Node with the animation that it encapsulates. A Node has no
106417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * dependencies by default; dependencies are added via the addDependency()
106517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * method.
106617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
106717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param animation The animation that the Node encapsulates.
106817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
1069a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public Node(Animator animation) {
107017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.animation = animation;
107117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
107217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
107317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
107417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Add a dependency to this Node. The dependency includes information about the
107517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * node that this node is dependency upon and the nature of the dependency.
107617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param dependency
107717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
107817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public void addDependency(Dependency dependency) {
107917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (dependencies == null) {
108017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                dependencies = new ArrayList<Dependency>();
108117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodeDependencies = new ArrayList<Node>();
108217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
108317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            dependencies.add(dependency);
108417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (!nodeDependencies.contains(dependency.node)) {
108517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodeDependencies.add(dependency.node);
108617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
108717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node dependencyNode = dependency.node;
108817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (dependencyNode.nodeDependents == null) {
108917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                dependencyNode.nodeDependents = new ArrayList<Node>();
109017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
109117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            dependencyNode.nodeDependents.add(this);
109217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
109349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
109449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        @Override
109521cd1389d2ef218b20994b617c57af120841a57fChet Haase        public Node clone() {
109621cd1389d2ef218b20994b617c57af120841a57fChet Haase            try {
109721cd1389d2ef218b20994b617c57af120841a57fChet Haase                Node node = (Node) super.clone();
1098b1e80d826b860203cc966d56584f9d83f5636bc0ztenghui                node.animation = animation.clone();
1099b1e80d826b860203cc966d56584f9d83f5636bc0ztenghui                node.done = false;
110021cd1389d2ef218b20994b617c57af120841a57fChet Haase                return node;
110121cd1389d2ef218b20994b617c57af120841a57fChet Haase            } catch (CloneNotSupportedException e) {
110221cd1389d2ef218b20994b617c57af120841a57fChet Haase               throw new AssertionError();
110321cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
110449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
110517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
110617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
110717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
110817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * The <code>Builder</code> object is a utility class to facilitate adding animations to a
1109a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>AnimatorSet</code> along with the relationships between the various animations. The
111017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * intention of the <code>Builder</code> methods, along with the {@link
11118b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible
11128b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * to express the dependency relationships of animations in a natural way. Developers can also
11138b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
1114a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
1115a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
111617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
111717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
1118a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
111917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
1120a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
112117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
112217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
1123a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *     AnimatorSet s = new AnimatorSet();
112417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim1).with(anim2);
112517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim2).before(anim3);
112617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim4).after(anim3);
112717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
112817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
1129a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
1130a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Builder#after(Animator)} are used. These are just different ways of expressing the same
113117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * relationship and are provided to make it easier to say things in a way that is more natural,
113217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * depending on the situation.</p>
113317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
113417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>It is possible to make several calls into the same <code>Builder</code> object to express
113517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * multiple relationships. However, note that it is only the animation passed into the initial
1136a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
113717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * calls to the <code>Builder</code> object. For example, the following code starts both anim2
113817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
113917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * anim3:
114017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
1141a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *   AnimatorSet s = new AnimatorSet();
114217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim1).before(anim2).before(anim3);
114317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
114417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
114517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * relationship correctly:</p>
114617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
1147a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *   AnimatorSet s = new AnimatorSet();
114817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim1).before(anim2);
114917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim2).before(anim3);
115017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
115117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
115217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>Note that it is possible to express relationships that cannot be resolved and will not
115317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
115417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * sense. In general, circular dependencies like this one (or more indirect ones where a depends
1155a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
1156a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * that can boil down to a simple, one-way relationship of animations starting with, before, and
115717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * after other, different, animations.</p>
115817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
115917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public class Builder {
116017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
116117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
116217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * This tracks the current node being processed. It is supplied to the play() method
1163a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * of AnimatorSet and passed into the constructor of Builder.
116417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
116517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private Node mCurrentNode;
116617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
116717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
1168a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * package-private constructor. Builders are only constructed by AnimatorSet, when the
116917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * play() method is called.
117017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
117117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that is the dependency for the other animations passed into
117217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the other methods of this Builder object.
117317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
1174a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        Builder(Animator anim) {
117517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mCurrentNode = mNodeMap.get(anim);
117617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mCurrentNode == null) {
117717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mCurrentNode = new Node(anim);
117817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, mCurrentNode);
117917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(mCurrentNode);
118017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
118117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
118217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
118317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
118417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play at the same time as the animation supplied in the
1185a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
118617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
118717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that will play when the animation supplied to the
1188a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method starts.
118917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
11902970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        public Builder with(Animator anim) {
119117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
119217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
119317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
119417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
119517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
119617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
119717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
119817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            node.addDependency(dependency);
11992970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            return this;
120017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
120117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
120217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
120317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play when the animation supplied in the
1204a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
120517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * ends.
120617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
120717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that will play when the animation supplied to the
1208a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method ends.
120917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
12102970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        public Builder before(Animator anim) {
12117bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            mReversible = false;
121217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
121317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
121417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
121517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
121617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
121717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
121817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
121917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            node.addDependency(dependency);
12202970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            return this;
122117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
122217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
122317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
122417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play when the animation supplied in the
1225a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
122617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * to start when the animation supplied in this method call ends.
122717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
122817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation whose end will cause the animation supplied to the
1229a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method to play.
123017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
12312970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        public Builder after(Animator anim) {
12327bc6a3f023ca3e1dde91fc97b6036dee3ba538a2ztenghui            mReversible = false;
123317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
123417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
123517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
123617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
123717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
123817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
123917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(node, Dependency.AFTER);
124017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mCurrentNode.addDependency(dependency);
12412970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            return this;
124217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
124317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
124417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
124517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the animation supplied in the
1246a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
124717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * to play when the given amount of time elapses.
124817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
124917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param delay The number of milliseconds that should elapse before the
125017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * animation starts.
125117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
12522970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        public Builder after(long delay) {
1253a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            // setup dummy ValueAnimator just to run the clock
12542794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
12552794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            anim.setDuration(delay);
12562794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            after(anim);
12572970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            return this;
125817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
125917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
126017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
126117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
126217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase}
1263