AnimatorSet.java revision e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9
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;
2017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haaseimport java.util.HashMap;
2117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
2217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase/**
23a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * This class plays a set of {@link Animator} objects in the specified order. Animations
2417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * can be set up to play together, in sequence, or after a specified delay.
2517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
26a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>There are two different approaches to adding animations to a <code>AnimatorSet</code>:
27a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or
28a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add
29a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be
30a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * used in conjunction with methods in the {@link AnimatorSet.Builder Builder}
3117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * class to add animations
3217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * one by one.</p>
3317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase *
34a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>It is possible to set up a <code>AnimatorSet</code> with circular dependencies between
3517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * its animations. For example, an animation a1 could be set up to start before animation a2, a2
3617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * before a3, and a3 before a1. The results of this configuration are undefined, but will typically
3717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * result in none of the affected animations being played. Because of this (and because
3817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * circular dependencies do not make logical sense anyway), circular dependencies
3917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * should be avoided, and the dependency flow of animations should only be in one direction.
4017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */
41a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic final class AnimatorSet extends Animator {
4217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
4317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
4449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * Internal variables
4549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * NOTE: This object implements the clone() method, making a deep copy of any referenced
4649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * objects. As other non-trivial fields are added to this class, make sure to add logic
4749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     * to clone() to make deep copies of them.
4849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase     */
4949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
5049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    /**
513b69b6f0be85d1f97c1e6824cf986777ba4e5d00Chet Haase     * Tracks animations currently being played, so that we know what to
52a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * cancel or end when cancel() or end() is called on this AnimatorSet
5317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
54a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>();
5517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
5617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
57a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Contains all nodes, mapped to their respective Animators. When new
58a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * dependency information is added for an Animator, we want to add it
59a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * to a single node representing that Animator, not create a new Node
6017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * if one already exists.
6117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
62a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private HashMap<Animator, Node> mNodeMap = new HashMap<Animator, Node>();
6317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
6417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
65a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Set of all nodes created for this AnimatorSet. This list is used upon
66a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * starting the set, and the nodes are placed in sorted order into the
6717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * sortedNodes collection.
6817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
6949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private ArrayList<Node> mNodes = new ArrayList<Node>();
7017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
7117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
7217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * The sorted list of nodes. This is the order in which the animations will
7317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * be played. The details about when exactly they will be played depend
7417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * on the dependency relationships of the nodes.
7517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
7649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private ArrayList<Node> mSortedNodes = new ArrayList<Node>();
7717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
7817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
7917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * Flag indicating whether the nodes should be sorted prior to playing. This
8017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * flag allows us to cache the previous sorted nodes so that if the sequence
8117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * is replayed with no changes, it does not have to re-sort the nodes again.
8217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
8317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private boolean mNeedsSort = true;
8417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
85a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private AnimatorSetListener mSetListener = null;
8617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
8717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
88a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Flag indicating that the AnimatorSet has been canceled (by calling cancel() or end()).
89010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase     * This flag is used to avoid starting other animations when currently-playing
90a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * child animations of this AnimatorSet end.
91010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase     */
92010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase    boolean mCanceled = false;
93010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
9421cd1389d2ef218b20994b617c57af120841a57fChet Haase    // The amount of time in ms to delay starting the animation after start() is called
9521cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mStartDelay = 0;
9621cd1389d2ef218b20994b617c57af120841a57fChet Haase
9721cd1389d2ef218b20994b617c57af120841a57fChet Haase
9821cd1389d2ef218b20994b617c57af120841a57fChet Haase    // How long the child animations should last in ms. The default value is negative, which
99a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    // simply means that there is no duration set on the AnimatorSet. When a real duration is
10021cd1389d2ef218b20994b617c57af120841a57fChet Haase    // set, it is passed along to the child animations.
10121cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mDuration = -1;
10221cd1389d2ef218b20994b617c57af120841a57fChet Haase
10321cd1389d2ef218b20994b617c57af120841a57fChet Haase
104010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase    /**
105a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
10617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
107a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @param items The animations that will be started simultaneously.
10817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
109a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public void playTogether(Animator... items) {
110a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        if (items != null) {
11117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
112a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Builder builder = play(items[0]);
113a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            for (int i = 1; i < items.length; ++i) {
114a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                builder.with(items[i]);
11517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
11617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
11717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
11817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
11917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
120a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets up this AnimatorSet to play each of the supplied animations when the
12117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * previous animation ends.
12217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
123a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @param items The aniamtions that will be started one after another.
12417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
125a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public void playSequentially(Animator... items) {
126a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        if (items != null) {
12717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
128a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (items.length == 1) {
129a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                play(items[0]);
13017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            } else {
131a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                for (int i = 0; i < items.length - 1; ++i) {
132a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    play(items[i]).before(items[i+1]);
13317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
13417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
13517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
13617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
13717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
13817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
139a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Returns the current list of child Animator objects controlled by this
140a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet. This is a copy of the internal list; modifications to the returned list
141a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * will not affect the AnimatorSet, although changes to the underlying Animator objects
142a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * will affect those objects being managed by the AnimatorSet.
143f54a8d7c479485174941c38f151ea7083c658da3Chet Haase     *
144a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return ArrayList<Animator> The list of child animations of this AnimatorSet.
145f54a8d7c479485174941c38f151ea7083c658da3Chet Haase     */
146a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public ArrayList<Animator> getChildAnimations() {
147a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        ArrayList<Animator> childList = new ArrayList<Animator>();
148f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        for (Node node : mNodes) {
149f54a8d7c479485174941c38f151ea7083c658da3Chet Haase            childList.add(node.animation);
150f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        }
151f54a8d7c479485174941c38f151ea7083c658da3Chet Haase        return childList;
152f54a8d7c479485174941c38f151ea7083c658da3Chet Haase    }
153f54a8d7c479485174941c38f151ea7083c658da3Chet Haase
154f54a8d7c479485174941c38f151ea7083c658da3Chet Haase    /**
155811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     * Sets the target object for all current {@link #getChildAnimations() child animations}
156a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * of this AnimatorSet that take targets ({@link ObjectAnimator} and
157a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet).
158811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     *
159811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     * @param target The object being animated
160811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase     */
16121cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
162811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    public void setTarget(Object target) {
163811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase        for (Node node : mNodes) {
164a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Animator animation = node.animation;
165a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (animation instanceof AnimatorSet) {
166a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                ((AnimatorSet)animation).setTarget(target);
167a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            } else if (animation instanceof ObjectAnimator) {
168a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                ((ObjectAnimator)animation).setTarget(target);
169811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase            }
170811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase        }
171811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    }
172811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase
173811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase    /**
174e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase     * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
175a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * of this AnimatorSet.
17621cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
177a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @param interpolator the interpolator to be used by each child animation of this AnimatorSet
17821cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
17921cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
180e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase    public void setInterpolator(TimeInterpolator interpolator) {
18121cd1389d2ef218b20994b617c57af120841a57fChet Haase        for (Node node : mNodes) {
18221cd1389d2ef218b20994b617c57af120841a57fChet Haase            node.animation.setInterpolator(interpolator);
18321cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
18421cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
18521cd1389d2ef218b20994b617c57af120841a57fChet Haase
18621cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
18717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This method creates a <code>Builder</code> object, which is used to
18817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * set up playing constraints. This initial <code>play()</code> method
18917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * tells the <code>Builder</code> the animation that is the dependency for
19017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * the succeeding commands to the <code>Builder</code>. For example,
191a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * calling <code>play(a1).with(a2)</code> sets up the AnimatorSet to play
19217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a1</code> and <code>a2</code> at the same time,
193a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>play(a1).before(a2)</code> sets up the AnimatorSet to play
19417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a1</code> first, followed by <code>a2</code>, and
195a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>play(a1).after(a2)</code> sets up the AnimatorSet to play
19617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a2</code> first, followed by <code>a1</code>.
19717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
19817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>Note that <code>play()</code> is the only way to tell the
19917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>Builder</code> the animation upon which the dependency is created,
20017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * so successive calls to the various functions in <code>Builder</code>
20117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * will all refer to the initial parameter supplied in <code>play()</code>
20217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * as the dependency of the other animations. For example, calling
20317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code>
20417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * and <code>a3</code> when a1 ends; it does not set up a dependency between
20517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>a2</code> and <code>a3</code>.</p>
20617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
20717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * @param anim The animation that is the dependency used in later calls to the
20817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * methods in the returned <code>Builder</code> object. A null parameter will result
20917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * in a null <code>Builder</code> return value.
210a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return Builder The object that constructs the AnimatorSet based on the dependencies
21117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * outlined in the calls to <code>play</code> and the other methods in the
21217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <code>Builder</code object.
21317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
214a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public Builder play(Animator anim) {
21517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (anim != null) {
21617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = true;
21717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            return new Builder(anim);
21817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
21917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        return null;
22017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
22117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
22217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
22317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
22417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
225a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Note that canceling a <code>AnimatorSet</code> also cancels all of the animations that it is
22617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * responsible for.</p>
22717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
22817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @SuppressWarnings("unchecked")
22917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
23017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void cancel() {
231010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase        mCanceled = true;
23217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (mListeners != null) {
233a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ArrayList<AnimatorListener> tmpListeners =
234a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    (ArrayList<AnimatorListener>) mListeners.clone();
235a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            for (AnimatorListener listener : tmpListeners) {
23617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                listener.onAnimationCancel(this);
23717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
23817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
239010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase        if (mSortedNodes.size() > 0) {
240010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase            for (Node node : mSortedNodes) {
241010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                node.animation.cancel();
24217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
24317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
24417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
24517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
24617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
24717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
24817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
249a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Note that ending a <code>AnimatorSet</code> also ends all of the animations that it is
25017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * responsible for.</p>
25117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
25217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
25317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void end() {
254010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase        mCanceled = true;
255f1b9b464216d2fac634be9c6aa8605d7c9ed5b68Chet Haase        if (mSortedNodes.size() != mNodes.size()) {
256f1b9b464216d2fac634be9c6aa8605d7c9ed5b68Chet Haase            // hasn't been started yet - sort the nodes now, then end them
257f1b9b464216d2fac634be9c6aa8605d7c9ed5b68Chet Haase            sortNodes();
2581e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase            for (Node node : mSortedNodes) {
259a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                if (mSetListener == null) {
260a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    mSetListener = new AnimatorSetListener(this);
2611e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase                }
262a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                node.animation.addListener(mSetListener);
2631e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase            }
264f1b9b464216d2fac634be9c6aa8605d7c9ed5b68Chet Haase        }
265010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase        if (mSortedNodes.size() > 0) {
266010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase            for (Node node : mSortedNodes) {
267010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                node.animation.end();
26817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
26917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
27017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
27117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
27217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
273a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Returns true if any of the child animations of this AnimatorSet have been started and have not
274673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase     * yet ended.
275a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return Whether this AnimatorSet has been started and has not yet ended.
276673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase     */
277673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    @Override
278673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    public boolean isRunning() {
279673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase        for (Node node : mNodes) {
280673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase            if (node.animation.isRunning()) {
281673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase                return true;
282673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase            }
283673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase        }
284673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase        return false;
285673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    }
286673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase
287673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase    /**
28821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The amount of time, in milliseconds, to delay starting the animation after
28921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * {@link #start()} is called.
29021cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
29121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return the number of milliseconds to delay running the animation
29221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
29321cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
29421cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getStartDelay() {
29521cd1389d2ef218b20994b617c57af120841a57fChet Haase        return mStartDelay;
29621cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
29721cd1389d2ef218b20994b617c57af120841a57fChet Haase
29821cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
29921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The amount of time, in milliseconds, to delay starting the animation after
30021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * {@link #start()} is called.
30121cd1389d2ef218b20994b617c57af120841a57fChet Haase
30221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param startDelay The amount of the delay, in milliseconds
30321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
30421cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
30521cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void setStartDelay(long startDelay) {
30621cd1389d2ef218b20994b617c57af120841a57fChet Haase        mStartDelay = startDelay;
30721cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
30821cd1389d2ef218b20994b617c57af120841a57fChet Haase
30921cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
310a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Gets the length of each of the child animations of this AnimatorSet. This value may
311a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * be less than 0, which indicates that no duration has been set on this AnimatorSet
31221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * and each of the child animations will use their own duration.
31321cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
31421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return The length of the animation, in milliseconds, of each of the child
315a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * animations of this AnimatorSet.
31621cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
31721cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
31821cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getDuration() {
31921cd1389d2ef218b20994b617c57af120841a57fChet Haase        return mDuration;
32021cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
32121cd1389d2ef218b20994b617c57af120841a57fChet Haase
32221cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
323a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Sets the length of each of the current child animations of this AnimatorSet. By default,
324a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * each child animation will use its own duration. If the duration is set on the AnimatorSet,
32521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * then each child animation inherits this duration.
32621cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
32721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param duration The length of the animation, in milliseconds, of each of the child
328a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * animations of this AnimatorSet.
32921cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
33021cd1389d2ef218b20994b617c57af120841a57fChet Haase    @Override
33121cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void setDuration(long duration) {
33221cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (duration < 0) {
33321cd1389d2ef218b20994b617c57af120841a57fChet Haase            throw new IllegalArgumentException("duration must be a value of zero or greater");
33421cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
33521cd1389d2ef218b20994b617c57af120841a57fChet Haase        for (Node node : mNodes) {
336a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
33721cd1389d2ef218b20994b617c57af120841a57fChet Haase            // insert "play-after" delays
33821cd1389d2ef218b20994b617c57af120841a57fChet Haase            node.animation.setDuration(duration);
33921cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
34021cd1389d2ef218b20994b617c57af120841a57fChet Haase        mDuration = duration;
34121cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
34221cd1389d2ef218b20994b617c57af120841a57fChet Haase
34321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
34417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * {@inheritDoc}
34517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
346a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which
34717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * it is responsible. The details of when exactly those animations are started depends on
34817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * the dependency relationships that have been set up between the animations.
34917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
35017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @SuppressWarnings("unchecked")
35117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    @Override
35217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public void start() {
353010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase        mCanceled = false;
354010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
35517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // First, sort the nodes (if necessary). This will ensure that sortedNodes
35617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // contains the animation nodes in the correct order.
35717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        sortNodes();
35817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
35917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // nodesToStart holds the list of nodes to be started immediately. We don't want to
36017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // start the animations in the loop directly because we first need to set up
36117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // dependencies on all of the nodes. For example, we don't want to start an animation
36217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // when some other animation also wants to start when the first animation begins.
36321cd1389d2ef218b20994b617c57af120841a57fChet Haase        final ArrayList<Node> nodesToStart = new ArrayList<Node>();
36417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        for (Node node : mSortedNodes) {
365a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (mSetListener == null) {
366a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                mSetListener = new AnimatorSetListener(this);
36717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
36817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node.dependencies == null || node.dependencies.size() == 0) {
36917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodesToStart.add(node);
37017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            } else {
37117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                for (Dependency dependency : node.dependencies) {
37217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependency.node.animation.addListener(
373010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                            new DependencyListener(this, node, dependency.rule));
37417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
37517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone();
37617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
377a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            node.animation.addListener(mSetListener);
37817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
37917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Now that all dependencies are set up, start the animations that should be started.
38021cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (mStartDelay <= 0) {
38121cd1389d2ef218b20994b617c57af120841a57fChet Haase            for (Node node : nodesToStart) {
38221cd1389d2ef218b20994b617c57af120841a57fChet Haase                node.animation.start();
38321cd1389d2ef218b20994b617c57af120841a57fChet Haase                mPlayingSet.add(node.animation);
38421cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
38521cd1389d2ef218b20994b617c57af120841a57fChet Haase        } else {
38621cd1389d2ef218b20994b617c57af120841a57fChet Haase            // TODO: Need to cancel out of the delay appropriately
387a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ValueAnimator delayAnim = new ValueAnimator(mStartDelay, 0f, 1f);
388a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            delayAnim.addListener(new AnimatorListenerAdapter() {
389a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                public void onAnimationEnd(Animator anim) {
39021cd1389d2ef218b20994b617c57af120841a57fChet Haase                    for (Node node : nodesToStart) {
39121cd1389d2ef218b20994b617c57af120841a57fChet Haase                        node.animation.start();
39221cd1389d2ef218b20994b617c57af120841a57fChet Haase                        mPlayingSet.add(node.animation);
39321cd1389d2ef218b20994b617c57af120841a57fChet Haase                    }
39421cd1389d2ef218b20994b617c57af120841a57fChet Haase                }
39521cd1389d2ef218b20994b617c57af120841a57fChet Haase            });
39617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
39717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (mListeners != null) {
398a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ArrayList<AnimatorListener> tmpListeners =
399a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    (ArrayList<AnimatorListener>) mListeners.clone();
400a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            for (AnimatorListener listener : tmpListeners) {
40117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                listener.onAnimationStart(this);
40217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
40317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
40417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
40517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
40649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    @Override
407a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public AnimatorSet clone() {
408a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        final AnimatorSet anim = (AnimatorSet) super.clone();
40949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        /*
41049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * The basic clone() operation copies all items. This doesn't work very well for
411a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * AnimatorSet, because it will copy references that need to be recreated and state
41249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * that may not apply. What we need to do now is put the clone in an uninitialized
41349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * state, with fresh, empty data structures. Then we will build up the nodes list
41449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * manually, as we clone each Node (and its animation). The clone will then be sorted,
41549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         * and will populate any appropriate lists, when it is started.
41649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase         */
41749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        anim.mNeedsSort = true;
41849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        anim.mCanceled = false;
419a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        anim.mPlayingSet = new ArrayList<Animator>();
420a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        anim.mNodeMap = new HashMap<Animator, Node>();
42149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        anim.mNodes = new ArrayList<Node>();
42249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        anim.mSortedNodes = new ArrayList<Node>();
42349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
42449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
425a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
42649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
42749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>(); // <old, new>
42849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        for (Node node : mNodes) {
42949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            Node nodeClone = node.clone();
43049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeCloneMap.put(node, nodeClone);
43149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            anim.mNodes.add(nodeClone);
43249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            anim.mNodeMap.put(nodeClone.animation, nodeClone);
43349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            // Clear out the dependencies in the clone; we'll set these up manually later
43449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.dependencies = null;
43549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.tmpDependencies = null;
43649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.nodeDependents = null;
43749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            nodeClone.nodeDependencies = null;
438a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            // clear out any listeners that were set up by the AnimatorSet; these will
43949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            // be set up when the clone's nodes are sorted
440a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
44149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            if (cloneListeners != null) {
442a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                ArrayList<AnimatorListener> listenersToRemove = null;
443a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                for (AnimatorListener listener : cloneListeners) {
444a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    if (listener instanceof AnimatorSetListener) {
44549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                        if (listenersToRemove == null) {
446a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                            listenersToRemove = new ArrayList<AnimatorListener>();
44749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                        }
44849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                        listenersToRemove.add(listener);
44949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    }
45049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                }
45149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                if (listenersToRemove != null) {
452a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    for (AnimatorListener listener : listenersToRemove) {
45349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                        cloneListeners.remove(listener);
45449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    }
45549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                }
45649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            }
45749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
45849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // Now that we've cloned all of the nodes, we're ready to walk through their
45949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        // dependencies, mapping the old dependencies to the new nodes
46049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        for (Node node : mNodes) {
46149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            Node nodeClone = nodeCloneMap.get(node);
46249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            if (node.dependencies != null) {
46349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                for (Dependency dependency : node.dependencies) {
46449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    Node clonedDependencyNode = nodeCloneMap.get(dependency.node);
46549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    Dependency cloneDependency = new Dependency(clonedDependencyNode,
46649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                            dependency.rule);
46749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                    nodeClone.addDependency(cloneDependency);
46849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase                }
46949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase            }
47049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
47149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
47249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        return anim;
47349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    }
47449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
47517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
47617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This class is the mechanism by which animations are started based on events in other
47717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * animations. If an animation has multiple dependencies on other animations, then
47817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * all dependencies must be satisfied before the animation is started.
47917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
480a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private static class DependencyListener implements AnimatorListener {
48117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
482a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private AnimatorSet mAnimatorSet;
483010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase
48417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The node upon which the dependency is based.
48517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private Node mNode;
48617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
48717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The Dependency rule (WITH or AFTER) that the listener should wait for on
48817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // the node
48917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private int mRule;
49017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
491a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public DependencyListener(AnimatorSet animatorSet, Node node, int rule) {
492a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            this.mAnimatorSet = animatorSet;
49317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.mNode = node;
49417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.mRule = rule;
49517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
49617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
49717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
498010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * Ignore cancel events for now. We may want to handle this eventually,
499010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * to prevent follow-on animations from running when some dependency
500010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase         * animation is canceled.
50117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
502a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationCancel(Animator animation) {
50317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
50417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
50517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
50617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * An end event is received - see if this is an event we are listening for
50717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
508a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationEnd(Animator animation) {
50917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mRule == Dependency.AFTER) {
51017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                startIfReady(animation);
51117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
51217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
51317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
51417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
51517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Ignore repeat events for now
51617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
517a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationRepeat(Animator animation) {
51817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
51917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
52017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
52117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * A start event is received - see if this is an event we are listening for
52217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
523a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationStart(Animator animation) {
52417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mRule == Dependency.WITH) {
52517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                startIfReady(animation);
52617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
52717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
52817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
52917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
53017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Check whether the event received is one that the node was waiting for.
53117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * If so, mark it as complete and see whether it's time to start
53217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the animation.
53317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param dependencyAnimation the animation that sent the event.
53417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
535a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private void startIfReady(Animator dependencyAnimation) {
536a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            if (mAnimatorSet.mCanceled) {
537a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                // if the parent AnimatorSet was canceled, then don't start any dependent anims
538010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                return;
539010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase            }
54017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependencyToRemove = null;
54117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            for (Dependency dependency : mNode.tmpDependencies) {
54217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (dependency.rule == mRule &&
54317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        dependency.node.animation == dependencyAnimation) {
54417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    // rule fired - remove the dependency and listener and check to
54517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    // see whether it's time to start the animation
54617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependencyToRemove = dependency;
54717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    dependencyAnimation.removeListener(this);
54817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    break;
54917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
55017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
55117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNode.tmpDependencies.remove(dependencyToRemove);
55217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mNode.tmpDependencies.size() == 0) {
55317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                // all dependencies satisfied: start the animation
55417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNode.animation.start();
555a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                mAnimatorSet.mPlayingSet.add(mNode.animation);
55617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
55717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
55817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
55917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
56017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
561a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private class AnimatorSetListener implements AnimatorListener {
56217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
563a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        private AnimatorSet mAnimatorSet;
56417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
565a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        AnimatorSetListener(AnimatorSet animatorSet) {
566a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            mAnimatorSet = animatorSet;
56717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
56817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
569a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationCancel(Animator animation) {
57017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mPlayingSet.size() == 0) {
57117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (mListeners != null) {
572a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    for (AnimatorListener listener : mListeners) {
573a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                        listener.onAnimationCancel(mAnimatorSet);
57417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
57517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
57617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
57717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
57817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
57917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        @SuppressWarnings("unchecked")
580a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationEnd(Animator animation) {
58117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            animation.removeListener(this);
58217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mPlayingSet.remove(animation);
583a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            Node animNode = mAnimatorSet.mNodeMap.get(animation);
5841e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase            animNode.done = true;
585a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
586a6e4a1757728efc91627ece602b0899d75303659Chet Haase            boolean allDone = true;
587673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase            for (Node node : sortedNodes) {
5881e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase                if (!node.done) {
589a6e4a1757728efc91627ece602b0899d75303659Chet Haase                    allDone = false;
590a6e4a1757728efc91627ece602b0899d75303659Chet Haase                    break;
591a6e4a1757728efc91627ece602b0899d75303659Chet Haase                }
592a6e4a1757728efc91627ece602b0899d75303659Chet Haase            }
593a6e4a1757728efc91627ece602b0899d75303659Chet Haase            if (allDone) {
59417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                // If this was the last child animation to end, then notify listeners that this
595a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                // AnimatorSet has ended
59617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (mListeners != null) {
597a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    ArrayList<AnimatorListener> tmpListeners =
598a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                            (ArrayList<AnimatorListener>) mListeners.clone();
599a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                    for (AnimatorListener listener : tmpListeners) {
600a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                        listener.onAnimationEnd(mAnimatorSet);
60117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
60217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
60317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
60417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
60517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
60617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Nothing to do
607a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationRepeat(Animator animation) {
60817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
60917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
61017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // Nothing to do
611a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void onAnimationStart(Animator animation) {
61217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
61317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
61417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
61517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
61617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
61717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * This method sorts the current set of nodes, if needed. The sort is a simple
61817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * DependencyGraph sort, which goes like this:
61917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * - All nodes without dependencies become 'roots'
62017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * - while roots list is not null
62117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -   for each root r
62217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -     add r to sorted list
62317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -     remove r as a dependency from any other node
62417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * -   any nodes with no dependencies are added to the roots list
62517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
62617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private void sortNodes() {
62717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        if (mNeedsSort) {
62817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mSortedNodes.clear();
62917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            ArrayList<Node> roots = new ArrayList<Node>();
63017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            for (Node node : mNodes) {
63117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (node.dependencies == null || node.dependencies.size() == 0) {
63217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    roots.add(node);
63317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
63417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
63517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            ArrayList<Node> tmpRoots = new ArrayList<Node>();
63617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            while (roots.size() > 0) {
63717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                for (Node root : roots) {
63817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    mSortedNodes.add(root);
63917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    if (root.nodeDependents != null) {
64017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        for (Node node : root.nodeDependents) {
64117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies.remove(root);
64217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            if (node.nodeDependencies.size() == 0) {
64317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                                tmpRoots.add(node);
64417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            }
64517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
64617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
64717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
648010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase                roots.clear();
64917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                roots.addAll(tmpRoots);
65017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                tmpRoots.clear();
65117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
65217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mNeedsSort = false;
65317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mSortedNodes.size() != mNodes.size()) {
65417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                throw new IllegalStateException("Circular dependencies cannot exist"
655a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                        + " in AnimatorSet");
65617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
65717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        } else {
65817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // Doesn't need sorting, but still need to add in the nodeDependencies list
65917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // because these get removed as the event listeners fire and the dependencies
66017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            // are satisfied
66117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            for (Node node : mNodes) {
66217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                if (node.dependencies != null && node.dependencies.size() > 0) {
66317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    for (Dependency dependency : node.dependencies) {
66417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        if (node.nodeDependencies == null) {
66517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies = new ArrayList<Node>();
66617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
66717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        if (!node.nodeDependencies.contains(dependency.node)) {
66817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                            node.nodeDependencies.add(dependency.node);
66917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                        }
67017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                    }
67117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                }
6721e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase                node.done = false;
67317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
67417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
67517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
67617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
67717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
67817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * Dependency holds information about the node that some other node is
67917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * dependent upon and the nature of that dependency.
68017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *
68117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
68217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    private static class Dependency {
68317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        static final int WITH = 0; // dependent node must start with this dependency node
68417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        static final int AFTER = 1; // dependent node must start when this dependency node finishes
68517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
68617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The node that the other node with this Dependency is dependent upon
68717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public Node node;
68817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
68917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        // The nature of the dependency (WITH or AFTER)
69017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public int rule;
69117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
69217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public Dependency(Node node, int rule) {
69317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.node = node;
69417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.rule = rule;
69517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
69617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
69717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
69817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
699a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * A Node is an embodiment of both the Animator that it wraps as well as
70017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * any dependencies that are associated with that Animation. This includes
70117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * both dependencies upon other nodes (in the dependencies list) as
70217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * well as dependencies of other nodes upon this (in the nodeDependents list).
70317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
70449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase    private static class Node implements Cloneable {
705a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public Animator animation;
70617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
70717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
70817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  These are the dependencies that this node's animation has on other
70917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  nodes. For example, if this node's animation should begin with some
71017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  other animation ends, then there will be an item in this node's
71117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *  dependencies list for that other animation's node.
71217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
71317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Dependency> dependencies = null;
71417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
71517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
71617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * tmpDependencies is a runtime detail. We use the dependencies list for sorting.
71717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * But we also use the list to keep track of when multiple dependencies are satisfied,
71817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * but removing each dependency as it is satisfied. We do not want to remove
71917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the dependency itself from the list, because we need to retain that information
720a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * if the AnimatorSet is launched in the future. So we create a copy of the dependency
721a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * list when the AnimatorSet starts and use this tmpDependencies list to track the
72217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * list of satisfied dependencies.
72317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
72417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Dependency> tmpDependencies = null;
72517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
72617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
72717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * nodeDependencies is just a list of the nodes that this Node is dependent upon.
72817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * This information is used in sortNodes(), to determine when a node is a root.
72917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
73017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Node> nodeDependencies = null;
73117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
73217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
73317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * nodeDepdendents is the list of nodes that have this node as a dependency. This
73417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * is a utility field used in sortNodes to facilitate removing this node as a
73517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * dependency when it is a root node.
73617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
73717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public ArrayList<Node> nodeDependents = null;
73817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
73917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
7401e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase         * Flag indicating whether the animation in this node is finished. This flag
741a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * is used by AnimatorSet to check, as each animation ends, whether all child animations
742a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * are done and it's time to send out an end event for the entire AnimatorSet.
7431e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase         */
7441e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase        public boolean done = false;
7451e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase
7461e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase        /**
74717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Constructs the Node with the animation that it encapsulates. A Node has no
74817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * dependencies by default; dependencies are added via the addDependency()
74917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * method.
75017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
75117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param animation The animation that the Node encapsulates.
75217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
753a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public Node(Animator animation) {
75417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            this.animation = animation;
75517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
75617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
75717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
75817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Add a dependency to this Node. The dependency includes information about the
75917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * node that this node is dependency upon and the nature of the dependency.
76017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param dependency
76117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
76217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public void addDependency(Dependency dependency) {
76317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (dependencies == null) {
76417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                dependencies = new ArrayList<Dependency>();
76517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodeDependencies = new ArrayList<Node>();
76617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
76717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            dependencies.add(dependency);
76817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (!nodeDependencies.contains(dependency.node)) {
76917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                nodeDependencies.add(dependency.node);
77017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
77117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node dependencyNode = dependency.node;
77217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (dependencyNode.nodeDependents == null) {
77317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                dependencyNode.nodeDependents = new ArrayList<Node>();
77417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
77517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            dependencyNode.nodeDependents.add(this);
77617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
77749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase
77849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        @Override
77921cd1389d2ef218b20994b617c57af120841a57fChet Haase        public Node clone() {
78021cd1389d2ef218b20994b617c57af120841a57fChet Haase            try {
78121cd1389d2ef218b20994b617c57af120841a57fChet Haase                Node node = (Node) super.clone();
782a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase                node.animation = (Animator) animation.clone();
78321cd1389d2ef218b20994b617c57af120841a57fChet Haase                return node;
78421cd1389d2ef218b20994b617c57af120841a57fChet Haase            } catch (CloneNotSupportedException e) {
78521cd1389d2ef218b20994b617c57af120841a57fChet Haase               throw new AssertionError();
78621cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
78749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase        }
78817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
78917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
79017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    /**
79117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * The <code>Builder</code> object is a utility class to facilitate adding animations to a
792a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <code>AnimatorSet</code> along with the relationships between the various animations. The
79317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * intention of the <code>Builder</code> methods, along with the {@link
794a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible to
79517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * express the dependency relationships of animations in a natural way. Developers can also use
796a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
797a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
798a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
79917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
80017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
801a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
80217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
803a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
80417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
80517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
806a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *     AnimatorSet s = new AnimatorSet();
80717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim1).with(anim2);
80817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim2).before(anim3);
80917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *     s.play(anim4).after(anim3);
81017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
81117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
812a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
813a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Builder#after(Animator)} are used. These are just different ways of expressing the same
81417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * relationship and are provided to make it easier to say things in a way that is more natural,
81517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * depending on the situation.</p>
81617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
81717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>It is possible to make several calls into the same <code>Builder</code> object to express
81817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * multiple relationships. However, note that it is only the animation passed into the initial
819a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
82017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * calls to the <code>Builder</code> object. For example, the following code starts both anim2
82117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
82217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * anim3:
82317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
824a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *   AnimatorSet s = new AnimatorSet();
82517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim1).before(anim2).before(anim3);
82617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
82717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
82817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * relationship correctly:</p>
82917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <pre>
830a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     *   AnimatorSet s = new AnimatorSet();
83117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim1).before(anim2);
83217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     *   s.play(anim2).before(anim3);
83317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * </pre>
83417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p/>
83517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * <p>Note that it is possible to express relationships that cannot be resolved and will not
83617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
83717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * sense. In general, circular dependencies like this one (or more indirect ones where a depends
838a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
839a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * that can boil down to a simple, one-way relationship of animations starting with, before, and
84017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     * after other, different, animations.</p>
84117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase     */
84217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    public class Builder {
84317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
84417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
84517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * This tracks the current node being processed. It is supplied to the play() method
846a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * of AnimatorSet and passed into the constructor of Builder.
84717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
84817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        private Node mCurrentNode;
84917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
85017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
851a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * package-private constructor. Builders are only constructed by AnimatorSet, when the
85217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * play() method is called.
85317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
85417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that is the dependency for the other animations passed into
85517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * the other methods of this Builder object.
85617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
857a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        Builder(Animator anim) {
85817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mCurrentNode = mNodeMap.get(anim);
85917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (mCurrentNode == null) {
86017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mCurrentNode = new Node(anim);
86117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, mCurrentNode);
86217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(mCurrentNode);
86317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
86417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
86517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
86617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
86717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play at the same time as the animation supplied in the
868a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
86917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
87017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that will play when the animation supplied to the
871a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method starts.
87217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
873a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void with(Animator anim) {
87417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
87517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
87617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
87717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
87817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
87917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
88017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
88117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            node.addDependency(dependency);
88217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
88317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
88417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
88517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play when the animation supplied in the
886a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
88717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * ends.
88817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
88917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation that will play when the animation supplied to the
890a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method ends.
89117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
892a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void before(Animator anim) {
89317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
89417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
89517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
89617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
89717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
89817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
89917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
90017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            node.addDependency(dependency);
90117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
90217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
90317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
90417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the given animation to play when the animation supplied in the
905a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
90617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * to start when the animation supplied in this method call ends.
90717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
90817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param anim The animation whose end will cause the animation supplied to the
909a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} method to play.
91017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
911a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        public void after(Animator anim) {
91217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Node node = mNodeMap.get(anim);
91317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            if (node == null) {
91417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                node = new Node(anim);
91517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodeMap.put(anim, node);
91617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase                mNodes.add(node);
91717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            }
91817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            Dependency dependency = new Dependency(node, Dependency.AFTER);
91917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase            mCurrentNode.addDependency(dependency);
92017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
92117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
92217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        /**
92317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * Sets up the animation supplied in the
924a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
92517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * to play when the given amount of time elapses.
92617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         *
92717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * @param delay The number of milliseconds that should elapse before the
92817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         * animation starts.
92917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase         */
93017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        public void after(long delay) {
931a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            // setup dummy ValueAnimator just to run the clock
932a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            after(new ValueAnimator(delay, 0f, 1f));
93317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase        }
93417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
93517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase    }
93617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase
93717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase}
938