AnimatorSet.java revision 8b699792b677bd4dd8442b32641ac09d48fdd79c
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
1917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haaseimport java.util.ArrayList;
2037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haaseimport java.util.Collection;
2117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haaseimport java.util.HashMap;
2237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haaseimport java.util.List;
2317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
2417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase/**
25a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * This class plays a set of {@link Animator} objects in the specified order. Animations
2617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * can be set up to play together, in sequence, or after a specified delay.
2717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
28a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>There are two different approaches to adding animations to a <code>AnimatorSet</code>:
29a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or
30a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add
31a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be
32a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * used in conjunction with methods in the {@link AnimatorSet.Builder Builder}
3317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * class to add animations
3417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * one by one.</p>
3517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
36a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>It is possible to set up a <code>AnimatorSet</code> with circular dependencies between
3717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * its animations. For example, an animation a1 could be set up to start before animation a2, a2
3817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * before a3, and a3 before a1. The results of this configuration are undefined, but will typically
3917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * result in none of the affected animations being played. Because of this (and because
4017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * circular dependencies do not make logical sense anyway), circular dependencies
4117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * should be avoided, and the dependency flow of animations should only be in one direction.
4217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */
43a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic final class AnimatorSet extends Animator {
4417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
4517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
4649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * Internal variables
4749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * NOTE: This object implements the clone() method, making a deep copy of any referenced
4849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * objects. As other non-trivial fields are added to this class, make sure to add logic
4949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * to clone() to make deep copies of them.
5049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     */
5149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
5249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    /**
533b69b6f0be85d1f97c1e6824cf986777ba4e5d00Chet Haase     * Tracks animations currently being played, so that we know what to
54a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * cancel or end when cancel() or end() is called on this AnimatorSet
5517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
56a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>();
5717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
5817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
59a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Contains all nodes, mapped to their respective Animators. When new
60a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * dependency information is added for an Animator, we want to add it
61a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * to a single node representing that Animator, not create a new Node
6217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * if one already exists.
6317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
64a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private HashMap<Animator, Node> mNodeMap = new HashMap<Animator, Node>();
6517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
6617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
67a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Set of all nodes created for this AnimatorSet. This list is used upon
68a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * starting the set, and the nodes are placed in sorted order into the
6917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * sortedNodes collection.
7017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
7149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private ArrayList<Node> mNodes = new ArrayList<Node>();
7217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
7317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
7417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * The sorted list of nodes. This is the order in which the animations will
7517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * be played. The details about when exactly they will be played depend
7617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * on the dependency relationships of the nodes.
7717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
7849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private ArrayList<Node> mSortedNodes = new ArrayList<Node>();
7917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
8017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
8117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * Flag indicating whether the nodes should be sorted prior to playing. This
8217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * flag allows us to cache the previous sorted nodes so that if the sequence
8317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * is replayed with no changes, it does not have to re-sort the nodes again.
8417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
8517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private boolean mNeedsSort = true;
8617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
87a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private AnimatorSetListener mSetListener = null;
8817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
8917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
907dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase     * Flag indicating that the AnimatorSet has been manually
917dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase     * terminated (by calling cancel() or end()).
92010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase     * This flag is used to avoid starting other animations when currently-playing
937dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase     * child animations of this AnimatorSet end. It also determines whether cancel/end
947dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase     * notifications are sent out via the normal AnimatorSetListener mechanism.
95010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase     */
967dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase    boolean mTerminated = false;
97010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
988b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    /**
998b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * Indicates whether an AnimatorSet has been start()'d, whether or
1008b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * not there is a nonzero startDelay.
1018b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     */
1028b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    private boolean mStarted = false;
1038b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase
10421cd1389d2ef218b20994b617c57af120841a57fChet Haase    // The amount of time in ms to delay starting the animation after start() is called
10521cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mStartDelay = 0;
10621cd1389d2ef218b20994b617c57af120841a57fChet Haase
107e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase    // Animator used for a nonzero startDelay
108e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase    private ValueAnimator mDelayAnim = null;
109e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase
11021cd1389d2ef218b20994b617c57af120841a57fChet Haase
11121cd1389d2ef218b20994b617c57af120841a57fChet Haase    // How long the child animations should last in ms. The default value is negative, which
112a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    // simply means that there is no duration set on the AnimatorSet. When a real duration is
11321cd1389d2ef218b20994b617c57af120841a57fChet Haase    // set, it is passed along to the child animations.
11421cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mDuration = -1;
11521cd1389d2ef218b20994b617c57af120841a57fChet Haase
11621cd1389d2ef218b20994b617c57af120841a57fChet Haase
117010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase    /**
118a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
11917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
120a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @param items The animations that will be started simultaneously.
12117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
122a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public void playTogether(Animator... items) {
123a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        if (items != null) {
12417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
125a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Builder builder = play(items[0]);
126a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            for (int i = 1; i < items.length; ++i) {
127a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                builder.with(items[i]);
12817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
12917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
13017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
13117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
13217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
13337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
13437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     *
13537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * @param items The animations that will be started simultaneously.
13637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     */
13737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    public void playTogether(Collection<Animator> items) {
13837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase        if (items != null && items.size() > 0) {
13937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            mNeedsSort = true;
14037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            Builder builder = null;
14137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            for (Animator anim : items) {
14237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                if (builder == null) {
14337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                    builder = play(anim);
14437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                } else {
14537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                    builder.with(anim);
14637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                }
14737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            }
14837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase        }
14937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    }
15037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase
15137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    /**
152a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets up this AnimatorSet to play each of the supplied animations when the
15317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * previous animation ends.
15417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
15537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * @param items The animations that will be started one after another.
15617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
157a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public void playSequentially(Animator... items) {
158a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        if (items != null) {
15917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
160a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (items.length == 1) {
161a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                play(items[0]);
16217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            } else {
163a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                for (int i = 0; i < items.length - 1; ++i) {
164a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    play(items[i]).before(items[i+1]);
16517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
16617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
16717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
16817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
16917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
17017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
17137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * Sets up this AnimatorSet to play each of the supplied animations when the
17237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * previous animation ends.
17337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     *
17437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     * @param items The animations that will be started one after another.
17537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase     */
17637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    public void playSequentially(List<Animator> items) {
17737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase        if (items != null && items.size() > 0) {
17837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            mNeedsSort = true;
17937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            if (items.size() == 1) {
18037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                play(items.get(0));
18137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            } else {
18237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                for (int i = 0; i < items.size() - 1; ++i) {
18337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                    play(items.get(i)).before(items.get(i+1));
18437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase                }
18537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase            }
18637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase        }
18737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    }
18837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase
18937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase    /**
190a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Returns the current list of child Animator objects controlled by this
191a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet. This is a copy of the internal list; modifications to the returned list
192a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * will not affect the AnimatorSet, although changes to the underlying Animator objects
193a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * will affect those objects being managed by the AnimatorSet.
194f54a8d7c479485174941c38f151ea7083c658da3Chet Haase     *
195a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return ArrayList<Animator> The list of child animations of this AnimatorSet.
196f54a8d7c479485174941c38f151ea7083c658da3Chet Haase     */
197a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public ArrayList<Animator> getChildAnimations() {
198a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        ArrayList<Animator> childList = new ArrayList<Animator>();
199f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        for (Node node : mNodes) {
200f54a8d7c479485174941c38f151ea7083c658da3Chet Haase            childList.add(node.animation);
201f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        }
202f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        return childList;
203f54a8d7c479485174941c38f151ea7083c658da3Chet Haase    }
204f54a8d7c479485174941c38f151ea7083c658da3Chet Haase
205f54a8d7c479485174941c38f151ea7083c658da3Chet Haase    /**
206811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     * Sets the target object for all current {@link #getChildAnimations() child animations}
207a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * of this AnimatorSet that take targets ({@link ObjectAnimator} and
208a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet).
209811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     *
210811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     * @param target The object being animated
211811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     */
21221cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
213811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    public void setTarget(Object target) {
214811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase        for (Node node : mNodes) {
215a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Animator animation = node.animation;
216a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (animation instanceof AnimatorSet) {
217a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                ((AnimatorSet)animation).setTarget(target);
218a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            } else if (animation instanceof ObjectAnimator) {
219a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                ((ObjectAnimator)animation).setTarget(target);
220811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase            }
221811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase        }
222811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    }
223811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase
224811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    /**
225e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase     * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
226a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * of this AnimatorSet.
22721cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
228a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @param interpolator the interpolator to be used by each child animation of this AnimatorSet
22921cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
23021cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
231e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase    public void setInterpolator(TimeInterpolator interpolator) {
23221cd1389d2ef218b20994b617c57af120841a57fChet Haase        for (Node node : mNodes) {
23321cd1389d2ef218b20994b617c57af120841a57fChet Haase            node.animation.setInterpolator(interpolator);
23421cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
23521cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
23621cd1389d2ef218b20994b617c57af120841a57fChet Haase
23721cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
23817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This method creates a <code>Builder</code> object, which is used to
23917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * set up playing constraints. This initial <code>play()</code> method
24017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * tells the <code>Builder</code> the animation that is the dependency for
24117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * the succeeding commands to the <code>Builder</code>. For example,
242a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * calling <code>play(a1).with(a2)</code> sets up the AnimatorSet to play
24317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a1</code> and <code>a2</code> at the same time,
244a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>play(a1).before(a2)</code> sets up the AnimatorSet to play
24517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a1</code> first, followed by <code>a2</code>, and
246a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>play(a1).after(a2)</code> sets up the AnimatorSet to play
24717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a2</code> first, followed by <code>a1</code>.
24817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
24917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>Note that <code>play()</code> is the only way to tell the
25017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>Builder</code> the animation upon which the dependency is created,
25117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * so successive calls to the various functions in <code>Builder</code>
25217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * will all refer to the initial parameter supplied in <code>play()</code>
25317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * as the dependency of the other animations. For example, calling
25417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code>
25517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * and <code>a3</code> when a1 ends; it does not set up a dependency between
25617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a2</code> and <code>a3</code>.</p>
25717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
25817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * @param anim The animation that is the dependency used in later calls to the
25917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * methods in the returned <code>Builder</code> object. A null parameter will result
26017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * in a null <code>Builder</code> return value.
261a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return Builder The object that constructs the AnimatorSet based on the dependencies
26217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * outlined in the calls to <code>play</code> and the other methods in the
26317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>Builder</code object.
26417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
265a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public Builder play(Animator anim) {
26617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (anim != null) {
26717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
26817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            return new Builder(anim);
26917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
27017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        return null;
27117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
27217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
27317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
27417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
27517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
2768b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * <p>Note that canceling a <code>AnimatorSet</code> also cancels all of the animations that it
2778b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * is responsible for.</p>
27817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
27917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @SuppressWarnings("unchecked")
28017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
28117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void cancel() {
2827dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase        mTerminated = true;
2838b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        if (isStarted()) {
2847dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            ArrayList<AnimatorListener> tmpListeners = null;
285e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            if (mListeners != null) {
2867dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
287e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                for (AnimatorListener listener : tmpListeners) {
2887dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    listener.onAnimationCancel(this);
289e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                }
290e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            }
2917dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mDelayAnim != null && mDelayAnim.isRunning()) {
2927dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // If we're currently in the startDelay period, just cancel that animator and
2937dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // send out the end event to all listeners
2947dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                mDelayAnim.cancel();
2957dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            } else  if (mSortedNodes.size() > 0) {
2967dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (Node node : mSortedNodes) {
2977dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    node.animation.cancel();
2987dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                }
2997dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            }
3007dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (tmpListeners != null) {
3017dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (AnimatorListener listener : tmpListeners) {
3027dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    listener.onAnimationEnd(this);
3037dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                }
30417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
3058b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            mStarted = false;
30617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
30717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
30817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
30917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
31017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
31117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
312a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Note that ending a <code>AnimatorSet</code> also ends all of the animations that it is
31317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * responsible for.</p>
31417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
31517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
31617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void end() {
3177dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase        mTerminated = true;
3188b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        if (isStarted()) {
3197dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mSortedNodes.size() != mNodes.size()) {
3207dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // hasn't been started yet - sort the nodes now, then end them
3217dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                sortNodes();
3227dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (Node node : mSortedNodes) {
3237dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (mSetListener == null) {
3247dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        mSetListener = new AnimatorSetListener(this);
3257dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    }
3267dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    node.animation.addListener(mSetListener);
3271e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase                }
3281e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase            }
3297dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mDelayAnim != null) {
3307dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                mDelayAnim.cancel();
3317dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            }
3327dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mSortedNodes.size() > 0) {
3337dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (Node node : mSortedNodes) {
3347dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    node.animation.end();
3357dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                }
3367dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            }
3377dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mListeners != null) {
3387dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                ArrayList<AnimatorListener> tmpListeners =
3397dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        (ArrayList<AnimatorListener>) mListeners.clone();
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    /**
3498b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * Returns true if any of the child animations of this AnimatorSet have been started and have
3508b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * not yet ended.
351a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return Whether this AnimatorSet has been started and has not yet ended.
352673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase     */
353673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    @Override
354673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    public boolean isRunning() {
355673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase        for (Node node : mNodes) {
356673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase            if (node.animation.isRunning()) {
357673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase                return true;
358673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase            }
359673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase        }
3608b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        return false;
3618b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    }
3628b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase
3638b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    @Override
3648b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase    public boolean isStarted() {
3658b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        return mStarted;
366673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    }
367673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase
368673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    /**
36921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The amount of time, in milliseconds, to delay starting the animation after
37021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * {@link #start()} is called.
37121cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
37221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return the number of milliseconds to delay running the animation
37321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
37421cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
37521cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getStartDelay() {
37621cd1389d2ef218b20994b617c57af120841a57fChet Haase        return mStartDelay;
37721cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
37821cd1389d2ef218b20994b617c57af120841a57fChet Haase
37921cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
38021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The amount of time, in milliseconds, to delay starting the animation after
38121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * {@link #start()} is called.
38221cd1389d2ef218b20994b617c57af120841a57fChet Haase
38321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param startDelay The amount of the delay, in milliseconds
38421cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
38521cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
38621cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void setStartDelay(long startDelay) {
38721cd1389d2ef218b20994b617c57af120841a57fChet Haase        mStartDelay = startDelay;
38821cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
38921cd1389d2ef218b20994b617c57af120841a57fChet Haase
39021cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
391a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Gets the length of each of the child animations of this AnimatorSet. This value may
392a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * be less than 0, which indicates that no duration has been set on this AnimatorSet
39321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * and each of the child animations will use their own duration.
39421cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
39521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return The length of the animation, in milliseconds, of each of the child
396a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * animations of this AnimatorSet.
39721cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
39821cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
39921cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getDuration() {
40021cd1389d2ef218b20994b617c57af120841a57fChet Haase        return mDuration;
40121cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
40221cd1389d2ef218b20994b617c57af120841a57fChet Haase
40321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
404a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets the length of each of the current child animations of this AnimatorSet. By default,
405a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * each child animation will use its own duration. If the duration is set on the AnimatorSet,
40621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * then each child animation inherits this duration.
40721cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
40821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param duration The length of the animation, in milliseconds, of each of the child
409a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * animations of this AnimatorSet.
41021cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
41121cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
4122794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase    public AnimatorSet setDuration(long duration) {
41321cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (duration < 0) {
41421cd1389d2ef218b20994b617c57af120841a57fChet Haase            throw new IllegalArgumentException("duration must be a value of zero or greater");
41521cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
41621cd1389d2ef218b20994b617c57af120841a57fChet Haase        for (Node node : mNodes) {
417a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
41821cd1389d2ef218b20994b617c57af120841a57fChet Haase            // insert "play-after" delays
41921cd1389d2ef218b20994b617c57af120841a57fChet Haase            node.animation.setDuration(duration);
42021cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
42121cd1389d2ef218b20994b617c57af120841a57fChet Haase        mDuration = duration;
4222794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase        return this;
42321cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
42421cd1389d2ef218b20994b617c57af120841a57fChet Haase
4252970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    @Override
4262970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    public void setupStartValues() {
4272970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        for (Node node : mNodes) {
4282970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            node.animation.setupStartValues();
4292970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        }
4302970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    }
4312970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase
4322970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    @Override
4332970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    public void setupEndValues() {
4342970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        for (Node node : mNodes) {
4352970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            node.animation.setupEndValues();
4362970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        }
4372970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase    }
4382970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase
43921cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
44017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
44117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
442a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which
44317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * it is responsible. The details of when exactly those animations are started depends on
44417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * the dependency relationships that have been set up between the animations.
44517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
44617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @SuppressWarnings("unchecked")
44717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
44817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void start() {
4497dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase        mTerminated = false;
4508b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        mStarted = true;
451010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
45217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // First, sort the nodes (if necessary). This will ensure that sortedNodes
45317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // contains the animation nodes in the correct order.
45417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        sortNodes();
45517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
456e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase        int numSortedNodes = mSortedNodes.size();
457e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase        for (int i = 0; i < numSortedNodes; ++i) {
458e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            Node node = mSortedNodes.get(i);
459e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            // First, clear out the old listeners
460e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
461e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            if (oldListeners != null && oldListeners.size() > 0) {
462d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen                final ArrayList<AnimatorListener> clonedListeners = new
463d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen                        ArrayList<AnimatorListener>(oldListeners);
464d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen
465d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen                for (AnimatorListener listener : clonedListeners) {
4667dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (listener instanceof DependencyListener ||
4677dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                            listener instanceof AnimatorSetListener) {
468e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                        node.animation.removeListener(listener);
469e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                    }
470e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                }
471e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            }
472e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase        }
473e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase
47417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // nodesToStart holds the list of nodes to be started immediately. We don't want to
47517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // start the animations in the loop directly because we first need to set up
47617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // dependencies on all of the nodes. For example, we don't want to start an animation
47717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // when some other animation also wants to start when the first animation begins.
47821cd1389d2ef218b20994b617c57af120841a57fChet Haase        final ArrayList<Node> nodesToStart = new ArrayList<Node>();
4797c608f25d494c8a0a671e7373efbb47ca635367eChet Haase        for (int i = 0; i < numSortedNodes; ++i) {
4807c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            Node node = mSortedNodes.get(i);
481a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (mSetListener == null) {
482a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                mSetListener = new AnimatorSetListener(this);
48317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
48417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node.dependencies == null || node.dependencies.size() == 0) {
48517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodesToStart.add(node);
48617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            } else {
4877c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                int numDependencies = node.dependencies.size();
4887c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                for (int j = 0; j < numDependencies; ++j) {
4897c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Dependency dependency = node.dependencies.get(j);
49017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependency.node.animation.addListener(
491010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                            new DependencyListener(this, node, dependency.rule));
49217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
49317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone();
49417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
495a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            node.animation.addListener(mSetListener);
49617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
49717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Now that all dependencies are set up, start the animations that should be started.
49821cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (mStartDelay <= 0) {
49921cd1389d2ef218b20994b617c57af120841a57fChet Haase            for (Node node : nodesToStart) {
50021cd1389d2ef218b20994b617c57af120841a57fChet Haase                node.animation.start();
50121cd1389d2ef218b20994b617c57af120841a57fChet Haase                mPlayingSet.add(node.animation);
50221cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
50321cd1389d2ef218b20994b617c57af120841a57fChet Haase        } else {
504e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
505e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            mDelayAnim.setDuration(mStartDelay);
506e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            mDelayAnim.addListener(new AnimatorListenerAdapter() {
507e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                boolean canceled = false;
508e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                public void onAnimationCancel(Animator anim) {
509e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                    canceled = true;
510e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                }
511a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                public void onAnimationEnd(Animator anim) {
512e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                    if (!canceled) {
513e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                        int numNodes = nodesToStart.size();
514e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                        for (int i = 0; i < numNodes; ++i) {
515e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                            Node node = nodesToStart.get(i);
516e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                            node.animation.start();
517e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                            mPlayingSet.add(node.animation);
518e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase                        }
51921cd1389d2ef218b20994b617c57af120841a57fChet Haase                    }
52021cd1389d2ef218b20994b617c57af120841a57fChet Haase                }
52121cd1389d2ef218b20994b617c57af120841a57fChet Haase            });
522e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase            mDelayAnim.start();
52317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
52417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (mListeners != null) {
525a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ArrayList<AnimatorListener> tmpListeners =
526a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    (ArrayList<AnimatorListener>) mListeners.clone();
5277c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            int numListeners = tmpListeners.size();
5287c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            for (int i = 0; i < numListeners; ++i) {
5297c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                tmpListeners.get(i).onAnimationStart(this);
5308b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            }
5318b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        }
5328b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        if (mNodes.size() == 0 && mStartDelay == 0) {
5338b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            // Handle unusual case where empty AnimatorSet is started - should send out
5348b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            // end event immediately since the event will not be sent out at all otherwise
5358b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            mStarted = false;
5368b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase            if (mListeners != null) {
5378b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                ArrayList<AnimatorListener> tmpListeners =
5388b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                        (ArrayList<AnimatorListener>) mListeners.clone();
5398b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                int numListeners = tmpListeners.size();
5408b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                for (int i = 0; i < numListeners; ++i) {
5412970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase                    tmpListeners.get(i).onAnimationEnd(this);
5422970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase                }
54317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
54417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
54517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
54617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
54749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    @Override
548a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public AnimatorSet clone() {
549a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        final AnimatorSet anim = (AnimatorSet) super.clone();
55049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        /*
55149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * The basic clone() operation copies all items. This doesn't work very well for
552a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * AnimatorSet, because it will copy references that need to be recreated and state
55349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * that may not apply. What we need to do now is put the clone in an uninitialized
55449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * state, with fresh, empty data structures. Then we will build up the nodes list
55549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * manually, as we clone each Node (and its animation). The clone will then be sorted,
55649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * and will populate any appropriate lists, when it is started.
55749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         */
55849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        anim.mNeedsSort = true;
5597dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase        anim.mTerminated = false;
5608b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase        anim.mStarted = false;
561a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        anim.mPlayingSet = new ArrayList<Animator>();
562a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        anim.mNodeMap = new HashMap<Animator, Node>();
56349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        anim.mNodes = new ArrayList<Node>();
56449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        anim.mSortedNodes = new ArrayList<Node>();
56549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
56649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
567a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
56849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
56949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>(); // <old, new>
57049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        for (Node node : mNodes) {
57149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            Node nodeClone = node.clone();
57249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeCloneMap.put(node, nodeClone);
57349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            anim.mNodes.add(nodeClone);
57449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            anim.mNodeMap.put(nodeClone.animation, nodeClone);
57549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            // Clear out the dependencies in the clone; we'll set these up manually later
57649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.dependencies = null;
57749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.tmpDependencies = null;
57849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.nodeDependents = null;
57949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.nodeDependencies = null;
580a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            // clear out any listeners that were set up by the AnimatorSet; these will
58149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            // be set up when the clone's nodes are sorted
582a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
58349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            if (cloneListeners != null) {
584a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                ArrayList<AnimatorListener> listenersToRemove = null;
585a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                for (AnimatorListener listener : cloneListeners) {
586a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    if (listener instanceof AnimatorSetListener) {
58749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                        if (listenersToRemove == null) {
588a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                            listenersToRemove = new ArrayList<AnimatorListener>();
58949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                        }
59049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                        listenersToRemove.add(listener);
59149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    }
59249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                }
59349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                if (listenersToRemove != null) {
594a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    for (AnimatorListener listener : listenersToRemove) {
59549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                        cloneListeners.remove(listener);
59649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    }
59749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                }
59849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            }
59949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
60049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // Now that we've cloned all of the nodes, we're ready to walk through their
60149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // dependencies, mapping the old dependencies to the new nodes
60249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        for (Node node : mNodes) {
60349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            Node nodeClone = nodeCloneMap.get(node);
60449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            if (node.dependencies != null) {
60549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                for (Dependency dependency : node.dependencies) {
60649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    Node clonedDependencyNode = nodeCloneMap.get(dependency.node);
60749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    Dependency cloneDependency = new Dependency(clonedDependencyNode,
60849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                            dependency.rule);
60949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    nodeClone.addDependency(cloneDependency);
61049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                }
61149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            }
61249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
61349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
61449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        return anim;
61549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    }
61649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
61717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
61817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This class is the mechanism by which animations are started based on events in other
61917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * animations. If an animation has multiple dependencies on other animations, then
62017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * all dependencies must be satisfied before the animation is started.
62117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
622a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private static class DependencyListener implements AnimatorListener {
62317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
624a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private AnimatorSet mAnimatorSet;
625010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
62617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The node upon which the dependency is based.
62717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private Node mNode;
62817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
62917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The Dependency rule (WITH or AFTER) that the listener should wait for on
63017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // the node
63117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private int mRule;
63217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
633a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public DependencyListener(AnimatorSet animatorSet, Node node, int rule) {
634a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            this.mAnimatorSet = animatorSet;
63517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.mNode = node;
63617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.mRule = rule;
63717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
63817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
63917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
640010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * Ignore cancel events for now. We may want to handle this eventually,
641010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * to prevent follow-on animations from running when some dependency
642010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * animation is canceled.
64317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
644a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationCancel(Animator animation) {
64517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
64617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
64717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
64817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * An end event is received - see if this is an event we are listening for
64917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
650a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationEnd(Animator animation) {
65117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mRule == Dependency.AFTER) {
65217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                startIfReady(animation);
65317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
65417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
65517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
65617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
65717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Ignore repeat events for now
65817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
659a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationRepeat(Animator animation) {
66017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
66117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
66217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
66317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * A start event is received - see if this is an event we are listening for
66417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
665a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationStart(Animator animation) {
66617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mRule == Dependency.WITH) {
66717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                startIfReady(animation);
66817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
66917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
67017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
67117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
67217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Check whether the event received is one that the node was waiting for.
67317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * If so, mark it as complete and see whether it's time to start
67417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the animation.
67517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param dependencyAnimation the animation that sent the event.
67617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
677a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private void startIfReady(Animator dependencyAnimation) {
6787dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (mAnimatorSet.mTerminated) {
679a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                // if the parent AnimatorSet was canceled, then don't start any dependent anims
680010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                return;
681010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase            }
68217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependencyToRemove = null;
6837c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            int numDependencies = mNode.tmpDependencies.size();
6847c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            for (int i = 0; i < numDependencies; ++i) {
6857c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                Dependency dependency = mNode.tmpDependencies.get(i);
68617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (dependency.rule == mRule &&
68717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        dependency.node.animation == dependencyAnimation) {
68817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    // rule fired - remove the dependency and listener and check to
68917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    // see whether it's time to start the animation
69017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependencyToRemove = dependency;
69117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependencyAnimation.removeListener(this);
69217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    break;
69317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
69417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
69517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNode.tmpDependencies.remove(dependencyToRemove);
69617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mNode.tmpDependencies.size() == 0) {
69717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                // all dependencies satisfied: start the animation
69817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNode.animation.start();
699a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                mAnimatorSet.mPlayingSet.add(mNode.animation);
70017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
70117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
70217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
70317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
70417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
705a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private class AnimatorSetListener implements AnimatorListener {
70617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
707a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private AnimatorSet mAnimatorSet;
70817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
709a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        AnimatorSetListener(AnimatorSet animatorSet) {
710a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            mAnimatorSet = animatorSet;
71117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
71217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
713a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationCancel(Animator animation) {
7147dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (!mTerminated) {
7157dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // Listeners are already notified of the AnimatorSet canceling in cancel().
7167dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // The logic below only kicks in when animations end normally
7177dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                if (mPlayingSet.size() == 0) {
7187dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (mListeners != null) {
7197dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        int numListeners = mListeners.size();
7207dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        for (int i = 0; i < numListeners; ++i) {
7217dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                            mListeners.get(i).onAnimationCancel(mAnimatorSet);
7227dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        }
72317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
72417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
72517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
72617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
72717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
72817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        @SuppressWarnings("unchecked")
729a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationEnd(Animator animation) {
73017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            animation.removeListener(this);
73117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mPlayingSet.remove(animation);
732a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Node animNode = mAnimatorSet.mNodeMap.get(animation);
7331e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase            animNode.done = true;
7347dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase            if (!mTerminated) {
7357dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // Listeners are already notified of the AnimatorSet ending in cancel() or
7367dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // end(); the logic below only kicks in when animations end normally
7377dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
7387dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                boolean allDone = true;
7397dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                int numSortedNodes = sortedNodes.size();
7407dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                for (int i = 0; i < numSortedNodes; ++i) {
7417dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (!sortedNodes.get(i).done) {
7427dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        allDone = false;
7437dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        break;
7447dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    }
745a6e4a1757728efc91627ece602b0899d75303659Chet Haase                }
7467dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                if (allDone) {
7477dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    // If this was the last child animation to end, then notify listeners that this
7487dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    // AnimatorSet has ended
7497dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                    if (mListeners != null) {
7507dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        ArrayList<AnimatorListener> tmpListeners =
7517dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                                (ArrayList<AnimatorListener>) mListeners.clone();
7527dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        int numListeners = tmpListeners.size();
7537dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        for (int i = 0; i < numListeners; ++i) {
7547dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                            tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
7557dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                        }
75617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
7578b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase                    mAnimatorSet.mStarted = false;
75817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
75917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
76017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
76117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
76217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Nothing to do
763a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationRepeat(Animator animation) {
76417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
76517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
76617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Nothing to do
767a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationStart(Animator animation) {
76817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
76917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
77017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
77117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
77217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
77317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This method sorts the current set of nodes, if needed. The sort is a simple
77417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * DependencyGraph sort, which goes like this:
77517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * - All nodes without dependencies become 'roots'
77617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * - while roots list is not null
77717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -   for each root r
77817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -     add r to sorted list
77917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -     remove r as a dependency from any other node
78017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -   any nodes with no dependencies are added to the roots list
78117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
78217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private void sortNodes() {
78317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (mNeedsSort) {
78417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mSortedNodes.clear();
78517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            ArrayList<Node> roots = new ArrayList<Node>();
7867c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            int numNodes = mNodes.size();
7877c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            for (int i = 0; i < numNodes; ++i) {
7887c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                Node node = mNodes.get(i);
78917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (node.dependencies == null || node.dependencies.size() == 0) {
79017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    roots.add(node);
79117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
79217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
79317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            ArrayList<Node> tmpRoots = new ArrayList<Node>();
79417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            while (roots.size() > 0) {
7957c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                int numRoots = roots.size();
7967c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                for (int i = 0; i < numRoots; ++i) {
7977c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    Node root = roots.get(i);
79817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    mSortedNodes.add(root);
79917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    if (root.nodeDependents != null) {
8007c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                        int numDependents = root.nodeDependents.size();
8017c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                        for (int j = 0; j < numDependents; ++j) {
8027c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                            Node node = root.nodeDependents.get(j);
80317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies.remove(root);
80417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            if (node.nodeDependencies.size() == 0) {
80517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                                tmpRoots.add(node);
80617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            }
80717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
80817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
80917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
810010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                roots.clear();
81117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                roots.addAll(tmpRoots);
81217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                tmpRoots.clear();
81317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
81417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = false;
81517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mSortedNodes.size() != mNodes.size()) {
81617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                throw new IllegalStateException("Circular dependencies cannot exist"
817a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                        + " in AnimatorSet");
81817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
81917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        } else {
82017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // Doesn't need sorting, but still need to add in the nodeDependencies list
82117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // because these get removed as the event listeners fire and the dependencies
82217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // are satisfied
8237c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            int numNodes = mNodes.size();
8247c608f25d494c8a0a671e7373efbb47ca635367eChet Haase            for (int i = 0; i < numNodes; ++i) {
8257c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                Node node = mNodes.get(i);
82617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (node.dependencies != null && node.dependencies.size() > 0) {
8277c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    int numDependencies = node.dependencies.size();
8287c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                    for (int j = 0; j < numDependencies; ++j) {
8297c608f25d494c8a0a671e7373efbb47ca635367eChet Haase                        Dependency dependency = node.dependencies.get(j);
83017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        if (node.nodeDependencies == null) {
83117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies = new ArrayList<Node>();
83217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
83317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        if (!node.nodeDependencies.contains(dependency.node)) {
83417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies.add(dependency.node);
83517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
83617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
83717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
8387dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // nodes are 'done' by default; they become un-done when started, and done
8397dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase                // again when ended
8401e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase                node.done = false;
84117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
84217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
84317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
84417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
84517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
84617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * Dependency holds information about the node that some other node is
84717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * dependent upon and the nature of that dependency.
84817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
84917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
85017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private static class Dependency {
85117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        static final int WITH = 0; // dependent node must start with this dependency node
85217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        static final int AFTER = 1; // dependent node must start when this dependency node finishes
85317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
85417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The node that the other node with this Dependency is dependent upon
85517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public Node node;
85617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
85717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The nature of the dependency (WITH or AFTER)
85817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public int rule;
85917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
86017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public Dependency(Node node, int rule) {
86117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.node = node;
86217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.rule = rule;
86317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
86417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
86517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
86617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
867a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * A Node is an embodiment of both the Animator that it wraps as well as
86817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * any dependencies that are associated with that Animation. This includes
86917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * both dependencies upon other nodes (in the dependencies list) as
87017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * well as dependencies of other nodes upon this (in the nodeDependents list).
87117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
87249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private static class Node implements Cloneable {
873a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public Animator animation;
87417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
87517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
87617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  These are the dependencies that this node's animation has on other
87717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  nodes. For example, if this node's animation should begin with some
87817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  other animation ends, then there will be an item in this node's
87917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  dependencies list for that other animation's node.
88017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
88117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Dependency> dependencies = null;
88217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
88317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
88417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * tmpDependencies is a runtime detail. We use the dependencies list for sorting.
88517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * But we also use the list to keep track of when multiple dependencies are satisfied,
88617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * but removing each dependency as it is satisfied. We do not want to remove
88717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the dependency itself from the list, because we need to retain that information
888a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * if the AnimatorSet is launched in the future. So we create a copy of the dependency
889a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * list when the AnimatorSet starts and use this tmpDependencies list to track the
89017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * list of satisfied dependencies.
89117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
89217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Dependency> tmpDependencies = null;
89317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
89417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
89517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * nodeDependencies is just a list of the nodes that this Node is dependent upon.
89617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * This information is used in sortNodes(), to determine when a node is a root.
89717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
89817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Node> nodeDependencies = null;
89917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
90017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
90117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * nodeDepdendents is the list of nodes that have this node as a dependency. This
90217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * is a utility field used in sortNodes to facilitate removing this node as a
90317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * dependency when it is a root node.
90417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
90517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Node> nodeDependents = null;
90617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
90717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
9081e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase         * Flag indicating whether the animation in this node is finished. This flag
909a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * is used by AnimatorSet to check, as each animation ends, whether all child animations
910a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * are done and it's time to send out an end event for the entire AnimatorSet.
9111e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase         */
9121e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase        public boolean done = false;
9131e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase
9141e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase        /**
91517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Constructs the Node with the animation that it encapsulates. A Node has no
91617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * dependencies by default; dependencies are added via the addDependency()
91717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * method.
91817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
91917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param animation The animation that the Node encapsulates.
92017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
921a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public Node(Animator animation) {
92217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.animation = animation;
92317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
92417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
92517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
92617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Add a dependency to this Node. The dependency includes information about the
92717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * node that this node is dependency upon and the nature of the dependency.
92817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param dependency
92917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
93017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public void addDependency(Dependency dependency) {
93117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (dependencies == null) {
93217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                dependencies = new ArrayList<Dependency>();
93317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodeDependencies = new ArrayList<Node>();
93417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
93517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            dependencies.add(dependency);
93617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (!nodeDependencies.contains(dependency.node)) {
93717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodeDependencies.add(dependency.node);
93817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
93917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node dependencyNode = dependency.node;
94017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (dependencyNode.nodeDependents == null) {
94117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                dependencyNode.nodeDependents = new ArrayList<Node>();
94217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
94317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            dependencyNode.nodeDependents.add(this);
94417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
94549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
94649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        @Override
94721cd1389d2ef218b20994b617c57af120841a57fChet Haase        public Node clone() {
94821cd1389d2ef218b20994b617c57af120841a57fChet Haase            try {
94921cd1389d2ef218b20994b617c57af120841a57fChet Haase                Node node = (Node) super.clone();
950a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                node.animation = (Animator) animation.clone();
95121cd1389d2ef218b20994b617c57af120841a57fChet Haase                return node;
95221cd1389d2ef218b20994b617c57af120841a57fChet Haase            } catch (CloneNotSupportedException e) {
95321cd1389d2ef218b20994b617c57af120841a57fChet Haase               throw new AssertionError();
95421cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
95549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
95617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
95717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
95817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
95917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * The <code>Builder</code> object is a utility class to facilitate adding animations to a
960a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>AnimatorSet</code> along with the relationships between the various animations. The
96117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * intention of the <code>Builder</code> methods, along with the {@link
9628b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible
9638b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * to express the dependency relationships of animations in a natural way. Developers can also
9648b699792b677bd4dd8442b32641ac09d48fdd79cChet Haase     * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
965a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
966a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
96717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
96817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
969a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
97017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
971a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
97217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
97317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
974a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *     AnimatorSet s = new AnimatorSet();
97517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim1).with(anim2);
97617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim2).before(anim3);
97717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim4).after(anim3);
97817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
97917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
980a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
981a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Builder#after(Animator)} are used. These are just different ways of expressing the same
98217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * relationship and are provided to make it easier to say things in a way that is more natural,
98317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * depending on the situation.</p>
98417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
98517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>It is possible to make several calls into the same <code>Builder</code> object to express
98617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * multiple relationships. However, note that it is only the animation passed into the initial
987a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
98817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * calls to the <code>Builder</code> object. For example, the following code starts both anim2
98917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
99017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * anim3:
99117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
992a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *   AnimatorSet s = new AnimatorSet();
99317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim1).before(anim2).before(anim3);
99417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
99517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
99617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * relationship correctly:</p>
99717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
998a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *   AnimatorSet s = new AnimatorSet();
99917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim1).before(anim2);
100017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim2).before(anim3);
100117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
100217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
100317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>Note that it is possible to express relationships that cannot be resolved and will not
100417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
100517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * sense. In general, circular dependencies like this one (or more indirect ones where a depends
1006a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
1007a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * that can boil down to a simple, one-way relationship of animations starting with, before, and
100817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * after other, different, animations.</p>
100917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
101017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public class Builder {
101117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
101217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
101317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * This tracks the current node being processed. It is supplied to the play() method
1014a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * of AnimatorSet and passed into the constructor of Builder.
101517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
101617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private Node mCurrentNode;
101717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
101817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
1019a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * package-private constructor. Builders are only constructed by AnimatorSet, when the
102017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * play() method is called.
102117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
102217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that is the dependency for the other animations passed into
102317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the other methods of this Builder object.
102417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
1025a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        Builder(Animator anim) {
102617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mCurrentNode = mNodeMap.get(anim);
102717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mCurrentNode == null) {
102817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mCurrentNode = new Node(anim);
102917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, mCurrentNode);
103017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(mCurrentNode);
103117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
103217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
103317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
103417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
103517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play at the same time as the animation supplied in the
1036a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
103717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
103817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that will play when the animation supplied to the
1039a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method starts.
104017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
10412970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        public Builder with(Animator anim) {
104217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
104317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
104417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
104517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
104617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
104717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
104817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
104917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            node.addDependency(dependency);
10502970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            return this;
105117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
105217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
105317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
105417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play when the animation supplied in the
1055a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
105617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * ends.
105717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
105817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that will play when the animation supplied to the
1059a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method ends.
106017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
10612970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        public Builder before(Animator anim) {
106217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
106317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
106417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
106517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
106617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
106717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
106817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
106917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            node.addDependency(dependency);
10702970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            return this;
107117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
107217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
107317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
107417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play when the animation supplied in the
1075a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
107617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * to start when the animation supplied in this method call ends.
107717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
107817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation whose end will cause the animation supplied to the
1079a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method to play.
108017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
10812970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        public Builder after(Animator anim) {
108217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
108317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
108417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
108517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
108617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
108717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
108817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(node, Dependency.AFTER);
108917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mCurrentNode.addDependency(dependency);
10902970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            return this;
109117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
109217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
109317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
109417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the animation supplied in the
1095a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
109617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * to play when the given amount of time elapses.
109717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
109817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param delay The number of milliseconds that should elapse before the
109917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * animation starts.
110017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
11012970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase        public Builder after(long delay) {
1102a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            // setup dummy ValueAnimator just to run the clock
11032794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
11042794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            anim.setDuration(delay);
11052794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            after(anim);
11062970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase            return this;
110717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
110817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
110917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
111017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
111117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase}
1112