121cd1389d2ef218b20994b617c57af120841a57fChet Haase/*
221cd1389d2ef218b20994b617c57af120841a57fChet Haase * Copyright (C) 2010 The Android Open Source Project
321cd1389d2ef218b20994b617c57af120841a57fChet Haase *
421cd1389d2ef218b20994b617c57af120841a57fChet Haase * Licensed under the Apache License, Version 2.0 (the "License");
521cd1389d2ef218b20994b617c57af120841a57fChet Haase * you may not use this file except in compliance with the License.
621cd1389d2ef218b20994b617c57af120841a57fChet Haase * You may obtain a copy of the License at
721cd1389d2ef218b20994b617c57af120841a57fChet Haase *
821cd1389d2ef218b20994b617c57af120841a57fChet Haase *      http://www.apache.org/licenses/LICENSE-2.0
921cd1389d2ef218b20994b617c57af120841a57fChet Haase *
1021cd1389d2ef218b20994b617c57af120841a57fChet Haase * Unless required by applicable law or agreed to in writing, software
1121cd1389d2ef218b20994b617c57af120841a57fChet Haase * distributed under the License is distributed on an "AS IS" BASIS,
1221cd1389d2ef218b20994b617c57af120841a57fChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1321cd1389d2ef218b20994b617c57af120841a57fChet Haase * See the License for the specific language governing permissions and
1421cd1389d2ef218b20994b617c57af120841a57fChet Haase * limitations under the License.
1521cd1389d2ef218b20994b617c57af120841a57fChet Haase */
1621cd1389d2ef218b20994b617c57af120841a57fChet Haase
1721cd1389d2ef218b20994b617c57af120841a57fChet Haasepackage android.animation;
1821cd1389d2ef218b20994b617c57af120841a57fChet Haase
1921cd1389d2ef218b20994b617c57af120841a57fChet Haaseimport android.view.View;
2021cd1389d2ef218b20994b617c57af120841a57fChet Haaseimport android.view.ViewGroup;
21cca2c9807206f320bd41bf8656a227e4f249e4baChet Haaseimport android.view.ViewParent;
2221cd1389d2ef218b20994b617c57af120841a57fChet Haaseimport android.view.ViewTreeObserver;
2321cd1389d2ef218b20994b617c57af120841a57fChet Haaseimport android.view.animation.AccelerateDecelerateInterpolator;
2421cd1389d2ef218b20994b617c57af120841a57fChet Haaseimport android.view.animation.DecelerateInterpolator;
2521cd1389d2ef218b20994b617c57af120841a57fChet Haase
2621cd1389d2ef218b20994b617c57af120841a57fChet Haaseimport java.util.ArrayList;
271a76dcd6d1e30f92668b5df309398d545cef9aceChet Haaseimport java.util.Collection;
2821cd1389d2ef218b20994b617c57af120841a57fChet Haaseimport java.util.HashMap;
29eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haaseimport java.util.LinkedHashMap;
3021cd1389d2ef218b20994b617c57af120841a57fChet Haaseimport java.util.List;
3121cd1389d2ef218b20994b617c57af120841a57fChet Haase
3221cd1389d2ef218b20994b617c57af120841a57fChet Haase/**
3321cd1389d2ef218b20994b617c57af120841a57fChet Haase * This class enables automatic animations on layout changes in ViewGroup objects. To enable
3421cd1389d2ef218b20994b617c57af120841a57fChet Haase * transitions for a layout container, create a LayoutTransition object and set it on any
3521cd1389d2ef218b20994b617c57af120841a57fChet Haase * ViewGroup by calling {@link ViewGroup#setLayoutTransition(LayoutTransition)}. This will cause
3621cd1389d2ef218b20994b617c57af120841a57fChet Haase * default animations to run whenever items are added to or removed from that container. To specify
37a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * custom animations, use the {@link LayoutTransition#setAnimator(int, Animator)
38a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * setAnimator()} method.
3921cd1389d2ef218b20994b617c57af120841a57fChet Haase *
40daf98e941e140e8739458126640183b9f296a2abChet Haase * <p>One of the core concepts of these transition animations is that there are two types of
4121cd1389d2ef218b20994b617c57af120841a57fChet Haase * changes that cause the transition and four different animations that run because of
4221cd1389d2ef218b20994b617c57af120841a57fChet Haase * those changes. The changes that trigger the transition are items being added to a container
4321cd1389d2ef218b20994b617c57af120841a57fChet Haase * (referred to as an "appearing" transition) or removed from a container (also known as
44daf98e941e140e8739458126640183b9f296a2abChet Haase * "disappearing"). Setting the visibility of views (between GONE and VISIBLE) will trigger
45daf98e941e140e8739458126640183b9f296a2abChet Haase * the same add/remove logic. The animations that run due to those events are one that animates
4621cd1389d2ef218b20994b617c57af120841a57fChet Haase * items being added, one that animates items being removed, and two that animate the other
4721cd1389d2ef218b20994b617c57af120841a57fChet Haase * items in the container that change due to the add/remove occurrence. Users of
4821cd1389d2ef218b20994b617c57af120841a57fChet Haase * the transition may want different animations for the changing items depending on whether
49daf98e941e140e8739458126640183b9f296a2abChet Haase * they are changing due to an appearing or disappearing event, so there is one animation for
5021cd1389d2ef218b20994b617c57af120841a57fChet Haase * each of these variations of the changing event. Most of the API of this class is concerned
5121cd1389d2ef218b20994b617c57af120841a57fChet Haase * with setting up the basic properties of the animations used in these four situations,
5221cd1389d2ef218b20994b617c57af120841a57fChet Haase * or with setting up custom animations for any or all of the four.</p>
5321cd1389d2ef218b20994b617c57af120841a57fChet Haase *
54c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * <p>By default, the DISAPPEARING animation begins immediately, as does the CHANGE_APPEARING
55c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * animation. The other animations begin after a delay that is set to the default duration
56c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * of the animations. This behavior facilitates a sequence of animations in transitions as
57c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * follows: when an item is being added to a layout, the other children of that container will
58c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * move first (thus creating space for the new item), then the appearing animation will run to
59c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * animate the item being added. Conversely, when an item is removed from a container, the
60c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * animation to remove it will run first, then the animations of the other children in the
61c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * layout will run (closing the gap created in the layout when the item was removed). If this
62c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * default choreography behavior is not desired, the {@link #setDuration(int, long)} and
63c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * {@link #setStartDelay(int, long)} of any or all of the animations can be changed as
64c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase * appropriate.</p>
65c54ed966f78b9ee8117931859d62faa6f11fe018Chet Haase *
6621cd1389d2ef218b20994b617c57af120841a57fChet Haase * <p>The animations specified for the transition, both the defaults and any custom animations
6721cd1389d2ef218b20994b617c57af120841a57fChet Haase * set on the transition object, are templates only. That is, these animations exist to hold the
6821cd1389d2ef218b20994b617c57af120841a57fChet Haase * basic animation properties, such as the duration, start delay, and properties being animated.
6921cd1389d2ef218b20994b617c57af120841a57fChet Haase * But the actual target object, as well as the start and end values for those properties, are
7021cd1389d2ef218b20994b617c57af120841a57fChet Haase * set automatically in the process of setting up the transition each time it runs. Each of the
7121cd1389d2ef218b20994b617c57af120841a57fChet Haase * animations is cloned from the original copy and the clone is then populated with the dynamic
7221cd1389d2ef218b20994b617c57af120841a57fChet Haase * values of the target being animated (such as one of the items in a layout container that is
7321cd1389d2ef218b20994b617c57af120841a57fChet Haase * moving as a result of the layout event) as well as the values that are changing (such as the
7421cd1389d2ef218b20994b617c57af120841a57fChet Haase * position and size of that object). The actual values that are pushed to each animation
7521cd1389d2ef218b20994b617c57af120841a57fChet Haase * depends on what properties are specified for the animation. For example, the default
76cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase * CHANGE_APPEARING animation animates the <code>left</code>, <code>top</code>, <code>right</code>,
77cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase * <code>bottom</code>, <code>scrollX</code>, and <code>scrollY</code> properties.
78cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase * Values for these properties are updated with the pre- and post-layout
7921cd1389d2ef218b20994b617c57af120841a57fChet Haase * values when the transition begins. Custom animations will be similarly populated with
80a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase * the target and values being animated, assuming they use ObjectAnimator objects with
8121cd1389d2ef218b20994b617c57af120841a57fChet Haase * property names that are known on the target object.</p>
82daf98e941e140e8739458126640183b9f296a2abChet Haase *
83daf98e941e140e8739458126640183b9f296a2abChet Haase * <p>This class, and the associated XML flag for containers, animateLayoutChanges="true",
84daf98e941e140e8739458126640183b9f296a2abChet Haase * provides a simple utility meant for automating changes in straightforward situations.
85daf98e941e140e8739458126640183b9f296a2abChet Haase * Using LayoutTransition at multiple levels of a nested view hierarchy may not work due to the
86daf98e941e140e8739458126640183b9f296a2abChet Haase * interrelationship of the various levels of layout. Also, a container that is being scrolled
87daf98e941e140e8739458126640183b9f296a2abChet Haase * at the same time as items are being added or removed is probably not a good candidate for
88daf98e941e140e8739458126640183b9f296a2abChet Haase * this utility, because the before/after locations calculated by LayoutTransition
89daf98e941e140e8739458126640183b9f296a2abChet Haase * may not match the actual locations when the animations finish due to the container
90daf98e941e140e8739458126640183b9f296a2abChet Haase * being scrolled as the animations are running. You can work around that
91daf98e941e140e8739458126640183b9f296a2abChet Haase * particular issue by disabling the 'changing' animations by setting the CHANGE_APPEARING
92daf98e941e140e8739458126640183b9f296a2abChet Haase * and CHANGE_DISAPPEARING animations to null, and setting the startDelay of the
93daf98e941e140e8739458126640183b9f296a2abChet Haase * other animations appropriately.</p>
9421cd1389d2ef218b20994b617c57af120841a57fChet Haase */
9521cd1389d2ef218b20994b617c57af120841a57fChet Haasepublic class LayoutTransition {
9621cd1389d2ef218b20994b617c57af120841a57fChet Haase
9721cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
9821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * A flag indicating the animation that runs on those items that are changing
9921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * due to a new item appearing in the container.
10021cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
10121cd1389d2ef218b20994b617c57af120841a57fChet Haase    public static final int CHANGE_APPEARING = 0;
10221cd1389d2ef218b20994b617c57af120841a57fChet Haase
10321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
10421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * A flag indicating the animation that runs on those items that are changing
1059e90a9953b65ae575ec8db3989857e0c145724b1Chet Haase     * due to an item disappearing from the container.
10621cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
10721cd1389d2ef218b20994b617c57af120841a57fChet Haase    public static final int CHANGE_DISAPPEARING = 1;
10821cd1389d2ef218b20994b617c57af120841a57fChet Haase
10921cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
1109e90a9953b65ae575ec8db3989857e0c145724b1Chet Haase     * A flag indicating the animation that runs on those items that are appearing
1119e90a9953b65ae575ec8db3989857e0c145724b1Chet Haase     * in the container.
11221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
11321cd1389d2ef218b20994b617c57af120841a57fChet Haase    public static final int APPEARING = 2;
11421cd1389d2ef218b20994b617c57af120841a57fChet Haase
11521cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
1169e90a9953b65ae575ec8db3989857e0c145724b1Chet Haase     * A flag indicating the animation that runs on those items that are disappearing
1179e90a9953b65ae575ec8db3989857e0c145724b1Chet Haase     * from the container.
11821cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
11921cd1389d2ef218b20994b617c57af120841a57fChet Haase    public static final int DISAPPEARING = 3;
12021cd1389d2ef218b20994b617c57af120841a57fChet Haase
12121cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
1227dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * A flag indicating the animation that runs on those items that are changing
1237dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * due to a layout change not caused by items being added to or removed
1247dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * from the container. This transition type is not enabled by default; it can be
1257dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * enabled via {@link #enableTransitionType(int)}.
1267dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     */
1277dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    public static final int CHANGING = 4;
1287dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase
1297dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    /**
1307dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * Private bit fields used to set the collection of enabled transition types for
1317dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * mTransitionTypes.
1327dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     */
1337dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private static final int FLAG_APPEARING             = 0x01;
1347dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private static final int FLAG_DISAPPEARING          = 0x02;
1357dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private static final int FLAG_CHANGE_APPEARING      = 0x04;
1367dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private static final int FLAG_CHANGE_DISAPPEARING   = 0x08;
1377dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private static final int FLAG_CHANGING              = 0x10;
1387dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase
1397dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    /**
14021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * These variables hold the animations that are currently used to run the transition effects.
14121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * These animations are set to defaults, but can be changed to custom animations by
142a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * calls to setAnimator().
14321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
144a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private Animator mDisappearingAnim = null;
145a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private Animator mAppearingAnim = null;
146a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private Animator mChangingAppearingAnim = null;
147a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private Animator mChangingDisappearingAnim = null;
1487dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private Animator mChangingAnim = null;
14921cd1389d2ef218b20994b617c57af120841a57fChet Haase
15021cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
15121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * These are the default animations, defined in the constructor, that will be used
15221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * unless the user specifies custom animations.
15321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
1547dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private static ObjectAnimator defaultChange;
155a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private static ObjectAnimator defaultChangeIn;
156a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private static ObjectAnimator defaultChangeOut;
157a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private static ObjectAnimator defaultFadeIn;
158a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    private static ObjectAnimator defaultFadeOut;
15921cd1389d2ef218b20994b617c57af120841a57fChet Haase
16021cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
16121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The default duration used by all animations.
16221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
16321cd1389d2ef218b20994b617c57af120841a57fChet Haase    private static long DEFAULT_DURATION = 300;
16421cd1389d2ef218b20994b617c57af120841a57fChet Haase
16521cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
1667dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * The durations of the different animations
16721cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
16821cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mChangingAppearingDuration = DEFAULT_DURATION;
16921cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mChangingDisappearingDuration = DEFAULT_DURATION;
1707dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private long mChangingDuration = DEFAULT_DURATION;
17121cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mAppearingDuration = DEFAULT_DURATION;
17221cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mDisappearingDuration = DEFAULT_DURATION;
17321cd1389d2ef218b20994b617c57af120841a57fChet Haase
17421cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
1757dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * The start delays of the different animations. Note that the default behavior of
17621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * the appearing item is the default duration, since it should wait for the items to move
17721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * before fading it. Same for the changing animation when disappearing; it waits for the item
17821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * to fade out before moving the other items.
17921cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
18021cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mAppearingDelay = DEFAULT_DURATION;
18121cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mDisappearingDelay = 0;
18221cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mChangingAppearingDelay = 0;
18321cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mChangingDisappearingDelay = DEFAULT_DURATION;
1847dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private long mChangingDelay = 0;
18521cd1389d2ef218b20994b617c57af120841a57fChet Haase
18621cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
1877dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * The inter-animation delays used on the changing animations
18821cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
18921cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mChangingAppearingStagger = 0;
19021cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long mChangingDisappearingStagger = 0;
1917dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private long mChangingStagger = 0;
19221cd1389d2ef218b20994b617c57af120841a57fChet Haase
19321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
19433d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase     * Static interpolators - these are stateless and can be shared across the instances
19533d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase     */
19633d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private static TimeInterpolator ACCEL_DECEL_INTERPOLATOR =
19733d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase            new AccelerateDecelerateInterpolator();
19833d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private static TimeInterpolator DECEL_INTERPOLATOR = new DecelerateInterpolator();
19933d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private static TimeInterpolator sAppearingInterpolator = ACCEL_DECEL_INTERPOLATOR;
20033d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private static TimeInterpolator sDisappearingInterpolator = ACCEL_DECEL_INTERPOLATOR;
20133d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private static TimeInterpolator sChangingAppearingInterpolator = DECEL_INTERPOLATOR;
20233d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private static TimeInterpolator sChangingDisappearingInterpolator = DECEL_INTERPOLATOR;
20333d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private static TimeInterpolator sChangingInterpolator = DECEL_INTERPOLATOR;
20433d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase
20533d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    /**
20621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The default interpolators used for the animations
20721cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
20833d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private TimeInterpolator mAppearingInterpolator = sAppearingInterpolator;
20933d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private TimeInterpolator mDisappearingInterpolator = sDisappearingInterpolator;
21033d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private TimeInterpolator mChangingAppearingInterpolator = sChangingAppearingInterpolator;
21133d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private TimeInterpolator mChangingDisappearingInterpolator = sChangingDisappearingInterpolator;
21233d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase    private TimeInterpolator mChangingInterpolator = sChangingInterpolator;
21321cd1389d2ef218b20994b617c57af120841a57fChet Haase
21421cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
215e64ea87f966e995f5e1a77f991b9da0ed21ffab0Chet Haase     * These hashmaps are used to store the animations that are currently running as part of
21621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * the transition. The reason for this is that a further layout event should cause
21721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * existing animations to stop where they are prior to starting new animations. So
21821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * we cache all of the current animations in this map for possible cancellation on
219eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase     * another layout event. LinkedHashMaps are used to preserve the order in which animations
220eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase     * are inserted, so that we process events (such as setting up start values) in the same order.
22121cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
222eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase    private final HashMap<View, Animator> pendingAnimations =
223cbda9104d029a8420786bd17725e8b1fb0c4c188Ben Komalo            new HashMap<View, Animator>();
224eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase    private final LinkedHashMap<View, Animator> currentChangingAnimations =
225eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase            new LinkedHashMap<View, Animator>();
226eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase    private final LinkedHashMap<View, Animator> currentAppearingAnimations =
227eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase            new LinkedHashMap<View, Animator>();
228eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase    private final LinkedHashMap<View, Animator> currentDisappearingAnimations =
229eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase            new LinkedHashMap<View, Animator>();
23021cd1389d2ef218b20994b617c57af120841a57fChet Haase
23121cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
23221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * This hashmap is used to track the listeners that have been added to the children of
23321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * a container. When a layout change occurs, an animation is created for each View, so that
23421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * the pre-layout values can be cached in that animation. Then a listener is added to the
23521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * view to see whether the layout changes the bounds of that view. If so, the animation
23621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * is set with the final values and then run. If not, the animation is not started. When
23721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * the process of setting up and running all appropriate animations is done, we need to
23821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * remove these listeners and clear out the map.
23921cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
240cbda9104d029a8420786bd17725e8b1fb0c4c188Ben Komalo    private final HashMap<View, View.OnLayoutChangeListener> layoutChangeListenerMap =
24121cd1389d2ef218b20994b617c57af120841a57fChet Haase            new HashMap<View, View.OnLayoutChangeListener>();
24221cd1389d2ef218b20994b617c57af120841a57fChet Haase
24321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
24421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Used to track the current delay being assigned to successive animations as they are
24521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * started. This value is incremented for each new animation, then zeroed before the next
24621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * transition begins.
24721cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
24821cd1389d2ef218b20994b617c57af120841a57fChet Haase    private long staggerDelay;
24921cd1389d2ef218b20994b617c57af120841a57fChet Haase
25021cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
2517dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * These are the types of transition animations that the LayoutTransition is reacting
2527dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * to. By default, appearing/disappearing and the change animations related to them are
2537dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * enabled (not CHANGING).
2547dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     */
2557dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    private int mTransitionTypes = FLAG_CHANGE_APPEARING | FLAG_CHANGE_DISAPPEARING |
2567dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            FLAG_APPEARING | FLAG_DISAPPEARING;
2577dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    /**
25821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * The set of listeners that should be notified when APPEARING/DISAPPEARING transitions
25921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * start and end.
26021cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
26121cd1389d2ef218b20994b617c57af120841a57fChet Haase    private ArrayList<TransitionListener> mListeners;
26221cd1389d2ef218b20994b617c57af120841a57fChet Haase
263cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    /**
264cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * Controls whether changing animations automatically animate the parent hierarchy as well.
265cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * This behavior prevents artifacts when wrap_content layouts snap to the end state as the
266cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * transition begins, causing visual glitches and clipping.
267cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * Default value is true.
268cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     */
269cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    private boolean mAnimateParentHierarchy = true;
270cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
27121cd1389d2ef218b20994b617c57af120841a57fChet Haase
27221cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
27321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Constructs a LayoutTransition object. By default, the object will listen to layout
27421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * events on any ViewGroup that it is set on and will run default animations for each
27521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * type of layout event.
27621cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
27721cd1389d2ef218b20994b617c57af120841a57fChet Haase    public LayoutTransition() {
27821cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (defaultChangeIn == null) {
27921cd1389d2ef218b20994b617c57af120841a57fChet Haase            // "left" is just a placeholder; we'll put real properties/values in when needed
2802794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);
2812794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
2822794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 1);
2832794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 1);
284cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            PropertyValuesHolder pvhScrollX = PropertyValuesHolder.ofInt("scrollX", 0, 1);
285cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            PropertyValuesHolder pvhScrollY = PropertyValuesHolder.ofInt("scrollY", 0, 1);
286622e05c4d2f7c7542ab9cdd30c31813cb6cdb103Chet Haase            defaultChangeIn = ObjectAnimator.ofPropertyValuesHolder((Object)null,
287cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScrollX, pvhScrollY);
2882794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            defaultChangeIn.setDuration(DEFAULT_DURATION);
28921cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultChangeIn.setStartDelay(mChangingAppearingDelay);
29021cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultChangeIn.setInterpolator(mChangingAppearingInterpolator);
29121cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultChangeOut = defaultChangeIn.clone();
29221cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultChangeOut.setStartDelay(mChangingDisappearingDelay);
29321cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultChangeOut.setInterpolator(mChangingDisappearingInterpolator);
2947dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            defaultChange = defaultChangeIn.clone();
2957dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            defaultChange.setStartDelay(mChangingDelay);
2967dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            defaultChange.setInterpolator(mChangingInterpolator);
297cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
298622e05c4d2f7c7542ab9cdd30c31813cb6cdb103Chet Haase            defaultFadeIn = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
2992794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            defaultFadeIn.setDuration(DEFAULT_DURATION);
30021cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultFadeIn.setStartDelay(mAppearingDelay);
30121cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultFadeIn.setInterpolator(mAppearingInterpolator);
302622e05c4d2f7c7542ab9cdd30c31813cb6cdb103Chet Haase            defaultFadeOut = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
3032794eb3b02e2404d453d3ad22a8a85a138130a07Chet Haase            defaultFadeOut.setDuration(DEFAULT_DURATION);
30421cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultFadeOut.setStartDelay(mDisappearingDelay);
30521cd1389d2ef218b20994b617c57af120841a57fChet Haase            defaultFadeOut.setInterpolator(mDisappearingInterpolator);
30621cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
30721cd1389d2ef218b20994b617c57af120841a57fChet Haase        mChangingAppearingAnim = defaultChangeIn;
30821cd1389d2ef218b20994b617c57af120841a57fChet Haase        mChangingDisappearingAnim = defaultChangeOut;
3097dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        mChangingAnim = defaultChange;
31021cd1389d2ef218b20994b617c57af120841a57fChet Haase        mAppearingAnim = defaultFadeIn;
31121cd1389d2ef218b20994b617c57af120841a57fChet Haase        mDisappearingAnim = defaultFadeOut;
31221cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
31321cd1389d2ef218b20994b617c57af120841a57fChet Haase
31421cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
31521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Sets the duration to be used by all animations of this transition object. If you want to
31621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * set the duration of just one of the animations in particular, use the
31721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * {@link #setDuration(int, long)} method.
31821cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
31921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param duration The length of time, in milliseconds, that the transition animations
32021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * should last.
32121cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
32221cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void setDuration(long duration) {
32321cd1389d2ef218b20994b617c57af120841a57fChet Haase        mChangingAppearingDuration = duration;
32421cd1389d2ef218b20994b617c57af120841a57fChet Haase        mChangingDisappearingDuration = duration;
3257dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        mChangingDuration = duration;
32621cd1389d2ef218b20994b617c57af120841a57fChet Haase        mAppearingDuration = duration;
32721cd1389d2ef218b20994b617c57af120841a57fChet Haase        mDisappearingDuration = duration;
32821cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
32921cd1389d2ef218b20994b617c57af120841a57fChet Haase
33021cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
3317dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * Enables the specified transitionType for this LayoutTransition object.
3327dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * By default, a LayoutTransition listens for changes in children being
3337dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * added/remove/hidden/shown in the container, and runs the animations associated with
3347dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * those events. That is, all transition types besides {@link #CHANGING} are enabled by default.
3357dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * You can also enable {@link #CHANGING} animations by calling this method with the
3367dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING} transitionType.
3377dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     *
3387dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
3397dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
3407dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     */
3417dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    public void enableTransitionType(int transitionType) {
3427dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        switch (transitionType) {
3437dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case APPEARING:
3447dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes |= FLAG_APPEARING;
3457dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3467dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case DISAPPEARING:
3477dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes |= FLAG_DISAPPEARING;
3487dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3497dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGE_APPEARING:
3507dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes |= FLAG_CHANGE_APPEARING;
3517dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3527dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGE_DISAPPEARING:
3537dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes |= FLAG_CHANGE_DISAPPEARING;
3547dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3557dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
3567dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes |= FLAG_CHANGING;
3577dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3587dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
3597dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    }
3607dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase
3617dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    /**
3627dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * Disables the specified transitionType for this LayoutTransition object.
3637dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * By default, all transition types except {@link #CHANGING} are enabled.
3647dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     *
3657dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
3667dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
3677dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     */
3687dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    public void disableTransitionType(int transitionType) {
3697dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        switch (transitionType) {
3707dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case APPEARING:
3717dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes &= ~FLAG_APPEARING;
3727dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3737dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case DISAPPEARING:
3747dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes &= ~FLAG_DISAPPEARING;
3757dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3767dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGE_APPEARING:
3777dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes &= ~FLAG_CHANGE_APPEARING;
3787dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3797dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGE_DISAPPEARING:
3807dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes &= ~FLAG_CHANGE_DISAPPEARING;
3817dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3827dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
3837dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mTransitionTypes &= ~FLAG_CHANGING;
3847dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
3857dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
3867dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    }
3877dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase
3887dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    /**
3897dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * Returns whether the specified transitionType is enabled for this LayoutTransition object.
3907dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * By default, all transition types except {@link #CHANGING} are enabled.
3917dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     *
3927dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
3937dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
3947dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @return true if the specified transitionType is currently enabled, false otherwise.
3957dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     */
3967dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    public boolean isTransitionTypeEnabled(int transitionType) {
3977dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        switch (transitionType) {
3987dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case APPEARING:
3997dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING;
4007dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case DISAPPEARING:
4017dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING;
4027dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGE_APPEARING:
4037dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING;
4047dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGE_DISAPPEARING:
4057dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING;
4067dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
4077dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return (mTransitionTypes & FLAG_CHANGING) == FLAG_CHANGING;
4087dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
4097dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        return false;
4107dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    }
4117dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase
4127dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    /**
41321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Sets the start delay on one of the animation objects used by this transition. The
41421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * <code>transitionType</code> parameter determines the animation whose start delay
41521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * is being set.
41621cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
4177dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
4187dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
4197dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * the animation whose start delay is being set.
42021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param delay The length of time, in milliseconds, to delay before starting the animation.
421a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @see Animator#setStartDelay(long)
42221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
42321cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void setStartDelay(int transitionType, long delay) {
42421cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
42521cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
42621cd1389d2ef218b20994b617c57af120841a57fChet Haase                mChangingAppearingDelay = delay;
42721cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
42821cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
42921cd1389d2ef218b20994b617c57af120841a57fChet Haase                mChangingDisappearingDelay = delay;
43021cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
4317dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
4327dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mChangingDelay = delay;
4337dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
43421cd1389d2ef218b20994b617c57af120841a57fChet Haase            case APPEARING:
43521cd1389d2ef218b20994b617c57af120841a57fChet Haase                mAppearingDelay = delay;
43621cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
43721cd1389d2ef218b20994b617c57af120841a57fChet Haase            case DISAPPEARING:
43821cd1389d2ef218b20994b617c57af120841a57fChet Haase                mDisappearingDelay = delay;
43921cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
44021cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
44121cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
44221cd1389d2ef218b20994b617c57af120841a57fChet Haase
44321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
44421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Gets the start delay on one of the animation objects used by this transition. The
44521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * <code>transitionType</code> parameter determines the animation whose start delay
44621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * is returned.
44721cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
4487dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
4497dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
4507dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * the animation whose start delay is returned.
45121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return long The start delay of the specified animation.
452a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @see Animator#getStartDelay()
45321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
45421cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getStartDelay(int transitionType) {
45521cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
45621cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
457cf06d7390cf35aec4f54b705ba4dfdb96fb1c01aRajdeep Dua                return mChangingAppearingDelay;
45821cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
459cf06d7390cf35aec4f54b705ba4dfdb96fb1c01aRajdeep Dua                return mChangingDisappearingDelay;
4607dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
4617dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return mChangingDelay;
46221cd1389d2ef218b20994b617c57af120841a57fChet Haase            case APPEARING:
463cf06d7390cf35aec4f54b705ba4dfdb96fb1c01aRajdeep Dua                return mAppearingDelay;
46421cd1389d2ef218b20994b617c57af120841a57fChet Haase            case DISAPPEARING:
465cf06d7390cf35aec4f54b705ba4dfdb96fb1c01aRajdeep Dua                return mDisappearingDelay;
46621cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
46721cd1389d2ef218b20994b617c57af120841a57fChet Haase        // shouldn't reach here
46821cd1389d2ef218b20994b617c57af120841a57fChet Haase        return 0;
46921cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
47021cd1389d2ef218b20994b617c57af120841a57fChet Haase
47121cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
47221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Sets the duration on one of the animation objects used by this transition. The
47321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * <code>transitionType</code> parameter determines the animation whose duration
47421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * is being set.
47521cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
4767dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
4777dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
4787dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * the animation whose duration is being set.
47921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param duration The length of time, in milliseconds, that the specified animation should run.
480a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @see Animator#setDuration(long)
48121cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
48221cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void setDuration(int transitionType, long duration) {
48321cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
48421cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
48521cd1389d2ef218b20994b617c57af120841a57fChet Haase                mChangingAppearingDuration = duration;
48621cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
48721cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
48821cd1389d2ef218b20994b617c57af120841a57fChet Haase                mChangingDisappearingDuration = duration;
48921cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
4907dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
4917dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mChangingDuration = duration;
4927dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
49321cd1389d2ef218b20994b617c57af120841a57fChet Haase            case APPEARING:
49421cd1389d2ef218b20994b617c57af120841a57fChet Haase                mAppearingDuration = duration;
49521cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
49621cd1389d2ef218b20994b617c57af120841a57fChet Haase            case DISAPPEARING:
49721cd1389d2ef218b20994b617c57af120841a57fChet Haase                mDisappearingDuration = duration;
49821cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
49921cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
50021cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
50121cd1389d2ef218b20994b617c57af120841a57fChet Haase
50221cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
50321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Gets the duration on one of the animation objects used by this transition. The
50421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * <code>transitionType</code> parameter determines the animation whose duration
50521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * is returned.
50621cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
5077dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
5087dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
5097dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * the animation whose duration is returned.
51021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return long The duration of the specified animation.
511a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @see Animator#getDuration()
51221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
51321cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getDuration(int transitionType) {
51421cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
51521cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
51621cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mChangingAppearingDuration;
51721cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
51821cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mChangingDisappearingDuration;
5197dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
5207dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return mChangingDuration;
52121cd1389d2ef218b20994b617c57af120841a57fChet Haase            case APPEARING:
52221cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mAppearingDuration;
52321cd1389d2ef218b20994b617c57af120841a57fChet Haase            case DISAPPEARING:
52421cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mDisappearingDuration;
52521cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
52621cd1389d2ef218b20994b617c57af120841a57fChet Haase        // shouldn't reach here
52721cd1389d2ef218b20994b617c57af120841a57fChet Haase        return 0;
52821cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
52921cd1389d2ef218b20994b617c57af120841a57fChet Haase
53021cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
53121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Sets the length of time to delay between starting each animation during one of the
5327dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * change animations.
53321cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
5347dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType A value of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING}, or
5357dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}.
53621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param duration The length of time, in milliseconds, to delay before launching the next
53721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * animation in the sequence.
53821cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
53921cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void setStagger(int transitionType, long duration) {
54021cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
54121cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
54221cd1389d2ef218b20994b617c57af120841a57fChet Haase                mChangingAppearingStagger = duration;
54321cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
54421cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
54521cd1389d2ef218b20994b617c57af120841a57fChet Haase                mChangingDisappearingStagger = duration;
54621cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
5477dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
5487dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mChangingStagger = duration;
5497dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
55021cd1389d2ef218b20994b617c57af120841a57fChet Haase            // noop other cases
55121cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
55221cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
55321cd1389d2ef218b20994b617c57af120841a57fChet Haase
55421cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
5557dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * Gets the length of time to delay between starting each animation during one of the
5567dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * change animations.
55721cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
5587dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType A value of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING}, or
5597dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}.
56021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return long The length of time, in milliseconds, to delay before launching the next
56121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * animation in the sequence.
56221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
56321cd1389d2ef218b20994b617c57af120841a57fChet Haase    public long getStagger(int transitionType) {
56421cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
56521cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
56621cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mChangingAppearingStagger;
56721cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
56821cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mChangingDisappearingStagger;
5697dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
5707dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return mChangingStagger;
57121cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
57221cd1389d2ef218b20994b617c57af120841a57fChet Haase        // shouldn't reach here
57321cd1389d2ef218b20994b617c57af120841a57fChet Haase        return 0;
57421cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
57521cd1389d2ef218b20994b617c57af120841a57fChet Haase
57621cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
57721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Sets the interpolator on one of the animation objects used by this transition. The
57821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * <code>transitionType</code> parameter determines the animation whose interpolator
57921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * is being set.
58021cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
5817dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
5827dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
5837dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * the animation whose interpolator is being set.
58421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param interpolator The interpolator that the specified animation should use.
585e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase     * @see Animator#setInterpolator(TimeInterpolator)
58621cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
587e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase    public void setInterpolator(int transitionType, TimeInterpolator interpolator) {
58821cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
58921cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
59021cd1389d2ef218b20994b617c57af120841a57fChet Haase                mChangingAppearingInterpolator = interpolator;
59121cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
59221cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
59321cd1389d2ef218b20994b617c57af120841a57fChet Haase                mChangingDisappearingInterpolator = interpolator;
59421cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
5957dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
5967dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mChangingInterpolator = interpolator;
5977dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
59821cd1389d2ef218b20994b617c57af120841a57fChet Haase            case APPEARING:
59921cd1389d2ef218b20994b617c57af120841a57fChet Haase                mAppearingInterpolator = interpolator;
60021cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
60121cd1389d2ef218b20994b617c57af120841a57fChet Haase            case DISAPPEARING:
60221cd1389d2ef218b20994b617c57af120841a57fChet Haase                mDisappearingInterpolator = interpolator;
60321cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
60421cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
60521cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
60621cd1389d2ef218b20994b617c57af120841a57fChet Haase
60721cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
60821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Gets the interpolator on one of the animation objects used by this transition. The
60921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * <code>transitionType</code> parameter determines the animation whose interpolator
61021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * is returned.
61121cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
6127dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
6137dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
6147dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * the animation whose interpolator is being returned.
615e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase     * @return TimeInterpolator The interpolator that the specified animation uses.
616e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase     * @see Animator#setInterpolator(TimeInterpolator)
61721cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
618e0ee2e9f3102c3c14c873a75a7b04e49787e0fb9Chet Haase    public TimeInterpolator getInterpolator(int transitionType) {
61921cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
62021cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
62121cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mChangingAppearingInterpolator;
62221cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
62321cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mChangingDisappearingInterpolator;
6247dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
6257dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return mChangingInterpolator;
62621cd1389d2ef218b20994b617c57af120841a57fChet Haase            case APPEARING:
62721cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mAppearingInterpolator;
62821cd1389d2ef218b20994b617c57af120841a57fChet Haase            case DISAPPEARING:
62921cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mDisappearingInterpolator;
63021cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
63121cd1389d2ef218b20994b617c57af120841a57fChet Haase        // shouldn't reach here
63221cd1389d2ef218b20994b617c57af120841a57fChet Haase        return null;
63321cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
63421cd1389d2ef218b20994b617c57af120841a57fChet Haase
63521cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
63621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Sets the animation used during one of the transition types that may run. Any
637a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * Animator object can be used, but to be most useful in the context of layout
638a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * transitions, the animation should either be a ObjectAnimator or a AnimatorSet
639a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * of animations including PropertyAnimators. Also, these ObjectAnimator objects
64021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * should be able to get and set values on their target objects automatically. For
641a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * example, a ObjectAnimator that animates the property "left" is able to set and get the
64221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * <code>left</code> property from the View objects being animated by the layout
64321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * transition. The transition works by setting target objects and properties
64421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * dynamically, according to the pre- and post-layoout values of those objects, so
64521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * having animations that can handle those properties appropriately will work best
64621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * for custom animation. The dynamic setting of values is only the case for the
64721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * CHANGE animations; the APPEARING and DISAPPEARING animations are simply run with
64821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * the values they have.
64921cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
65021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * <p>It is also worth noting that any and all animations (and their underlying
65121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * PropertyValuesHolder objects) will have their start and end values set according
65221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * to the pre- and post-layout values. So, for example, a custom animation on "alpha"
65321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * as the CHANGE_APPEARING animation will inherit the real value of alpha on the target
65421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * object (presumably 1) as its starting and ending value when the animation begins.
65521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Animations which need to use values at the beginning and end that may not match the
65621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * values queried when the transition begins may need to use a different mechanism
657a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * than a standard ObjectAnimator object.</p>
65821cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
6597dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
6607dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the
6617dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * animation whose animator is being set.
6625d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase     * @param animator The animation being assigned. A value of <code>null</code> means that no
6635d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase     * animation will be run for the specified transitionType.
66421cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
665a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public void setAnimator(int transitionType, Animator animator) {
66621cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
66721cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
6685d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase                mChangingAppearingAnim = animator;
66921cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
67021cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
6715d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase                mChangingDisappearingAnim = animator;
67221cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
6737dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
6747dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                mChangingAnim = animator;
6757dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
67621cd1389d2ef218b20994b617c57af120841a57fChet Haase            case APPEARING:
6775d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase                mAppearingAnim = animator;
67821cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
67921cd1389d2ef218b20994b617c57af120841a57fChet Haase            case DISAPPEARING:
6805d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase                mDisappearingAnim = animator;
68121cd1389d2ef218b20994b617c57af120841a57fChet Haase                break;
68221cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
68321cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
68421cd1389d2ef218b20994b617c57af120841a57fChet Haase
68521cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
68621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Gets the animation used during one of the transition types that may run.
68721cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
6887dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
6897dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
6907dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * the animation whose animator is being returned.
691a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @return Animator The animation being used for the given transition type.
692a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase     * @see #setAnimator(int, Animator)
69321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
694a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase    public Animator getAnimator(int transitionType) {
69521cd1389d2ef218b20994b617c57af120841a57fChet Haase        switch (transitionType) {
69621cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_APPEARING:
69721cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mChangingAppearingAnim;
69821cd1389d2ef218b20994b617c57af120841a57fChet Haase            case CHANGE_DISAPPEARING:
69921cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mChangingDisappearingAnim;
7007dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
7017dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                return mChangingAnim;
70221cd1389d2ef218b20994b617c57af120841a57fChet Haase            case APPEARING:
70321cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mAppearingAnim;
70421cd1389d2ef218b20994b617c57af120841a57fChet Haase            case DISAPPEARING:
70521cd1389d2ef218b20994b617c57af120841a57fChet Haase                return mDisappearingAnim;
70621cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
70721cd1389d2ef218b20994b617c57af120841a57fChet Haase        // shouldn't reach here
70821cd1389d2ef218b20994b617c57af120841a57fChet Haase        return null;
70921cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
71021cd1389d2ef218b20994b617c57af120841a57fChet Haase
71121cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
712eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase     * This function sets up animations on all of the views that change during layout.
71321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * For every child in the parent, we create a change animation of the appropriate
7147dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * type (appearing, disappearing, or changing) and ask it to populate its start values from its
71521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * target view. We add layout listeners to all child views and listen for changes. For
71621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * those views that change, we populate the end values for those animations and start them.
71721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Animations are not run on unchanging views.
71821cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
7197dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param parent The container which is undergoing a change.
7207dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param newView The view being added to or removed from the parent. May be null if the
7217dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * changeReason is CHANGING.
7227dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param changeReason A value of APPEARING, DISAPPEARING, or CHANGING, indicating whether the
7237dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * transition is occurring because an item is being added to or removed from the parent, or
7247dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * if it is running in response to a layout operation (that is, if the value is CHANGING).
72521cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
72621cd1389d2ef218b20994b617c57af120841a57fChet Haase    private void runChangeTransition(final ViewGroup parent, View newView, final int changeReason) {
7275d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase
7287dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        Animator baseAnimator = null;
7297dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        Animator parentAnimator = null;
7307dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        final long duration;
7317dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        switch (changeReason) {
7327dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case APPEARING:
7337dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                baseAnimator = mChangingAppearingAnim;
7347dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                duration = mChangingAppearingDuration;
7357dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                parentAnimator = defaultChangeIn;
7367dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
7377dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case DISAPPEARING:
7387dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                baseAnimator = mChangingDisappearingAnim;
7397dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                duration = mChangingDisappearingDuration;
7407dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                parentAnimator = defaultChangeOut;
7417dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
7427dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
7437dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                baseAnimator = mChangingAnim;
7447dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                duration = mChangingDuration;
7457dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                parentAnimator = defaultChange;
7467dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
7477dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            default:
7487dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                // Shouldn't reach here
7497dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                duration = 0;
7507dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                break;
7517dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
7525d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase        // If the animation is null, there's nothing to do
7535d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase        if (baseAnimator == null) {
7545d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase            return;
7555d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase        }
7565d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase
75721cd1389d2ef218b20994b617c57af120841a57fChet Haase        // reset the inter-animation delay, in case we use it later
75821cd1389d2ef218b20994b617c57af120841a57fChet Haase        staggerDelay = 0;
75921cd1389d2ef218b20994b617c57af120841a57fChet Haase
76021cd1389d2ef218b20994b617c57af120841a57fChet Haase        final ViewTreeObserver observer = parent.getViewTreeObserver(); // used for later cleanup
761634a20acf713ffe0d4a67c0b888cf1e9782890e7Chet Haase        if (!observer.isAlive()) {
762634a20acf713ffe0d4a67c0b888cf1e9782890e7Chet Haase            // If the observer's not in a good state, skip the transition
763634a20acf713ffe0d4a67c0b888cf1e9782890e7Chet Haase            return;
764634a20acf713ffe0d4a67c0b888cf1e9782890e7Chet Haase        }
76521cd1389d2ef218b20994b617c57af120841a57fChet Haase        int numChildren = parent.getChildCount();
76621cd1389d2ef218b20994b617c57af120841a57fChet Haase
76721cd1389d2ef218b20994b617c57af120841a57fChet Haase        for (int i = 0; i < numChildren; ++i) {
76821cd1389d2ef218b20994b617c57af120841a57fChet Haase            final View child = parent.getChildAt(i);
76921cd1389d2ef218b20994b617c57af120841a57fChet Haase
77021cd1389d2ef218b20994b617c57af120841a57fChet Haase            // only animate the views not being added or removed
77121cd1389d2ef218b20994b617c57af120841a57fChet Haase            if (child != newView) {
772cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                setupChangeAnimation(parent, changeReason, baseAnimator, duration, child);
773cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            }
774cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        }
775cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        if (mAnimateParentHierarchy) {
776cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            ViewGroup tempParent = parent;
777cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            while (tempParent != null) {
778cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                ViewParent parentParent = tempParent.getParent();
779cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                if (parentParent instanceof ViewGroup) {
780e115ffeb3a05f440c0062ad9b3954b7fefef4b00Chet Haase                    setupChangeAnimation((ViewGroup)parentParent, changeReason, parentAnimator,
781cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                            duration, tempParent);
782cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    tempParent = (ViewGroup) parentParent;
783cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                } else {
784cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    tempParent = null;
7850dfc39842459daea98e2b551bbecd16d1baca439Chet Haase                }
78621cd1389d2ef218b20994b617c57af120841a57fChet Haase
78721cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
78821cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
789cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
79021cd1389d2ef218b20994b617c57af120841a57fChet Haase        // This is the cleanup step. When we get this rendering event, we know that all of
79121cd1389d2ef218b20994b617c57af120841a57fChet Haase        // the appropriate animations have been set up and run. Now we can clear out the
79221cd1389d2ef218b20994b617c57af120841a57fChet Haase        // layout listeners.
79321cd1389d2ef218b20994b617c57af120841a57fChet Haase        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
79421cd1389d2ef218b20994b617c57af120841a57fChet Haase            public boolean onPreDraw() {
795634a20acf713ffe0d4a67c0b888cf1e9782890e7Chet Haase                parent.getViewTreeObserver().removeOnPreDrawListener(this);
7961a76dcd6d1e30f92668b5df309398d545cef9aceChet Haase                int count = layoutChangeListenerMap.size();
7971a76dcd6d1e30f92668b5df309398d545cef9aceChet Haase                if (count > 0) {
7981a76dcd6d1e30f92668b5df309398d545cef9aceChet Haase                    Collection<View> views = layoutChangeListenerMap.keySet();
7991a76dcd6d1e30f92668b5df309398d545cef9aceChet Haase                    for (View view : views) {
8001a76dcd6d1e30f92668b5df309398d545cef9aceChet Haase                        View.OnLayoutChangeListener listener = layoutChangeListenerMap.get(view);
8011a76dcd6d1e30f92668b5df309398d545cef9aceChet Haase                        view.removeOnLayoutChangeListener(listener);
8021a76dcd6d1e30f92668b5df309398d545cef9aceChet Haase                    }
80321cd1389d2ef218b20994b617c57af120841a57fChet Haase                }
80421cd1389d2ef218b20994b617c57af120841a57fChet Haase                layoutChangeListenerMap.clear();
80521cd1389d2ef218b20994b617c57af120841a57fChet Haase                return true;
80621cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
80721cd1389d2ef218b20994b617c57af120841a57fChet Haase        });
80821cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
80921cd1389d2ef218b20994b617c57af120841a57fChet Haase
81021cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
811cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * This flag controls whether CHANGE_APPEARING or CHANGE_DISAPPEARING animations will
812e115ffeb3a05f440c0062ad9b3954b7fefef4b00Chet Haase     * cause the default changing animation to be run on the parent hierarchy as well. This allows
813cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * containers of transitioning views to also transition, which may be necessary in situations
814cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * where the containers bounds change between the before/after states and may clip their
815cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * children during the transition animations. For example, layouts with wrap_content will
816cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * adjust their bounds according to the dimensions of their children.
817cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     *
818e115ffeb3a05f440c0062ad9b3954b7fefef4b00Chet Haase     * <p>The default changing transitions animate the bounds and scroll positions of the
819e115ffeb3a05f440c0062ad9b3954b7fefef4b00Chet Haase     * target views. These are the animations that will run on the parent hierarchy, not
820e115ffeb3a05f440c0062ad9b3954b7fefef4b00Chet Haase     * the custom animations that happen to be set on the transition. This allows custom
821e115ffeb3a05f440c0062ad9b3954b7fefef4b00Chet Haase     * behavior for the children of the transitioning container, but uses standard behavior
822e115ffeb3a05f440c0062ad9b3954b7fefef4b00Chet Haase     * of resizing/rescrolling on any changing parents.
823e115ffeb3a05f440c0062ad9b3954b7fefef4b00Chet Haase     *
824cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * @param animateParentHierarchy A boolean value indicating whether the parents of
825cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * transitioning views should also be animated during the transition. Default value is true.
826cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     */
827cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    public void setAnimateParentHierarchy(boolean animateParentHierarchy) {
828cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        mAnimateParentHierarchy = animateParentHierarchy;
829cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    }
830cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
831cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    /**
832cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * Utility function called by runChangingTransition for both the children and the parent
833cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * hierarchy.
834cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     */
835cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    private void setupChangeAnimation(final ViewGroup parent, final int changeReason,
836cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            Animator baseAnimator, final long duration, final View child) {
8378a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase
8388a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase        // If we already have a listener for this child, then we've already set up the
8398a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase        // changing animation we need. Multiple calls for a child may occur when several
8408a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase        // add/remove operations are run at once on a container; each one will trigger
8418a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase        // changes for the existing children in the container.
8428a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase        if (layoutChangeListenerMap.get(child) != null) {
8438a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase            return;
8448a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase        }
8458a22e59311ab797aeb10682b4c9e036ded95a429Chet Haase
84666ef1a201ea9df71a8ec9b2d1aaab1eb1180ae40Chet Haase        // Don't animate items up from size(0,0); this is likely because the objects
84766ef1a201ea9df71a8ec9b2d1aaab1eb1180ae40Chet Haase        // were offscreen/invisible or otherwise measured to be infinitely small. We don't
84866ef1a201ea9df71a8ec9b2d1aaab1eb1180ae40Chet Haase        // want to see them animate into their real size; just ignore animation requests
84966ef1a201ea9df71a8ec9b2d1aaab1eb1180ae40Chet Haase        // on these views
85066ef1a201ea9df71a8ec9b2d1aaab1eb1180ae40Chet Haase        if (child.getWidth() == 0 && child.getHeight() == 0) {
85166ef1a201ea9df71a8ec9b2d1aaab1eb1180ae40Chet Haase            return;
85266ef1a201ea9df71a8ec9b2d1aaab1eb1180ae40Chet Haase        }
85366ef1a201ea9df71a8ec9b2d1aaab1eb1180ae40Chet Haase
854cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // Make a copy of the appropriate animation
855cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        final Animator anim = baseAnimator.clone();
856cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
857cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // Set the target object for the animation
858cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        anim.setTarget(child);
859cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
860cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // A ObjectAnimator (or AnimatorSet of them) can extract start values from
861cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // its target object
862cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        anim.setupStartValues();
863cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
864cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // If there's an animation running on this view already, cancel it
865cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        Animator currentAnimation = pendingAnimations.get(child);
866cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        if (currentAnimation != null) {
867cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            currentAnimation.cancel();
868cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            pendingAnimations.remove(child);
869cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        }
870cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // Cache the animation in case we need to cancel it later
871cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        pendingAnimations.put(child, anim);
872cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
873cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // For the animations which don't get started, we have to have a means of
874cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // removing them from the cache, lest we leak them and their target objects.
875cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // We run an animator for the default duration+100 (an arbitrary time, but one
876cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // which should far surpass the delay between setting them up here and
877cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // handling layout events which start them.
878cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        ValueAnimator pendingAnimRemover = ValueAnimator.ofFloat(0f, 1f).
879cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                setDuration(duration + 100);
880cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        pendingAnimRemover.addListener(new AnimatorListenerAdapter() {
881cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            @Override
882cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            public void onAnimationEnd(Animator animation) {
883cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                pendingAnimations.remove(child);
884cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            }
885cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        });
886cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        pendingAnimRemover.start();
887cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
888cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // Add a listener to track layout changes on this view. If we don't get a callback,
889cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // then there's nothing to animate.
890cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        final View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
891cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            public void onLayoutChange(View v, int left, int top, int right, int bottom,
892cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
893cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
894cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                // Tell the animation to extract end values from the changed object
895cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                anim.setupEndValues();
896cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                if (anim instanceof ValueAnimator) {
897cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    boolean valuesDiffer = false;
898cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    ValueAnimator valueAnim = (ValueAnimator)anim;
899cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    PropertyValuesHolder[] oldValues = valueAnim.getValues();
900cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    for (int i = 0; i < oldValues.length; ++i) {
901cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                        PropertyValuesHolder pvh = oldValues[i];
902cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                        KeyframeSet keyframeSet = pvh.mKeyframeSet;
903cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                        if (keyframeSet.mFirstKeyframe == null ||
904cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                                keyframeSet.mLastKeyframe == null ||
905cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                                !keyframeSet.mFirstKeyframe.getValue().equals(
906cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                                keyframeSet.mLastKeyframe.getValue())) {
907cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                            valuesDiffer = true;
908cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                        }
909cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    }
910cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    if (!valuesDiffer) {
911cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                        return;
912cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    }
913cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                }
914cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
9157dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                long startDelay = 0;
9167dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                switch (changeReason) {
9177dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                    case APPEARING:
9187dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        startDelay = mChangingAppearingDelay + staggerDelay;
9197dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        staggerDelay += mChangingAppearingStagger;
92033d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                        if (mChangingAppearingInterpolator != sChangingAppearingInterpolator) {
92133d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                            anim.setInterpolator(mChangingAppearingInterpolator);
92233d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                        }
9237dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        break;
9247dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                    case DISAPPEARING:
9257dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        startDelay = mChangingDisappearingDelay + staggerDelay;
9267dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        staggerDelay += mChangingDisappearingStagger;
92733d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                        if (mChangingDisappearingInterpolator !=
92833d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                                sChangingDisappearingInterpolator) {
92933d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                            anim.setInterpolator(mChangingDisappearingInterpolator);
93033d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                        }
9317dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        break;
9327dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                    case CHANGING:
9337dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        startDelay = mChangingDelay + staggerDelay;
9347dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        staggerDelay += mChangingStagger;
93533d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                        if (mChangingInterpolator != sChangingInterpolator) {
93633d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                            anim.setInterpolator(mChangingInterpolator);
93733d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase                        }
9387dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                        break;
939cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                }
940cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                anim.setStartDelay(startDelay);
941cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                anim.setDuration(duration);
942cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
943cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                Animator prevAnimation = currentChangingAnimations.get(child);
944cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                if (prevAnimation != null) {
945cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    prevAnimation.cancel();
946cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                }
947cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                Animator pendingAnimation = pendingAnimations.get(child);
948cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                if (pendingAnimation != null) {
949cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    pendingAnimations.remove(child);
950cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                }
951cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                // Cache the animation in case we need to cancel it later
952cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                currentChangingAnimations.put(child, anim);
953cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
954cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                parent.requestTransitionStart(LayoutTransition.this);
955cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
956cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                // this only removes listeners whose views changed - must clear the
957cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                // other listeners later
958cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                child.removeOnLayoutChangeListener(this);
959cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                layoutChangeListenerMap.remove(child);
960cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            }
961cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        };
962cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // Remove the animation from the cache when it ends
963cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        anim.addListener(new AnimatorListenerAdapter() {
964cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
965cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            @Override
966cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            public void onAnimationStart(Animator animator) {
967c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                if (hasListeners()) {
968c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    ArrayList<TransitionListener> listeners =
969c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                            (ArrayList<TransitionListener>) mListeners.clone();
970c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    for (TransitionListener listener : listeners) {
971cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                        listener.startTransition(LayoutTransition.this, parent, child,
972cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                                changeReason == APPEARING ?
9737dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                                        CHANGE_APPEARING : changeReason == DISAPPEARING ?
9747dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                                        CHANGE_DISAPPEARING : CHANGING);
975cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    }
976cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                }
977cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            }
978cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
979cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            @Override
980cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            public void onAnimationCancel(Animator animator) {
981cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                child.removeOnLayoutChangeListener(listener);
982cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                layoutChangeListenerMap.remove(child);
983cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            }
984cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
985cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            @Override
986cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            public void onAnimationEnd(Animator animator) {
987cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                currentChangingAnimations.remove(child);
988c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                if (hasListeners()) {
989c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    ArrayList<TransitionListener> listeners =
990c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                            (ArrayList<TransitionListener>) mListeners.clone();
991c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    for (TransitionListener listener : listeners) {
992cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                        listener.endTransition(LayoutTransition.this, parent, child,
993cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                                changeReason == APPEARING ?
9947dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                                        CHANGE_APPEARING : changeReason == DISAPPEARING ?
9957dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                                        CHANGE_DISAPPEARING : CHANGING);
996cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                    }
997cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                }
998cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            }
999cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        });
1000cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
1001cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        child.addOnLayoutChangeListener(listener);
1002cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        // cache the listener for later removal
1003cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        layoutChangeListenerMap.put(child, listener);
1004cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    }
1005cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
1006cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    /**
1007cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * Starts the animations set up for a CHANGING transition. We separate the setup of these
1008cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * animations from actually starting them, to avoid side-effects that starting the animations
1009cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * may have on the properties of the affected objects. After setup, we tell the affected parent
1010cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * that this transition should be started. The parent informs its ViewAncestor, which then
1011cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * starts the transition after the current layout/measurement phase, just prior to drawing
1012cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * the view hierarchy.
1013cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     *
1014cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     * @hide
1015cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase     */
1016cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    public void startChangingAnimations() {
1017d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase        LinkedHashMap<View, Animator> currentAnimCopy =
1018d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase                (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
1019d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase        for (Animator anim : currentAnimCopy.values()) {
1020cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            if (anim instanceof ObjectAnimator) {
1021cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase                ((ObjectAnimator) anim).setCurrentPlayTime(0);
1022cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            }
1023cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase            anim.start();
1024cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase        }
1025cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    }
1026cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase
1027cca2c9807206f320bd41bf8656a227e4f249e4baChet Haase    /**
1028d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase     * Ends the animations that are set up for a CHANGING transition. This is a variant of
1029d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase     * startChangingAnimations() which is called when the window the transition is playing in
1030d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase     * is not visible. We need to make sure the animations put their targets in their end states
1031d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase     * and that the transition finishes to remove any mid-process state (such as isRunning()).
1032d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase     *
1033d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase     * @hide
1034d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase     */
1035d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase    public void endChangingAnimations() {
1036d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase        LinkedHashMap<View, Animator> currentAnimCopy =
1037d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase                (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
1038d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase        for (Animator anim : currentAnimCopy.values()) {
1039d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase            anim.start();
1040d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase            anim.end();
1041d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase        }
104217cf42cb85c22b50ecfa8d21efc992f99d20fc45Chet Haase        // listeners should clean up the currentChangingAnimations list, but just in case...
104317cf42cb85c22b50ecfa8d21efc992f99d20fc45Chet Haase        currentChangingAnimations.clear();
1044d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase    }
1045d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase
1046d56c6951755a902a354e13e5fa05fb0984132cc6Chet Haase    /**
10479c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     * Returns true if animations are running which animate layout-related properties. This
10489c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     * essentially means that either CHANGE_APPEARING or CHANGE_DISAPPEARING animations
10499c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     * are running, since these animations operate on layout-related properties.
10509c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     *
10519c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     * @return true if CHANGE_APPEARING or CHANGE_DISAPPEARING animations are currently
10529c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     * running.
10539c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     */
10549c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase    public boolean isChangingLayout() {
10559c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase        return (currentChangingAnimations.size() > 0);
10569c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase    }
10579c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase
10589c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase    /**
10599c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     * Returns true if any of the animations in this transition are currently running.
10609c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     *
10619c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     * @return true if any animations in the transition are running.
10629c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase     */
10639c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase    public boolean isRunning() {
1064e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        return (currentChangingAnimations.size() > 0 || currentAppearingAnimations.size() > 0 ||
1065e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                currentDisappearingAnimations.size() > 0);
10669c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase    }
10679c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase
10689c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase    /**
1069add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase     * Cancels the currently running transition. Note that we cancel() the changing animations
1070add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase     * but end() the visibility animations. This is because this method is currently called
1071add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase     * in the context of starting a new transition, so we want to move things from their mid-
1072add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase     * transition positions, but we want them to have their end-transition visibility.
1073add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase     *
1074add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase     * @hide
1075add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase     */
1076add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase    public void cancel() {
1077e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        if (currentChangingAnimations.size() > 0) {
1078eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase            LinkedHashMap<View, Animator> currentAnimCopy =
1079eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                    (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
1080e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            for (Animator anim : currentAnimCopy.values()) {
1081e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                anim.cancel();
1082e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            }
1083e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            currentChangingAnimations.clear();
1084e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        }
1085e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        if (currentAppearingAnimations.size() > 0) {
1086eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase            LinkedHashMap<View, Animator> currentAnimCopy =
1087eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                    (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone();
1088e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            for (Animator anim : currentAnimCopy.values()) {
1089e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                anim.end();
1090e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            }
1091e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            currentAppearingAnimations.clear();
1092add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase        }
1093e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        if (currentDisappearingAnimations.size() > 0) {
1094eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase            LinkedHashMap<View, Animator> currentAnimCopy =
1095eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                    (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone();
1096e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            for (Animator anim : currentAnimCopy.values()) {
1097e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                anim.end();
1098e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            }
1099e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            currentDisappearingAnimations.clear();
1100e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        }
1101e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase    }
1102e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase
1103e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase    /**
1104e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase     * Cancels the specified type of transition. Note that we cancel() the changing animations
1105e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase     * but end() the visibility animations. This is because this method is currently called
1106e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase     * in the context of starting a new transition, so we want to move things from their mid-
1107e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase     * transition positions, but we want them to have their end-transition visibility.
1108e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase     *
1109e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase     * @hide
1110e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase     */
1111e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase    public void cancel(int transitionType) {
1112e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        switch (transitionType) {
1113e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            case CHANGE_APPEARING:
1114e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            case CHANGE_DISAPPEARING:
11157dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            case CHANGING:
1116e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                if (currentChangingAnimations.size() > 0) {
1117eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                    LinkedHashMap<View, Animator> currentAnimCopy =
1118eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                            (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
1119e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    for (Animator anim : currentAnimCopy.values()) {
1120e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                        anim.cancel();
1121e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    }
1122e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    currentChangingAnimations.clear();
1123e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                }
1124e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                break;
1125e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            case APPEARING:
1126e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                if (currentAppearingAnimations.size() > 0) {
1127eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                    LinkedHashMap<View, Animator> currentAnimCopy =
1128eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                            (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone();
1129e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    for (Animator anim : currentAnimCopy.values()) {
1130e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                        anim.end();
1131e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    }
1132e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    currentAppearingAnimations.clear();
1133e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                }
1134e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                break;
1135e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase            case DISAPPEARING:
1136e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                if (currentDisappearingAnimations.size() > 0) {
1137eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                    LinkedHashMap<View, Animator> currentAnimCopy =
1138eb1d851e0e6c2dc1de0ec7990ccf7d29dda41a9aChet Haase                            (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone();
1139e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    for (Animator anim : currentAnimCopy.values()) {
1140e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                        anim.end();
1141e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    }
1142e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                    currentDisappearingAnimations.clear();
1143e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                }
1144e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase                break;
1145add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase        }
1146add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase    }
1147add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase
1148add6577a0196258e5a48c5deefcdb12e05c935b3Chet Haase    /**
114921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * This method runs the animation that makes an added item appear.
115021cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
115121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param parent The ViewGroup to which the View is being added.
115221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param child The View being added to the ViewGroup.
115321cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
115421cd1389d2ef218b20994b617c57af120841a57fChet Haase    private void runAppearingTransition(final ViewGroup parent, final View child) {
1155e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        Animator currentAnimation = currentDisappearingAnimations.get(child);
1156e64ea87f966e995f5e1a77f991b9da0ed21ffab0Chet Haase        if (currentAnimation != null) {
1157e64ea87f966e995f5e1a77f991b9da0ed21ffab0Chet Haase            currentAnimation.cancel();
1158e64ea87f966e995f5e1a77f991b9da0ed21ffab0Chet Haase        }
11595d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase        if (mAppearingAnim == null) {
1160c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin            if (hasListeners()) {
1161c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                ArrayList<TransitionListener> listeners =
1162c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                        (ArrayList<TransitionListener>) mListeners.clone();
1163c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                for (TransitionListener listener : listeners) {
11645d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase                    listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
11655d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase                }
11665d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase            }
11675d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase            return;
11685d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase        }
1169a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        Animator anim = mAppearingAnim.clone();
117021cd1389d2ef218b20994b617c57af120841a57fChet Haase        anim.setTarget(child);
117121cd1389d2ef218b20994b617c57af120841a57fChet Haase        anim.setStartDelay(mAppearingDelay);
117221cd1389d2ef218b20994b617c57af120841a57fChet Haase        anim.setDuration(mAppearingDuration);
117333d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase        if (mAppearingInterpolator != sAppearingInterpolator) {
117433d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase            anim.setInterpolator(mAppearingInterpolator);
117533d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase        }
1176a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        if (anim instanceof ObjectAnimator) {
1177a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ((ObjectAnimator) anim).setCurrentPlayTime(0);
117821cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
1179a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase        anim.addListener(new AnimatorListenerAdapter() {
1180a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase            @Override
1181a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase            public void onAnimationEnd(Animator anim) {
1182a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase                currentAppearingAnimations.remove(child);
1183c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                if (hasListeners()) {
1184c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    ArrayList<TransitionListener> listeners =
1185c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                            (ArrayList<TransitionListener>) mListeners.clone();
1186c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    for (TransitionListener listener : listeners) {
118721cd1389d2ef218b20994b617c57af120841a57fChet Haase                        listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
118821cd1389d2ef218b20994b617c57af120841a57fChet Haase                    }
118921cd1389d2ef218b20994b617c57af120841a57fChet Haase                }
1190a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase            }
1191a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase        });
1192e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        currentAppearingAnimations.put(child, anim);
119321cd1389d2ef218b20994b617c57af120841a57fChet Haase        anim.start();
119421cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
119521cd1389d2ef218b20994b617c57af120841a57fChet Haase
119621cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
119721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * This method runs the animation that makes a removed item disappear.
119821cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
119921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param parent The ViewGroup from which the View is being removed.
120021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param child The View being removed from the ViewGroup.
120121cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
120221cd1389d2ef218b20994b617c57af120841a57fChet Haase    private void runDisappearingTransition(final ViewGroup parent, final View child) {
1203e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        Animator currentAnimation = currentAppearingAnimations.get(child);
1204e64ea87f966e995f5e1a77f991b9da0ed21ffab0Chet Haase        if (currentAnimation != null) {
1205e64ea87f966e995f5e1a77f991b9da0ed21ffab0Chet Haase            currentAnimation.cancel();
1206e64ea87f966e995f5e1a77f991b9da0ed21ffab0Chet Haase        }
12075d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase        if (mDisappearingAnim == null) {
1208c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin            if (hasListeners()) {
1209c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                ArrayList<TransitionListener> listeners =
1210c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                        (ArrayList<TransitionListener>) mListeners.clone();
1211c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                for (TransitionListener listener : listeners) {
12125d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase                    listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
12135d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase                }
12145d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase            }
12155d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase            return;
12165d6d7b9c3d76ba0bf72906d54c2ef366be149a23Chet Haase        }
1217a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        Animator anim = mDisappearingAnim.clone();
121821cd1389d2ef218b20994b617c57af120841a57fChet Haase        anim.setStartDelay(mDisappearingDelay);
121921cd1389d2ef218b20994b617c57af120841a57fChet Haase        anim.setDuration(mDisappearingDuration);
122033d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase        if (mDisappearingInterpolator != sDisappearingInterpolator) {
122133d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase            anim.setInterpolator(mDisappearingInterpolator);
122233d08762d8e8d32422903929ad2b72774d9f8c87Chet Haase        }
122321cd1389d2ef218b20994b617c57af120841a57fChet Haase        anim.setTarget(child);
1224a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase        final float preAnimAlpha = child.getAlpha();
1225a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase        anim.addListener(new AnimatorListenerAdapter() {
1226a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase            @Override
1227a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase            public void onAnimationEnd(Animator anim) {
1228a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase                currentDisappearingAnimations.remove(child);
1229a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase                child.setAlpha(preAnimAlpha);
1230c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                if (hasListeners()) {
1231c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    ArrayList<TransitionListener> listeners =
1232c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                            (ArrayList<TransitionListener>) mListeners.clone();
1233c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    for (TransitionListener listener : listeners) {
123421cd1389d2ef218b20994b617c57af120841a57fChet Haase                        listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
123521cd1389d2ef218b20994b617c57af120841a57fChet Haase                    }
123621cd1389d2ef218b20994b617c57af120841a57fChet Haase                }
1237a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase            }
1238a553113a1f88e112b0999c12c7c2e8d724ed7fa8Chet Haase        });
1239a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase        if (anim instanceof ObjectAnimator) {
1240a18a86b43e40e3c15dcca0ae0148d641be9b25feChet Haase            ((ObjectAnimator) anim).setCurrentPlayTime(0);
124121cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
1242e8e45d32fd1f67fed1b70d0fc19d2f91a76f128eChet Haase        currentDisappearingAnimations.put(child, anim);
124321cd1389d2ef218b20994b617c57af120841a57fChet Haase        anim.start();
124421cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
124521cd1389d2ef218b20994b617c57af120841a57fChet Haase
124621cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
124721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * This method is called by ViewGroup when a child view is about to be added to the
124821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * container. This callback starts the process of a transition; we grab the starting
124921cd1389d2ef218b20994b617c57af120841a57fChet Haase     * values, listen for changes to all of the children of the container, and start appropriate
125021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * animations.
125121cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
125221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param parent The ViewGroup to which the View is being added.
125321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param child The View being added to the ViewGroup.
12540d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @param changesLayout Whether the removal will cause changes in the layout of other views
12550d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * in the container. INVISIBLE views becoming VISIBLE will not cause changes and thus will not
12560d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
125721cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
12580d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    private void addChild(ViewGroup parent, View child, boolean changesLayout) {
1259ab3a776827365b6bb413052a5e093bbc87265728Chet Haase        if (parent.getWindowVisibility() != View.VISIBLE) {
1260ab3a776827365b6bb413052a5e093bbc87265728Chet Haase            return;
1261ab3a776827365b6bb413052a5e093bbc87265728Chet Haase        }
12627dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if ((mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
12637dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            // Want disappearing animations to finish up before proceeding
12647dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            cancel(DISAPPEARING);
12657dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
12667dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if (changesLayout && (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING) {
12670d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase            // Also, cancel changing animations so that we start fresh ones from current locations
12680d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase            cancel(CHANGE_APPEARING);
12697dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            cancel(CHANGING);
12700d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        }
1271c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin        if (hasListeners() && (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
1272c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin            ArrayList<TransitionListener> listeners =
1273c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    (ArrayList<TransitionListener>) mListeners.clone();
1274c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin            for (TransitionListener listener : listeners) {
127521cd1389d2ef218b20994b617c57af120841a57fChet Haase                listener.startTransition(this, parent, child, APPEARING);
127621cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
127721cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
12787dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if (changesLayout && (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING) {
12790d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase            runChangeTransition(parent, child, APPEARING);
12800d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        }
12817dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if ((mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
12827dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            runAppearingTransition(parent, child);
12837dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
12847dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    }
12857dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase
1286c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin    private boolean hasListeners() {
1287c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin        return mListeners != null && mListeners.size() > 0;
1288c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin    }
1289c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin
12907dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    /**
12917dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * This method is called by ViewGroup when there is a call to layout() on the container
12927dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * with this LayoutTransition. If the CHANGING transition is enabled and if there is no other
12937dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * transition currently running on the container, then this call runs a CHANGING transition.
12947dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * The transition does not start immediately; it just sets up the mechanism to run if any
12957dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * of the children of the container change their layout parameters (similar to
12967dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * the CHANGE_APPEARING and CHANGE_DISAPPEARING transitions).
12977dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     *
12987dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @param parent The ViewGroup whose layout() method has been called.
12997dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     *
13007dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     * @hide
13017dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase     */
13027dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase    public void layoutChange(ViewGroup parent) {
1303ab3a776827365b6bb413052a5e093bbc87265728Chet Haase        if (parent.getWindowVisibility() != View.VISIBLE) {
1304ab3a776827365b6bb413052a5e093bbc87265728Chet Haase            return;
1305ab3a776827365b6bb413052a5e093bbc87265728Chet Haase        }
13067dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if ((mTransitionTypes & FLAG_CHANGING) == FLAG_CHANGING  && !isRunning()) {
13077dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            // This method is called for all calls to layout() in the container, including
13087dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            // those caused by add/remove/hide/show events, which will already have set up
13097dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            // transition animations. Avoid setting up CHANGING animations in this case; only
13107dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            // do so when there is not a transition already running on the container.
13117dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            runChangeTransition(parent, null, CHANGING);
13127dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
131321cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
131421cd1389d2ef218b20994b617c57af120841a57fChet Haase
131521cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
13165e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * This method is called by ViewGroup when a child view is about to be added to the
13175e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * container. This callback starts the process of a transition; we grab the starting
13185e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * values, listen for changes to all of the children of the container, and start appropriate
13195e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * animations.
13205e25c2c14593caee5638603120553ae1ec530f85Chet Haase     *
13215e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * @param parent The ViewGroup to which the View is being added.
13225e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * @param child The View being added to the ViewGroup.
13235e25c2c14593caee5638603120553ae1ec530f85Chet Haase     */
13240d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    public void addChild(ViewGroup parent, View child) {
13250d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        addChild(parent, child, true);
13260d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    }
13270d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase
13280d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    /**
13290d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @deprecated Use {@link #showChild(android.view.ViewGroup, android.view.View, int)}.
13300d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     */
13310d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    @Deprecated
13325e25c2c14593caee5638603120553ae1ec530f85Chet Haase    public void showChild(ViewGroup parent, View child) {
13330d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        addChild(parent, child, true);
13340d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    }
13350d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase
13360d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    /**
13370d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * This method is called by ViewGroup when a child view is about to be made visible in the
13380d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * container. This callback starts the process of a transition; we grab the starting
13390d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * values, listen for changes to all of the children of the container, and start appropriate
13400d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * animations.
13410d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     *
13420d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @param parent The ViewGroup in which the View is being made visible.
13430d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @param child The View being made visible.
13440d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @param oldVisibility The previous visibility value of the child View, either
13450d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * {@link View#GONE} or {@link View#INVISIBLE}.
13460d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     */
13470d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    public void showChild(ViewGroup parent, View child, int oldVisibility) {
13480d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        addChild(parent, child, oldVisibility == View.GONE);
13495e25c2c14593caee5638603120553ae1ec530f85Chet Haase    }
13505e25c2c14593caee5638603120553ae1ec530f85Chet Haase
13515e25c2c14593caee5638603120553ae1ec530f85Chet Haase    /**
135221cd1389d2ef218b20994b617c57af120841a57fChet Haase     * This method is called by ViewGroup when a child view is about to be removed from the
135321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * container. This callback starts the process of a transition; we grab the starting
135421cd1389d2ef218b20994b617c57af120841a57fChet Haase     * values, listen for changes to all of the children of the container, and start appropriate
135521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * animations.
135621cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
135721cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param parent The ViewGroup from which the View is being removed.
135821cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param child The View being removed from the ViewGroup.
13590d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @param changesLayout Whether the removal will cause changes in the layout of other views
13600d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * in the container. Views becoming INVISIBLE will not cause changes and thus will not
13610d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
136221cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
13630d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
1364ab3a776827365b6bb413052a5e093bbc87265728Chet Haase        if (parent.getWindowVisibility() != View.VISIBLE) {
1365ab3a776827365b6bb413052a5e093bbc87265728Chet Haase            return;
1366ab3a776827365b6bb413052a5e093bbc87265728Chet Haase        }
13677dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if ((mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
13687dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            // Want appearing animations to finish up before proceeding
13697dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            cancel(APPEARING);
13707dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
13717dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if (changesLayout &&
13727dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING) {
13730d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase            // Also, cancel changing animations so that we start fresh ones from current locations
13740d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase            cancel(CHANGE_DISAPPEARING);
13757dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            cancel(CHANGING);
13760d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        }
1377c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin        if (hasListeners() && (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
1378c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin            ArrayList<TransitionListener> listeners = (ArrayList<TransitionListener>) mListeners
1379c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin                    .clone();
1380c20fc8daf56eb348fa4a9355a9e33b0ebc468699Luca Zanolin            for (TransitionListener listener : listeners) {
138121cd1389d2ef218b20994b617c57af120841a57fChet Haase                listener.startTransition(this, parent, child, DISAPPEARING);
138221cd1389d2ef218b20994b617c57af120841a57fChet Haase            }
138321cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
13847dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if (changesLayout &&
13857dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase                (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING) {
13860d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase            runChangeTransition(parent, child, DISAPPEARING);
13870d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        }
13887dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        if ((mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
13897dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase            runDisappearingTransition(parent, child);
13907dd4a536a125d5e9573e82c39581bf9ee3922424Chet Haase        }
139121cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
139221cd1389d2ef218b20994b617c57af120841a57fChet Haase
139321cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
13945e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * This method is called by ViewGroup when a child view is about to be removed from the
13955e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * container. This callback starts the process of a transition; we grab the starting
13965e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * values, listen for changes to all of the children of the container, and start appropriate
13975e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * animations.
13985e25c2c14593caee5638603120553ae1ec530f85Chet Haase     *
13995e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * @param parent The ViewGroup from which the View is being removed.
14005e25c2c14593caee5638603120553ae1ec530f85Chet Haase     * @param child The View being removed from the ViewGroup.
14015e25c2c14593caee5638603120553ae1ec530f85Chet Haase     */
14020d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    public void removeChild(ViewGroup parent, View child) {
14030d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        removeChild(parent, child, true);
14040d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    }
14050d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase
14060d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    /**
14070d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @deprecated Use {@link #hideChild(android.view.ViewGroup, android.view.View, int)}.
14080d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     */
14090d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    @Deprecated
14105e25c2c14593caee5638603120553ae1ec530f85Chet Haase    public void hideChild(ViewGroup parent, View child) {
14110d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        removeChild(parent, child, true);
14120d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    }
14130d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase
14140d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    /**
14150d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * This method is called by ViewGroup when a child view is about to be hidden in
14160d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * container. This callback starts the process of a transition; we grab the starting
14170d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * values, listen for changes to all of the children of the container, and start appropriate
14180d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * animations.
14190d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     *
14200d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @param parent The parent ViewGroup of the View being hidden.
14210d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @param child The View being hidden.
14220d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * @param newVisibility The new visibility value of the child View, either
14230d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     * {@link View#GONE} or {@link View#INVISIBLE}.
14240d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase     */
14250d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase    public void hideChild(ViewGroup parent, View child, int newVisibility) {
14260d29936ec3b5545a415e8d032150ea987aab36e3Chet Haase        removeChild(parent, child, newVisibility == View.GONE);
14275e25c2c14593caee5638603120553ae1ec530f85Chet Haase    }
14285e25c2c14593caee5638603120553ae1ec530f85Chet Haase
14295e25c2c14593caee5638603120553ae1ec530f85Chet Haase    /**
143021cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Add a listener that will be called when the bounds of the view change due to
143121cd1389d2ef218b20994b617c57af120841a57fChet Haase     * layout processing.
143221cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
143321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param listener The listener that will be called when layout bounds change.
143421cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
143521cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void addTransitionListener(TransitionListener listener) {
143621cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (mListeners == null) {
143721cd1389d2ef218b20994b617c57af120841a57fChet Haase            mListeners = new ArrayList<TransitionListener>();
143821cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
143921cd1389d2ef218b20994b617c57af120841a57fChet Haase        mListeners.add(listener);
144021cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
144121cd1389d2ef218b20994b617c57af120841a57fChet Haase
144221cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
144321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Remove a listener for layout changes.
144421cd1389d2ef218b20994b617c57af120841a57fChet Haase     *
144521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @param listener The listener for layout bounds change.
144621cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
144721cd1389d2ef218b20994b617c57af120841a57fChet Haase    public void removeTransitionListener(TransitionListener listener) {
144821cd1389d2ef218b20994b617c57af120841a57fChet Haase        if (mListeners == null) {
144921cd1389d2ef218b20994b617c57af120841a57fChet Haase            return;
145021cd1389d2ef218b20994b617c57af120841a57fChet Haase        }
145121cd1389d2ef218b20994b617c57af120841a57fChet Haase        mListeners.remove(listener);
145221cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
145321cd1389d2ef218b20994b617c57af120841a57fChet Haase
145421cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
145521cd1389d2ef218b20994b617c57af120841a57fChet Haase     * Gets the current list of listeners for layout changes.
145621cd1389d2ef218b20994b617c57af120841a57fChet Haase     * @return
145721cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
145821cd1389d2ef218b20994b617c57af120841a57fChet Haase    public List<TransitionListener> getTransitionListeners() {
145921cd1389d2ef218b20994b617c57af120841a57fChet Haase        return mListeners;
146021cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
146121cd1389d2ef218b20994b617c57af120841a57fChet Haase
146221cd1389d2ef218b20994b617c57af120841a57fChet Haase    /**
146321cd1389d2ef218b20994b617c57af120841a57fChet Haase     * This interface is used for listening to starting and ending events for transitions.
146421cd1389d2ef218b20994b617c57af120841a57fChet Haase     */
146521cd1389d2ef218b20994b617c57af120841a57fChet Haase    public interface TransitionListener {
146621cd1389d2ef218b20994b617c57af120841a57fChet Haase
146721cd1389d2ef218b20994b617c57af120841a57fChet Haase        /**
14689c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * This event is sent to listeners when any type of transition animation begins.
146921cd1389d2ef218b20994b617c57af120841a57fChet Haase         *
147021cd1389d2ef218b20994b617c57af120841a57fChet Haase         * @param transition The LayoutTransition sending out the event.
147121cd1389d2ef218b20994b617c57af120841a57fChet Haase         * @param container The ViewGroup on which the transition is playing.
14729c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * @param view The View object being affected by the transition animation.
14739c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * @param transitionType The type of transition that is beginning,
14749c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * {@link android.animation.LayoutTransition#APPEARING},
14759c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * {@link android.animation.LayoutTransition#DISAPPEARING},
14769c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * {@link android.animation.LayoutTransition#CHANGE_APPEARING}, or
14779c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * {@link android.animation.LayoutTransition#CHANGE_DISAPPEARING}.
147821cd1389d2ef218b20994b617c57af120841a57fChet Haase         */
147921cd1389d2ef218b20994b617c57af120841a57fChet Haase        public void startTransition(LayoutTransition transition, ViewGroup container,
148021cd1389d2ef218b20994b617c57af120841a57fChet Haase                View view, int transitionType);
148121cd1389d2ef218b20994b617c57af120841a57fChet Haase
148221cd1389d2ef218b20994b617c57af120841a57fChet Haase        /**
14839c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * This event is sent to listeners when any type of transition animation ends.
148421cd1389d2ef218b20994b617c57af120841a57fChet Haase         *
148521cd1389d2ef218b20994b617c57af120841a57fChet Haase         * @param transition The LayoutTransition sending out the event.
148621cd1389d2ef218b20994b617c57af120841a57fChet Haase         * @param container The ViewGroup on which the transition is playing.
14879c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * @param view The View object being affected by the transition animation.
14889c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * @param transitionType The type of transition that is ending,
14899c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * {@link android.animation.LayoutTransition#APPEARING},
14909c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * {@link android.animation.LayoutTransition#DISAPPEARING},
14919c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * {@link android.animation.LayoutTransition#CHANGE_APPEARING}, or
14929c0874408cfc6f6f4e4561973ca5ae52a5982db7Chet Haase         * {@link android.animation.LayoutTransition#CHANGE_DISAPPEARING}.
149321cd1389d2ef218b20994b617c57af120841a57fChet Haase         */
149421cd1389d2ef218b20994b617c57af120841a57fChet Haase        public void endTransition(LayoutTransition transition, ViewGroup container,
149521cd1389d2ef218b20994b617c57af120841a57fChet Haase                View view, int transitionType);
149621cd1389d2ef218b20994b617c57af120841a57fChet Haase    }
149721cd1389d2ef218b20994b617c57af120841a57fChet Haase
1498abb7d66049c176459779a22810b3931d263f68e6Chet Haase}
1499