AnimatorSet.java revision d45204ba092312630a0e516ea7c247e594ce893b
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; 22d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenenimport java.util.Iterator; 2337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haaseimport java.util.List; 2417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 2517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase/** 26a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * This class plays a set of {@link Animator} objects in the specified order. Animations 2717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * can be set up to play together, in sequence, or after a specified delay. 2817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 29a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>There are two different approaches to adding animations to a <code>AnimatorSet</code>: 30a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or 31a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add 32a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be 33a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * used in conjunction with methods in the {@link AnimatorSet.Builder Builder} 3417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * class to add animations 3517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * one by one.</p> 3617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 37a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>It is possible to set up a <code>AnimatorSet</code> with circular dependencies between 3817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * its animations. For example, an animation a1 could be set up to start before animation a2, a2 3917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * before a3, and a3 before a1. The results of this configuration are undefined, but will typically 4017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * result in none of the affected animations being played. Because of this (and because 4117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * circular dependencies do not make logical sense anyway), circular dependencies 4217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * should be avoided, and the dependency flow of animations should only be in one direction. 4317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 44a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haasepublic final class AnimatorSet extends Animator { 4517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 4617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 4749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * Internal variables 4849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * NOTE: This object implements the clone() method, making a deep copy of any referenced 4949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * objects. As other non-trivial fields are added to this class, make sure to add logic 5049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * to clone() to make deep copies of them. 5149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase */ 5249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase 5349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase /** 543b69b6f0be85d1f97c1e6824cf986777ba4e5d00Chet Haase * Tracks animations currently being played, so that we know what to 55a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * cancel or end when cancel() or end() is called on this AnimatorSet 5617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 57a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>(); 5817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 5917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 60a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Contains all nodes, mapped to their respective Animators. When new 61a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * dependency information is added for an Animator, we want to add it 62a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * to a single node representing that Animator, not create a new Node 6317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * if one already exists. 6417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 65a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase private HashMap<Animator, Node> mNodeMap = new HashMap<Animator, Node>(); 6617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 6717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 68a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Set of all nodes created for this AnimatorSet. This list is used upon 69a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * starting the set, and the nodes are placed in sorted order into the 7017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * sortedNodes collection. 7117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 7249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase private ArrayList<Node> mNodes = new ArrayList<Node>(); 7317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 7417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 7517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * The sorted list of nodes. This is the order in which the animations will 7617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * be played. The details about when exactly they will be played depend 7717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * on the dependency relationships of the nodes. 7817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 7949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase private ArrayList<Node> mSortedNodes = new ArrayList<Node>(); 8017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 8117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 8217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Flag indicating whether the nodes should be sorted prior to playing. This 8317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * flag allows us to cache the previous sorted nodes so that if the sequence 8417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * is replayed with no changes, it does not have to re-sort the nodes again. 8517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 8617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase private boolean mNeedsSort = true; 8717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 88a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase private AnimatorSetListener mSetListener = null; 8917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 9017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 917dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase * Flag indicating that the AnimatorSet has been manually 927dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase * terminated (by calling cancel() or end()). 93010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase * This flag is used to avoid starting other animations when currently-playing 947dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase * child animations of this AnimatorSet end. It also determines whether cancel/end 957dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase * notifications are sent out via the normal AnimatorSetListener mechanism. 96010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase */ 977dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase boolean mTerminated = false; 98010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase 9921cd1389d2ef218b20994b617c57af120841a57fChet Haase // The amount of time in ms to delay starting the animation after start() is called 10021cd1389d2ef218b20994b617c57af120841a57fChet Haase private long mStartDelay = 0; 10121cd1389d2ef218b20994b617c57af120841a57fChet Haase 102e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase // Animator used for a nonzero startDelay 103e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase private ValueAnimator mDelayAnim = null; 104e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase 10521cd1389d2ef218b20994b617c57af120841a57fChet Haase 10621cd1389d2ef218b20994b617c57af120841a57fChet Haase // How long the child animations should last in ms. The default value is negative, which 107a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase // simply means that there is no duration set on the AnimatorSet. When a real duration is 10821cd1389d2ef218b20994b617c57af120841a57fChet Haase // set, it is passed along to the child animations. 10921cd1389d2ef218b20994b617c57af120841a57fChet Haase private long mDuration = -1; 11021cd1389d2ef218b20994b617c57af120841a57fChet Haase 11121cd1389d2ef218b20994b617c57af120841a57fChet Haase 112010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase /** 113a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Sets up this AnimatorSet to play all of the supplied animations at the same time. 11417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 115a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @param items The animations that will be started simultaneously. 11617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 117a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void playTogether(Animator... items) { 118a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase if (items != null) { 11917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNeedsSort = true; 120a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase Builder builder = play(items[0]); 121a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase for (int i = 1; i < items.length; ++i) { 122a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase builder.with(items[i]); 12317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 12417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 12517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 12617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 12717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 12837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase * Sets up this AnimatorSet to play all of the supplied animations at the same time. 12937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase * 13037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase * @param items The animations that will be started simultaneously. 13137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase */ 13237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase public void playTogether(Collection<Animator> items) { 13337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase if (items != null && items.size() > 0) { 13437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase mNeedsSort = true; 13537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase Builder builder = null; 13637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase for (Animator anim : items) { 13737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase if (builder == null) { 13837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase builder = play(anim); 13937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } else { 14037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase builder.with(anim); 14137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } 14237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } 14337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } 14437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } 14537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase 14637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase /** 147a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Sets up this AnimatorSet to play each of the supplied animations when the 14817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * previous animation ends. 14917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 15037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase * @param items The animations that will be started one after another. 15117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 152a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void playSequentially(Animator... items) { 153a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase if (items != null) { 15417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNeedsSort = true; 155a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase if (items.length == 1) { 156a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase play(items[0]); 15717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } else { 158a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase for (int i = 0; i < items.length - 1; ++i) { 159a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase play(items[i]).before(items[i+1]); 16017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 16117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 16217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 16317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 16417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 16517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 16637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase * Sets up this AnimatorSet to play each of the supplied animations when the 16737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase * previous animation ends. 16837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase * 16937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase * @param items The animations that will be started one after another. 17037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase */ 17137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase public void playSequentially(List<Animator> items) { 17237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase if (items != null && items.size() > 0) { 17337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase mNeedsSort = true; 17437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase if (items.size() == 1) { 17537a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase play(items.get(0)); 17637a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } else { 17737a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase for (int i = 0; i < items.size() - 1; ++i) { 17837a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase play(items.get(i)).before(items.get(i+1)); 17937a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } 18037a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } 18137a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } 18237a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase } 18337a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase 18437a7bec599e8d877d8a7f12ab2c2c160d1c2cf8aChet Haase /** 185a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Returns the current list of child Animator objects controlled by this 186a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * AnimatorSet. This is a copy of the internal list; modifications to the returned list 187a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * will not affect the AnimatorSet, although changes to the underlying Animator objects 188a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * will affect those objects being managed by the AnimatorSet. 189f54a8d7c479485174941c38f151ea7083c658da3Chet Haase * 190a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @return ArrayList<Animator> The list of child animations of this AnimatorSet. 191f54a8d7c479485174941c38f151ea7083c658da3Chet Haase */ 192a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public ArrayList<Animator> getChildAnimations() { 193a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase ArrayList<Animator> childList = new ArrayList<Animator>(); 194f54a8d7c479485174941c38f151ea7083c658da3Chet Haase for (Node node : mNodes) { 195f54a8d7c479485174941c38f151ea7083c658da3Chet Haase childList.add(node.animation); 196f54a8d7c479485174941c38f151ea7083c658da3Chet Haase } 197f54a8d7c479485174941c38f151ea7083c658da3Chet Haase return childList; 198f54a8d7c479485174941c38f151ea7083c658da3Chet Haase } 199f54a8d7c479485174941c38f151ea7083c658da3Chet Haase 200f54a8d7c479485174941c38f151ea7083c658da3Chet Haase /** 201811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase * Sets the target object for all current {@link #getChildAnimations() child animations} 202a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * of this AnimatorSet that take targets ({@link ObjectAnimator} and 203a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * AnimatorSet). 204811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase * 205811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase * @param target The object being animated 206811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase */ 20721cd1389d2ef218b20994b617c57af120841a57fChet Haase @Override 208811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase public void setTarget(Object target) { 209811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase for (Node node : mNodes) { 210a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase Animator animation = node.animation; 211a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase if (animation instanceof AnimatorSet) { 212a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase ((AnimatorSet)animation).setTarget(target); 213a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase } else if (animation instanceof ObjectAnimator) { 214a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase ((ObjectAnimator)animation).setTarget(target); 215811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase } 216811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase } 217811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase } 218811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase 219811ed1065f39469cf2cf6adba22cab397ed88d5eChet Haase /** 220e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations} 221a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * of this AnimatorSet. 22221cd1389d2ef218b20994b617c57af120841a57fChet Haase * 223a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @param interpolator the interpolator to be used by each child animation of this AnimatorSet 22421cd1389d2ef218b20994b617c57af120841a57fChet Haase */ 22521cd1389d2ef218b20994b617c57af120841a57fChet Haase @Override 226e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase public void setInterpolator(TimeInterpolator interpolator) { 22721cd1389d2ef218b20994b617c57af120841a57fChet Haase for (Node node : mNodes) { 22821cd1389d2ef218b20994b617c57af120841a57fChet Haase node.animation.setInterpolator(interpolator); 22921cd1389d2ef218b20994b617c57af120841a57fChet Haase } 23021cd1389d2ef218b20994b617c57af120841a57fChet Haase } 23121cd1389d2ef218b20994b617c57af120841a57fChet Haase 23221cd1389d2ef218b20994b617c57af120841a57fChet Haase /** 23317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * This method creates a <code>Builder</code> object, which is used to 23417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * set up playing constraints. This initial <code>play()</code> method 23517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * tells the <code>Builder</code> the animation that is the dependency for 23617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * the succeeding commands to the <code>Builder</code>. For example, 237a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * calling <code>play(a1).with(a2)</code> sets up the AnimatorSet to play 23817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <code>a1</code> and <code>a2</code> at the same time, 239a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <code>play(a1).before(a2)</code> sets up the AnimatorSet to play 24017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <code>a1</code> first, followed by <code>a2</code>, and 241a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <code>play(a1).after(a2)</code> sets up the AnimatorSet to play 24217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <code>a2</code> first, followed by <code>a1</code>. 24317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 24417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p>Note that <code>play()</code> is the only way to tell the 24517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <code>Builder</code> the animation upon which the dependency is created, 24617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * so successive calls to the various functions in <code>Builder</code> 24717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * will all refer to the initial parameter supplied in <code>play()</code> 24817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * as the dependency of the other animations. For example, calling 24917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code> 25017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * and <code>a3</code> when a1 ends; it does not set up a dependency between 25117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <code>a2</code> and <code>a3</code>.</p> 25217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 25317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param anim The animation that is the dependency used in later calls to the 25417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * methods in the returned <code>Builder</code> object. A null parameter will result 25517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * in a null <code>Builder</code> return value. 256a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @return Builder The object that constructs the AnimatorSet based on the dependencies 25717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * outlined in the calls to <code>play</code> and the other methods in the 25817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <code>Builder</code object. 25917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 260a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public Builder play(Animator anim) { 26117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (anim != null) { 26217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNeedsSort = true; 26317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase return new Builder(anim); 26417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 26517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase return null; 26617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 26717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 26817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 26917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * {@inheritDoc} 27017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 271a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>Note that canceling a <code>AnimatorSet</code> also cancels all of the animations that it is 27217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * responsible for.</p> 27317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 27417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase @SuppressWarnings("unchecked") 27517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase @Override 27617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public void cancel() { 2777dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase mTerminated = true; 2787dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (isRunning()) { 2797dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase ArrayList<AnimatorListener> tmpListeners = null; 280e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase if (mListeners != null) { 2817dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone(); 282e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase for (AnimatorListener listener : tmpListeners) { 2837dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase listener.onAnimationCancel(this); 284e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase } 285e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase } 2867dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mDelayAnim != null && mDelayAnim.isRunning()) { 2877dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // If we're currently in the startDelay period, just cancel that animator and 2887dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // send out the end event to all listeners 2897dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase mDelayAnim.cancel(); 2907dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } else if (mSortedNodes.size() > 0) { 2917dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase for (Node node : mSortedNodes) { 2927dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase node.animation.cancel(); 2937dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 2947dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 2957dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (tmpListeners != null) { 2967dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase for (AnimatorListener listener : tmpListeners) { 2977dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase listener.onAnimationEnd(this); 2987dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 29917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 30017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 30117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 30217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 30317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 30417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * {@inheritDoc} 30517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 306a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>Note that ending a <code>AnimatorSet</code> also ends all of the animations that it is 30717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * responsible for.</p> 30817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 30917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase @Override 31017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public void end() { 3117dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase mTerminated = true; 3127dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (isRunning()) { 3137dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mSortedNodes.size() != mNodes.size()) { 3147dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // hasn't been started yet - sort the nodes now, then end them 3157dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase sortNodes(); 3167dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase for (Node node : mSortedNodes) { 3177dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mSetListener == null) { 3187dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase mSetListener = new AnimatorSetListener(this); 3197dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 3207dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase node.animation.addListener(mSetListener); 3211e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase } 3221e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase } 3237dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mDelayAnim != null) { 3247dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase mDelayAnim.cancel(); 3257dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 3267dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mSortedNodes.size() > 0) { 3277dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase for (Node node : mSortedNodes) { 3287dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase node.animation.end(); 3297dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 3307dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 3317dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mListeners != null) { 3327dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase ArrayList<AnimatorListener> tmpListeners = 3337dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase (ArrayList<AnimatorListener>) mListeners.clone(); 3347dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase for (AnimatorListener listener : tmpListeners) { 3357dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase listener.onAnimationEnd(this); 3367dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 33717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 33817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 33917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 34017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 34117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 342a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Returns true if any of the child animations of this AnimatorSet have been started and have not 343673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase * yet ended. 344a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * @return Whether this AnimatorSet has been started and has not yet ended. 345673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase */ 346673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase @Override 347673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase public boolean isRunning() { 348673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase for (Node node : mNodes) { 349673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase if (node.animation.isRunning()) { 350673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase return true; 351673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase } 352673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase } 353673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase return false; 354673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase } 355673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase 356673e42fafd4088970ec95e1f13c61dc83132c74eChet Haase /** 35721cd1389d2ef218b20994b617c57af120841a57fChet Haase * The amount of time, in milliseconds, to delay starting the animation after 35821cd1389d2ef218b20994b617c57af120841a57fChet Haase * {@link #start()} is called. 35921cd1389d2ef218b20994b617c57af120841a57fChet Haase * 36021cd1389d2ef218b20994b617c57af120841a57fChet Haase * @return the number of milliseconds to delay running the animation 36121cd1389d2ef218b20994b617c57af120841a57fChet Haase */ 36221cd1389d2ef218b20994b617c57af120841a57fChet Haase @Override 36321cd1389d2ef218b20994b617c57af120841a57fChet Haase public long getStartDelay() { 36421cd1389d2ef218b20994b617c57af120841a57fChet Haase return mStartDelay; 36521cd1389d2ef218b20994b617c57af120841a57fChet Haase } 36621cd1389d2ef218b20994b617c57af120841a57fChet Haase 36721cd1389d2ef218b20994b617c57af120841a57fChet Haase /** 36821cd1389d2ef218b20994b617c57af120841a57fChet Haase * The amount of time, in milliseconds, to delay starting the animation after 36921cd1389d2ef218b20994b617c57af120841a57fChet Haase * {@link #start()} is called. 37021cd1389d2ef218b20994b617c57af120841a57fChet Haase 37121cd1389d2ef218b20994b617c57af120841a57fChet Haase * @param startDelay The amount of the delay, in milliseconds 37221cd1389d2ef218b20994b617c57af120841a57fChet Haase */ 37321cd1389d2ef218b20994b617c57af120841a57fChet Haase @Override 37421cd1389d2ef218b20994b617c57af120841a57fChet Haase public void setStartDelay(long startDelay) { 37521cd1389d2ef218b20994b617c57af120841a57fChet Haase mStartDelay = startDelay; 37621cd1389d2ef218b20994b617c57af120841a57fChet Haase } 37721cd1389d2ef218b20994b617c57af120841a57fChet Haase 37821cd1389d2ef218b20994b617c57af120841a57fChet Haase /** 379a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Gets the length of each of the child animations of this AnimatorSet. This value may 380a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * be less than 0, which indicates that no duration has been set on this AnimatorSet 38121cd1389d2ef218b20994b617c57af120841a57fChet Haase * and each of the child animations will use their own duration. 38221cd1389d2ef218b20994b617c57af120841a57fChet Haase * 38321cd1389d2ef218b20994b617c57af120841a57fChet Haase * @return The length of the animation, in milliseconds, of each of the child 384a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * animations of this AnimatorSet. 38521cd1389d2ef218b20994b617c57af120841a57fChet Haase */ 38621cd1389d2ef218b20994b617c57af120841a57fChet Haase @Override 38721cd1389d2ef218b20994b617c57af120841a57fChet Haase public long getDuration() { 38821cd1389d2ef218b20994b617c57af120841a57fChet Haase return mDuration; 38921cd1389d2ef218b20994b617c57af120841a57fChet Haase } 39021cd1389d2ef218b20994b617c57af120841a57fChet Haase 39121cd1389d2ef218b20994b617c57af120841a57fChet Haase /** 392a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Sets the length of each of the current child animations of this AnimatorSet. By default, 393a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * each child animation will use its own duration. If the duration is set on the AnimatorSet, 39421cd1389d2ef218b20994b617c57af120841a57fChet Haase * then each child animation inherits this duration. 39521cd1389d2ef218b20994b617c57af120841a57fChet Haase * 39621cd1389d2ef218b20994b617c57af120841a57fChet Haase * @param duration The length of the animation, in milliseconds, of each of the child 397a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * animations of this AnimatorSet. 39821cd1389d2ef218b20994b617c57af120841a57fChet Haase */ 39921cd1389d2ef218b20994b617c57af120841a57fChet Haase @Override 4002794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase public AnimatorSet setDuration(long duration) { 40121cd1389d2ef218b20994b617c57af120841a57fChet Haase if (duration < 0) { 40221cd1389d2ef218b20994b617c57af120841a57fChet Haase throw new IllegalArgumentException("duration must be a value of zero or greater"); 40321cd1389d2ef218b20994b617c57af120841a57fChet Haase } 40421cd1389d2ef218b20994b617c57af120841a57fChet Haase for (Node node : mNodes) { 405a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to 40621cd1389d2ef218b20994b617c57af120841a57fChet Haase // insert "play-after" delays 40721cd1389d2ef218b20994b617c57af120841a57fChet Haase node.animation.setDuration(duration); 40821cd1389d2ef218b20994b617c57af120841a57fChet Haase } 40921cd1389d2ef218b20994b617c57af120841a57fChet Haase mDuration = duration; 4102794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase return this; 41121cd1389d2ef218b20994b617c57af120841a57fChet Haase } 41221cd1389d2ef218b20994b617c57af120841a57fChet Haase 4132970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase @Override 4142970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase public void setupStartValues() { 4152970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase for (Node node : mNodes) { 4162970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase node.animation.setupStartValues(); 4172970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase } 4182970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase } 4192970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase 4202970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase @Override 4212970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase public void setupEndValues() { 4222970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase for (Node node : mNodes) { 4232970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase node.animation.setupEndValues(); 4242970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase } 4252970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase } 4262970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase 42721cd1389d2ef218b20994b617c57af120841a57fChet Haase /** 42817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * {@inheritDoc} 42917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 430a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which 43117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * it is responsible. The details of when exactly those animations are started depends on 43217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * the dependency relationships that have been set up between the animations. 43317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 43417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase @SuppressWarnings("unchecked") 43517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase @Override 43617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public void start() { 4377dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase mTerminated = false; 438010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase 43917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // First, sort the nodes (if necessary). This will ensure that sortedNodes 44017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // contains the animation nodes in the correct order. 44117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase sortNodes(); 44217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 443e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase int numSortedNodes = mSortedNodes.size(); 444e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase for (int i = 0; i < numSortedNodes; ++i) { 445e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase Node node = mSortedNodes.get(i); 446e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase // First, clear out the old listeners 447e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase ArrayList<AnimatorListener> oldListeners = node.animation.getListeners(); 448e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase if (oldListeners != null && oldListeners.size() > 0) { 449d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen final ArrayList<AnimatorListener> clonedListeners = new 450d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen ArrayList<AnimatorListener>(oldListeners); 451d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen 452d45204ba092312630a0e516ea7c247e594ce893bMartijn Coenen for (AnimatorListener listener : clonedListeners) { 4537dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (listener instanceof DependencyListener || 4547dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase listener instanceof AnimatorSetListener) { 455e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase node.animation.removeListener(listener); 456e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase } 457e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase } 458e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase } 459e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase } 460e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase 46117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // nodesToStart holds the list of nodes to be started immediately. We don't want to 46217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // start the animations in the loop directly because we first need to set up 46317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // dependencies on all of the nodes. For example, we don't want to start an animation 46417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // when some other animation also wants to start when the first animation begins. 46521cd1389d2ef218b20994b617c57af120841a57fChet Haase final ArrayList<Node> nodesToStart = new ArrayList<Node>(); 4667c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int i = 0; i < numSortedNodes; ++i) { 4677c608f25d494c8a0a671e7373efbb47ca635367eChet Haase Node node = mSortedNodes.get(i); 468a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase if (mSetListener == null) { 469a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase mSetListener = new AnimatorSetListener(this); 47017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 47117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (node.dependencies == null || node.dependencies.size() == 0) { 47217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase nodesToStart.add(node); 47317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } else { 4747c608f25d494c8a0a671e7373efbb47ca635367eChet Haase int numDependencies = node.dependencies.size(); 4757c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int j = 0; j < numDependencies; ++j) { 4767c608f25d494c8a0a671e7373efbb47ca635367eChet Haase Dependency dependency = node.dependencies.get(j); 47717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase dependency.node.animation.addListener( 478010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase new DependencyListener(this, node, dependency.rule)); 47917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 48017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone(); 48117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 482a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase node.animation.addListener(mSetListener); 48317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 48417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // Now that all dependencies are set up, start the animations that should be started. 48521cd1389d2ef218b20994b617c57af120841a57fChet Haase if (mStartDelay <= 0) { 48621cd1389d2ef218b20994b617c57af120841a57fChet Haase for (Node node : nodesToStart) { 48721cd1389d2ef218b20994b617c57af120841a57fChet Haase node.animation.start(); 48821cd1389d2ef218b20994b617c57af120841a57fChet Haase mPlayingSet.add(node.animation); 48921cd1389d2ef218b20994b617c57af120841a57fChet Haase } 49021cd1389d2ef218b20994b617c57af120841a57fChet Haase } else { 49121cd1389d2ef218b20994b617c57af120841a57fChet Haase // TODO: Need to cancel out of the delay appropriately 492e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase mDelayAnim = ValueAnimator.ofFloat(0f, 1f); 493e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase mDelayAnim.setDuration(mStartDelay); 494e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase mDelayAnim.addListener(new AnimatorListenerAdapter() { 495e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase boolean canceled = false; 496e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase public void onAnimationCancel(Animator anim) { 497e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase canceled = true; 498e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase } 499a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationEnd(Animator anim) { 500e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase if (!canceled) { 501e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase int numNodes = nodesToStart.size(); 502e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase for (int i = 0; i < numNodes; ++i) { 503e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase Node node = nodesToStart.get(i); 504e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase node.animation.start(); 505e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase mPlayingSet.add(node.animation); 506e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase } 50721cd1389d2ef218b20994b617c57af120841a57fChet Haase } 50821cd1389d2ef218b20994b617c57af120841a57fChet Haase } 50921cd1389d2ef218b20994b617c57af120841a57fChet Haase }); 510e2ab7ccd385cdb6517955c719e1d2b49771bedb6Chet Haase mDelayAnim.start(); 51117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 51217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (mListeners != null) { 513a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase ArrayList<AnimatorListener> tmpListeners = 514a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase (ArrayList<AnimatorListener>) mListeners.clone(); 5157c608f25d494c8a0a671e7373efbb47ca635367eChet Haase int numListeners = tmpListeners.size(); 5167c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int i = 0; i < numListeners; ++i) { 5177c608f25d494c8a0a671e7373efbb47ca635367eChet Haase tmpListeners.get(i).onAnimationStart(this); 5182970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase if (mNodes.size() == 0) { 5192970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase // Handle unusual case where empty AnimatorSet is started - should send out 5202970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase // end event immediately since the event will not be sent out at all otherwise 5212970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase tmpListeners.get(i).onAnimationEnd(this); 5222970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase } 52317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 52417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 52517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 52617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 52749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase @Override 528a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public AnimatorSet clone() { 529a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase final AnimatorSet anim = (AnimatorSet) super.clone(); 53049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase /* 53149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * The basic clone() operation copies all items. This doesn't work very well for 532a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * AnimatorSet, because it will copy references that need to be recreated and state 53349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * that may not apply. What we need to do now is put the clone in an uninitialized 53449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * state, with fresh, empty data structures. Then we will build up the nodes list 53549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * manually, as we clone each Node (and its animation). The clone will then be sorted, 53649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * and will populate any appropriate lists, when it is started. 53749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase */ 53849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase anim.mNeedsSort = true; 5397dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase anim.mTerminated = false; 540a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase anim.mPlayingSet = new ArrayList<Animator>(); 541a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase anim.mNodeMap = new HashMap<Animator, Node>(); 54249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase anim.mNodes = new ArrayList<Node>(); 54349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase anim.mSortedNodes = new ArrayList<Node>(); 54449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase 54549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase // Walk through the old nodes list, cloning each node and adding it to the new nodemap. 546a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase // One problem is that the old node dependencies point to nodes in the old AnimatorSet. 54749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase // We need to track the old/new nodes in order to reconstruct the dependencies in the clone. 54849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>(); // <old, new> 54949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase for (Node node : mNodes) { 55049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase Node nodeClone = node.clone(); 55149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase nodeCloneMap.put(node, nodeClone); 55249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase anim.mNodes.add(nodeClone); 55349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase anim.mNodeMap.put(nodeClone.animation, nodeClone); 55449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase // Clear out the dependencies in the clone; we'll set these up manually later 55549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase nodeClone.dependencies = null; 55649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase nodeClone.tmpDependencies = null; 55749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase nodeClone.nodeDependents = null; 55849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase nodeClone.nodeDependencies = null; 559a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase // clear out any listeners that were set up by the AnimatorSet; these will 56049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase // be set up when the clone's nodes are sorted 561a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners(); 56249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase if (cloneListeners != null) { 563a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase ArrayList<AnimatorListener> listenersToRemove = null; 564a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase for (AnimatorListener listener : cloneListeners) { 565a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase if (listener instanceof AnimatorSetListener) { 56649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase if (listenersToRemove == null) { 567a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase listenersToRemove = new ArrayList<AnimatorListener>(); 56849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 56949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase listenersToRemove.add(listener); 57049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 57149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 57249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase if (listenersToRemove != null) { 573a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase for (AnimatorListener listener : listenersToRemove) { 57449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase cloneListeners.remove(listener); 57549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 57649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 57749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 57849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 57949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase // Now that we've cloned all of the nodes, we're ready to walk through their 58049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase // dependencies, mapping the old dependencies to the new nodes 58149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase for (Node node : mNodes) { 58249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase Node nodeClone = nodeCloneMap.get(node); 58349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase if (node.dependencies != null) { 58449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase for (Dependency dependency : node.dependencies) { 58549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase Node clonedDependencyNode = nodeCloneMap.get(dependency.node); 58649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase Dependency cloneDependency = new Dependency(clonedDependencyNode, 58749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase dependency.rule); 58849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase nodeClone.addDependency(cloneDependency); 58949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 59049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 59149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 59249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase 59349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase return anim; 59449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 59549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase 59617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 59717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * This class is the mechanism by which animations are started based on events in other 59817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * animations. If an animation has multiple dependencies on other animations, then 59917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * all dependencies must be satisfied before the animation is started. 60017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 601a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase private static class DependencyListener implements AnimatorListener { 60217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 603a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase private AnimatorSet mAnimatorSet; 604010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase 60517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // The node upon which the dependency is based. 60617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase private Node mNode; 60717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 60817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // The Dependency rule (WITH or AFTER) that the listener should wait for on 60917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // the node 61017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase private int mRule; 61117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 612a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public DependencyListener(AnimatorSet animatorSet, Node node, int rule) { 613a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase this.mAnimatorSet = animatorSet; 61417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase this.mNode = node; 61517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase this.mRule = rule; 61617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 61717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 61817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 619010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase * Ignore cancel events for now. We may want to handle this eventually, 620010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase * to prevent follow-on animations from running when some dependency 621010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase * animation is canceled. 62217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 623a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationCancel(Animator animation) { 62417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 62517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 62617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 62717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * An end event is received - see if this is an event we are listening for 62817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 629a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationEnd(Animator animation) { 63017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (mRule == Dependency.AFTER) { 63117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase startIfReady(animation); 63217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 63317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 63417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 63517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 63617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Ignore repeat events for now 63717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 638a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationRepeat(Animator animation) { 63917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 64017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 64117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 64217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * A start event is received - see if this is an event we are listening for 64317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 644a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationStart(Animator animation) { 64517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (mRule == Dependency.WITH) { 64617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase startIfReady(animation); 64717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 64817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 64917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 65017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 65117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Check whether the event received is one that the node was waiting for. 65217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * If so, mark it as complete and see whether it's time to start 65317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * the animation. 65417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param dependencyAnimation the animation that sent the event. 65517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 656a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase private void startIfReady(Animator dependencyAnimation) { 6577dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mAnimatorSet.mTerminated) { 658a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase // if the parent AnimatorSet was canceled, then don't start any dependent anims 659010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase return; 660010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase } 66117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase Dependency dependencyToRemove = null; 6627c608f25d494c8a0a671e7373efbb47ca635367eChet Haase int numDependencies = mNode.tmpDependencies.size(); 6637c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int i = 0; i < numDependencies; ++i) { 6647c608f25d494c8a0a671e7373efbb47ca635367eChet Haase Dependency dependency = mNode.tmpDependencies.get(i); 66517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (dependency.rule == mRule && 66617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase dependency.node.animation == dependencyAnimation) { 66717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // rule fired - remove the dependency and listener and check to 66817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // see whether it's time to start the animation 66917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase dependencyToRemove = dependency; 67017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase dependencyAnimation.removeListener(this); 67117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase break; 67217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 67317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 67417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNode.tmpDependencies.remove(dependencyToRemove); 67517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (mNode.tmpDependencies.size() == 0) { 67617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // all dependencies satisfied: start the animation 67717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNode.animation.start(); 678a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase mAnimatorSet.mPlayingSet.add(mNode.animation); 67917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 68017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 68117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 68217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 68317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 684a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase private class AnimatorSetListener implements AnimatorListener { 68517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 686a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase private AnimatorSet mAnimatorSet; 68717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 688a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase AnimatorSetListener(AnimatorSet animatorSet) { 689a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase mAnimatorSet = animatorSet; 69017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 69117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 692a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationCancel(Animator animation) { 6937dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (!mTerminated) { 6947dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // Listeners are already notified of the AnimatorSet canceling in cancel(). 6957dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // The logic below only kicks in when animations end normally 6967dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mPlayingSet.size() == 0) { 6977dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mListeners != null) { 6987dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase int numListeners = mListeners.size(); 6997dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase for (int i = 0; i < numListeners; ++i) { 7007dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase mListeners.get(i).onAnimationCancel(mAnimatorSet); 7017dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 70217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 70317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 70417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 70517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 70617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 70717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase @SuppressWarnings("unchecked") 708a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationEnd(Animator animation) { 70917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase animation.removeListener(this); 71017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mPlayingSet.remove(animation); 711a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase Node animNode = mAnimatorSet.mNodeMap.get(animation); 7121e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase animNode.done = true; 7137dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (!mTerminated) { 7147dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // Listeners are already notified of the AnimatorSet ending in cancel() or 7157dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // end(); the logic below only kicks in when animations end normally 7167dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes; 7177dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase boolean allDone = true; 7187dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase int numSortedNodes = sortedNodes.size(); 7197dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase for (int i = 0; i < numSortedNodes; ++i) { 7207dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (!sortedNodes.get(i).done) { 7217dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase allDone = false; 7227dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase break; 7237dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 724a6e4a1757728efc91627ece602b0899d75303659Chet Haase } 7257dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (allDone) { 7267dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // If this was the last child animation to end, then notify listeners that this 7277dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // AnimatorSet has ended 7287dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase if (mListeners != null) { 7297dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase ArrayList<AnimatorListener> tmpListeners = 7307dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase (ArrayList<AnimatorListener>) mListeners.clone(); 7317dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase int numListeners = tmpListeners.size(); 7327dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase for (int i = 0; i < numListeners; ++i) { 7337dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase tmpListeners.get(i).onAnimationEnd(mAnimatorSet); 7347dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase } 73517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 73617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 73717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 73817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 73917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 74017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // Nothing to do 741a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationRepeat(Animator animation) { 74217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 74317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 74417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // Nothing to do 745a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public void onAnimationStart(Animator animation) { 74617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 74717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 74817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 74917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 75017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 75117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * This method sorts the current set of nodes, if needed. The sort is a simple 75217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * DependencyGraph sort, which goes like this: 75317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * - All nodes without dependencies become 'roots' 75417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * - while roots list is not null 75517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * - for each root r 75617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * - add r to sorted list 75717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * - remove r as a dependency from any other node 75817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * - any nodes with no dependencies are added to the roots list 75917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 76017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase private void sortNodes() { 76117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (mNeedsSort) { 76217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mSortedNodes.clear(); 76317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase ArrayList<Node> roots = new ArrayList<Node>(); 7647c608f25d494c8a0a671e7373efbb47ca635367eChet Haase int numNodes = mNodes.size(); 7657c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int i = 0; i < numNodes; ++i) { 7667c608f25d494c8a0a671e7373efbb47ca635367eChet Haase Node node = mNodes.get(i); 76717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (node.dependencies == null || node.dependencies.size() == 0) { 76817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase roots.add(node); 76917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 77017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 77117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase ArrayList<Node> tmpRoots = new ArrayList<Node>(); 77217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase while (roots.size() > 0) { 7737c608f25d494c8a0a671e7373efbb47ca635367eChet Haase int numRoots = roots.size(); 7747c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int i = 0; i < numRoots; ++i) { 7757c608f25d494c8a0a671e7373efbb47ca635367eChet Haase Node root = roots.get(i); 77617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mSortedNodes.add(root); 77717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (root.nodeDependents != null) { 7787c608f25d494c8a0a671e7373efbb47ca635367eChet Haase int numDependents = root.nodeDependents.size(); 7797c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int j = 0; j < numDependents; ++j) { 7807c608f25d494c8a0a671e7373efbb47ca635367eChet Haase Node node = root.nodeDependents.get(j); 78117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node.nodeDependencies.remove(root); 78217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (node.nodeDependencies.size() == 0) { 78317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase tmpRoots.add(node); 78417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 78517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 78617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 78717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 788010dbaa1236cf2dcdc62c29049468e90188acaaeChet Haase roots.clear(); 78917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase roots.addAll(tmpRoots); 79017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase tmpRoots.clear(); 79117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 79217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNeedsSort = false; 79317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (mSortedNodes.size() != mNodes.size()) { 79417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase throw new IllegalStateException("Circular dependencies cannot exist" 795a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase + " in AnimatorSet"); 79617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 79717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } else { 79817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // Doesn't need sorting, but still need to add in the nodeDependencies list 79917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // because these get removed as the event listeners fire and the dependencies 80017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // are satisfied 8017c608f25d494c8a0a671e7373efbb47ca635367eChet Haase int numNodes = mNodes.size(); 8027c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int i = 0; i < numNodes; ++i) { 8037c608f25d494c8a0a671e7373efbb47ca635367eChet Haase Node node = mNodes.get(i); 80417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (node.dependencies != null && node.dependencies.size() > 0) { 8057c608f25d494c8a0a671e7373efbb47ca635367eChet Haase int numDependencies = node.dependencies.size(); 8067c608f25d494c8a0a671e7373efbb47ca635367eChet Haase for (int j = 0; j < numDependencies; ++j) { 8077c608f25d494c8a0a671e7373efbb47ca635367eChet Haase Dependency dependency = node.dependencies.get(j); 80817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (node.nodeDependencies == null) { 80917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node.nodeDependencies = new ArrayList<Node>(); 81017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 81117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (!node.nodeDependencies.contains(dependency.node)) { 81217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node.nodeDependencies.add(dependency.node); 81317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 81417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 81517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 8167dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // nodes are 'done' by default; they become un-done when started, and done 8177dfacdb1c820f955cb3cd6032ff5fbc2dd7d9df5Chet Haase // again when ended 8181e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase node.done = false; 81917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 82017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 82117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 82217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 82317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 82417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Dependency holds information about the node that some other node is 82517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * dependent upon and the nature of that dependency. 82617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 82717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 82817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase private static class Dependency { 82917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase static final int WITH = 0; // dependent node must start with this dependency node 83017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase static final int AFTER = 1; // dependent node must start when this dependency node finishes 83117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 83217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // The node that the other node with this Dependency is dependent upon 83317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public Node node; 83417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 83517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase // The nature of the dependency (WITH or AFTER) 83617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public int rule; 83717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 83817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public Dependency(Node node, int rule) { 83917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase this.node = node; 84017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase this.rule = rule; 84117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 84217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 84317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 84417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 845a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * A Node is an embodiment of both the Animator that it wraps as well as 84617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * any dependencies that are associated with that Animation. This includes 84717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * both dependencies upon other nodes (in the dependencies list) as 84817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * well as dependencies of other nodes upon this (in the nodeDependents list). 84917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 85049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase private static class Node implements Cloneable { 851a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public Animator animation; 85217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 85317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 85417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * These are the dependencies that this node's animation has on other 85517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * nodes. For example, if this node's animation should begin with some 85617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * other animation ends, then there will be an item in this node's 85717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * dependencies list for that other animation's node. 85817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 85917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public ArrayList<Dependency> dependencies = null; 86017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 86117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 86217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * tmpDependencies is a runtime detail. We use the dependencies list for sorting. 86317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * But we also use the list to keep track of when multiple dependencies are satisfied, 86417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * but removing each dependency as it is satisfied. We do not want to remove 86517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * the dependency itself from the list, because we need to retain that information 866a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * if the AnimatorSet is launched in the future. So we create a copy of the dependency 867a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * list when the AnimatorSet starts and use this tmpDependencies list to track the 86817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * list of satisfied dependencies. 86917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 87017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public ArrayList<Dependency> tmpDependencies = null; 87117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 87217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 87317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * nodeDependencies is just a list of the nodes that this Node is dependent upon. 87417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * This information is used in sortNodes(), to determine when a node is a root. 87517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 87617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public ArrayList<Node> nodeDependencies = null; 87717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 87817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 87917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * nodeDepdendents is the list of nodes that have this node as a dependency. This 88017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * is a utility field used in sortNodes to facilitate removing this node as a 88117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * dependency when it is a root node. 88217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 88317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public ArrayList<Node> nodeDependents = null; 88417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 88517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 8861e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase * Flag indicating whether the animation in this node is finished. This flag 887a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * is used by AnimatorSet to check, as each animation ends, whether all child animations 888a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * are done and it's time to send out an end event for the entire AnimatorSet. 8891e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase */ 8901e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase public boolean done = false; 8911e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase 8921e0ac5a1063d00670f4dc7ca5b120ef2836f9e8fChet Haase /** 89317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Constructs the Node with the animation that it encapsulates. A Node has no 89417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * dependencies by default; dependencies are added via the addDependency() 89517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * method. 89617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 89717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param animation The animation that the Node encapsulates. 89817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 899a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase public Node(Animator animation) { 90017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase this.animation = animation; 90117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 90217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 90317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 90417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Add a dependency to this Node. The dependency includes information about the 90517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * node that this node is dependency upon and the nature of the dependency. 90617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param dependency 90717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 90817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public void addDependency(Dependency dependency) { 90917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (dependencies == null) { 91017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase dependencies = new ArrayList<Dependency>(); 91117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase nodeDependencies = new ArrayList<Node>(); 91217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 91317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase dependencies.add(dependency); 91417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (!nodeDependencies.contains(dependency.node)) { 91517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase nodeDependencies.add(dependency.node); 91617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 91717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase Node dependencyNode = dependency.node; 91817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (dependencyNode.nodeDependents == null) { 91917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase dependencyNode.nodeDependents = new ArrayList<Node>(); 92017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 92117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase dependencyNode.nodeDependents.add(this); 92217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 92349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase 92449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase @Override 92521cd1389d2ef218b20994b617c57af120841a57fChet Haase public Node clone() { 92621cd1389d2ef218b20994b617c57af120841a57fChet Haase try { 92721cd1389d2ef218b20994b617c57af120841a57fChet Haase Node node = (Node) super.clone(); 928a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase node.animation = (Animator) animation.clone(); 92921cd1389d2ef218b20994b617c57af120841a57fChet Haase return node; 93021cd1389d2ef218b20994b617c57af120841a57fChet Haase } catch (CloneNotSupportedException e) { 93121cd1389d2ef218b20994b617c57af120841a57fChet Haase throw new AssertionError(); 93221cd1389d2ef218b20994b617c57af120841a57fChet Haase } 93349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase } 93417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 93517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 93617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 93717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * The <code>Builder</code> object is a utility class to facilitate adding animations to a 938a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <code>AnimatorSet</code> along with the relationships between the various animations. The 93917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * intention of the <code>Builder</code> methods, along with the {@link 940a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible to 94117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * express the dependency relationships of animations in a natural way. Developers can also use 942a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link 943a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need, 944a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * but it might be easier in some situations to express the AnimatorSet of animations in pairs. 94517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p/> 94617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed 947a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * internally via a call to {@link AnimatorSet#play(Animator)}.</p> 94817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p/> 949a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to 95017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * play when anim2 finishes, and anim4 to play when anim3 finishes:</p> 95117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <pre> 952a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * AnimatorSet s = new AnimatorSet(); 95317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * s.play(anim1).with(anim2); 95417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * s.play(anim2).before(anim3); 95517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * s.play(anim4).after(anim3); 95617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * </pre> 95717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p/> 958a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * <p>Note in the example that both {@link Builder#before(Animator)} and {@link 959a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * Builder#after(Animator)} are used. These are just different ways of expressing the same 96017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * relationship and are provided to make it easier to say things in a way that is more natural, 96117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * depending on the situation.</p> 96217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p/> 96317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p>It is possible to make several calls into the same <code>Builder</code> object to express 96417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * multiple relationships. However, note that it is only the animation passed into the initial 965a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive 96617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * calls to the <code>Builder</code> object. For example, the following code starts both anim2 96717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and 96817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * anim3: 96917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <pre> 970a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * AnimatorSet s = new AnimatorSet(); 97117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * s.play(anim1).before(anim2).before(anim3); 97217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * </pre> 97317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * If the desired result is to play anim1 then anim2 then anim3, this code expresses the 97417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * relationship correctly:</p> 97517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <pre> 976a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * AnimatorSet s = new AnimatorSet(); 97717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * s.play(anim1).before(anim2); 97817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * s.play(anim2).before(anim3); 97917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * </pre> 98017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p/> 98117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * <p>Note that it is possible to express relationships that cannot be resolved and will not 98217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no 98317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * sense. In general, circular dependencies like this one (or more indirect ones where a depends 984a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets 985a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * that can boil down to a simple, one-way relationship of animations starting with, before, and 98617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * after other, different, animations.</p> 98717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 98817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase public class Builder { 98917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 99017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 99117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * This tracks the current node being processed. It is supplied to the play() method 992a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * of AnimatorSet and passed into the constructor of Builder. 99317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 99417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase private Node mCurrentNode; 99517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 99617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 997a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * package-private constructor. Builders are only constructed by AnimatorSet, when the 99817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * play() method is called. 99917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 100017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param anim The animation that is the dependency for the other animations passed into 100117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * the other methods of this Builder object. 100217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 1003a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase Builder(Animator anim) { 100417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mCurrentNode = mNodeMap.get(anim); 100517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (mCurrentNode == null) { 100617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mCurrentNode = new Node(anim); 100717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNodeMap.put(anim, mCurrentNode); 100817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNodes.add(mCurrentNode); 100917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 101017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 101117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 101217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 101317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Sets up the given animation to play at the same time as the animation supplied in the 1014a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object. 101517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 101617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param anim The animation that will play when the animation supplied to the 1017a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#play(Animator)} method starts. 101817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 10192970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase public Builder with(Animator anim) { 102017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase Node node = mNodeMap.get(anim); 102117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (node == null) { 102217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node = new Node(anim); 102317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNodeMap.put(anim, node); 102417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNodes.add(node); 102517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 102617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH); 102717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node.addDependency(dependency); 10282970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase return this; 102917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 103017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 103117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 103217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Sets up the given animation to play when the animation supplied in the 1033a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object 103417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * ends. 103517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 103617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param anim The animation that will play when the animation supplied to the 1037a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#play(Animator)} method ends. 103817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 10392970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase public Builder before(Animator anim) { 104017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase Node node = mNodeMap.get(anim); 104117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (node == null) { 104217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node = new Node(anim); 104317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNodeMap.put(anim, node); 104417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNodes.add(node); 104517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 104617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER); 104717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node.addDependency(dependency); 10482970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase return this; 104917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 105017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 105117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 105217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Sets up the given animation to play when the animation supplied in the 1053a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object 105417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * to start when the animation supplied in this method call ends. 105517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 105617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param anim The animation whose end will cause the animation supplied to the 1057a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#play(Animator)} method to play. 105817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 10592970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase public Builder after(Animator anim) { 106017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase Node node = mNodeMap.get(anim); 106117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase if (node == null) { 106217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase node = new Node(anim); 106317fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNodeMap.put(anim, node); 106417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mNodes.add(node); 106517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 106617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase Dependency dependency = new Dependency(node, Dependency.AFTER); 106717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase mCurrentNode.addDependency(dependency); 10682970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase return this; 106917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 107017fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 107117fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase /** 107217fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * Sets up the animation supplied in the 1073a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object 107417fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * to play when the given amount of time elapses. 107517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * 107617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * @param delay The number of milliseconds that should elapse before the 107717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase * animation starts. 107817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase */ 10792970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase public Builder after(long delay) { 1080a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase // setup dummy ValueAnimator just to run the clock 10812794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); 10822794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase anim.setDuration(delay); 10832794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase after(anim); 10842970c499388b4dcd1232cd622a9b80b395eeb2b4Chet Haase return this; 108517fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 108617fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 108717fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase } 108817fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase 108917fb4b0d1cfbad1f026fec704c86640f070b4c2fChet Haase} 1090