1733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki/*
2733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * Copyright (C) 2016 The Android Open Source Project
3733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki *
4733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * Licensed under the Apache License, Version 2.0 (the "License");
5733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * you may not use this file except in compliance with the License.
6733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * You may obtain a copy of the License at
7733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki *
8733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki *      http://www.apache.org/licenses/LICENSE-2.0
9733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki *
10733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * Unless required by applicable law or agreed to in writing, software
11733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * distributed under the License is distributed on an "AS IS" BASIS,
12733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * See the License for the specific language governing permissions and
14733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * limitations under the License.
15733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki */
16733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
17733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Arakipackage android.support.transition;
18733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
19a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Arakiimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
21733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Arakiimport android.animation.Animator;
22a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Arakiimport android.animation.AnimatorListenerAdapter;
238158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Arakiimport android.content.Context;
248158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Arakiimport android.content.res.TypedArray;
258158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Arakiimport android.content.res.XmlResourceParser;
26a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Arakiimport android.support.annotation.IntDef;
27733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Arakiimport android.support.annotation.NonNull;
284e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakiimport android.support.annotation.Nullable;
29a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Arakiimport android.support.annotation.RestrictTo;
308158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Arakiimport android.support.v4.content.res.TypedArrayUtils;
318158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Arakiimport android.util.AttributeSet;
32733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Arakiimport android.view.View;
33733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Arakiimport android.view.ViewGroup;
34733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
35a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Arakiimport java.lang.annotation.Retention;
36a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Arakiimport java.lang.annotation.RetentionPolicy;
37a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
38733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki/**
39733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * This transition tracks changes to the visibility of target views in the
40733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * start and end scenes. Visibility is determined not just by the
41733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * {@link View#setVisibility(int)} state of views, but also whether
42733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * views exist in the current view hierarchy. The class is intended to be a
439562a3b639225d406d736b64a12e2d75459259e3Alan Viverette * utility for subclasses such as {@link Fade}, which use this visibility
44733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * information to determine the specific animations to run when visibility
45733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * changes occur. Subclasses should implement one or both of the methods
46733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)},
478158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)} or
488158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki * {@link #onAppear(ViewGroup, View, TransitionValues, TransitionValues)},
498158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki * {@link #onDisappear(ViewGroup, View, TransitionValues, TransitionValues)}.
50733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki */
514e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Arakipublic abstract class Visibility extends Transition {
52733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
534c904b38c763179727b9b5ea7a80454630545663Yuichi Araki    static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
544e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private static final String PROPNAME_PARENT = "android:visibility:parent";
55a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    private static final String PROPNAME_SCREEN_LOCATION = "android:visibility:screenLocation";
56a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
57a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
58a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * Mode used in {@link #setMode(int)} to make the transition
59a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * operate on targets that are appearing. Maybe be combined with
60a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * {@link #MODE_OUT} to target Visibility changes both in and out.
61a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
62a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public static final int MODE_IN = 0x1;
63a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
64a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
65a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * Mode used in {@link #setMode(int)} to make the transition
66a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * operate on targets that are disappearing. Maybe be combined with
67a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * {@link #MODE_IN} to target Visibility changes both in and out.
68a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
69a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public static final int MODE_OUT = 0x2;
70a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
71a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /** @hide */
72a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @RestrictTo(LIBRARY_GROUP)
73a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @IntDef(flag = true, value = {MODE_IN, MODE_OUT})
74a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @Retention(RetentionPolicy.SOURCE)
75a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public @interface Mode {
76a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
774e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
784e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private static final String[] sTransitionProperties = {
794e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            PROPNAME_VISIBILITY,
804e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            PROPNAME_PARENT,
814e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    };
824e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
834e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private static class VisibilityInfo {
844e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        boolean mVisibilityChange;
854e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        boolean mFadeIn;
864e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        int mStartVisibility;
874e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        int mEndVisibility;
884e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        ViewGroup mStartParent;
894e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        ViewGroup mEndParent;
90733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    }
91733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
92a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    private int mMode = MODE_IN | MODE_OUT;
93a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
944e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public Visibility() {
95733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    }
96733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
978158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki    public Visibility(Context context, AttributeSet attrs) {
988158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki        super(context, attrs);
998158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki        TypedArray a = context.obtainStyledAttributes(attrs, Styleable.VISIBILITY_TRANSITION);
1008158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki        @Mode
1018158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki        int mode = TypedArrayUtils.getNamedInt(a, (XmlResourceParser) attrs,
1028158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki                "transitionVisibilityMode",
1038158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki                Styleable.VisibilityTransition.TRANSITION_VISIBILITY_MODE, 0);
1048158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki        a.recycle();
1058158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki        if (mode != 0) {
1068158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki            setMode(mode);
1078158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki        }
1088158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki    }
1098158051cdfef95fc1f22b56bba93b9c610f5ecb1Yuichi Araki
110a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
111a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * Changes the transition to support appearing and/or disappearing Views, depending
112a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * on <code>mode</code>.
113a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *
114a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param mode The behavior supported by this transition, a combination of
115a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *             {@link #MODE_IN} and {@link #MODE_OUT}.
116a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
117a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public void setMode(@Mode int mode) {
118a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if ((mode & ~(MODE_IN | MODE_OUT)) != 0) {
119a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            throw new IllegalArgumentException("Only MODE_IN and MODE_OUT flags are allowed");
120a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
121a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        mMode = mode;
122a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
123a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
124a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
125a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * Returns whether appearing and/or disappearing Views are supported.
126a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *
127a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @return whether appearing and/or disappearing Views are supported. A combination of
128a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * {@link #MODE_IN} and {@link #MODE_OUT}.
129a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
130a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    @Mode
131a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public int getMode() {
132a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        return mMode;
133a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
134a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
1354e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @Nullable
136733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    @Override
1374e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public String[] getTransitionProperties() {
1384e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        return sTransitionProperties;
1394e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
1404e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1414e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private void captureValues(TransitionValues transitionValues) {
1424e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        int visibility = transitionValues.view.getVisibility();
1434e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        transitionValues.values.put(PROPNAME_VISIBILITY, visibility);
1444e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        transitionValues.values.put(PROPNAME_PARENT, transitionValues.view.getParent());
145a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        int[] loc = new int[2];
146a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        transitionValues.view.getLocationOnScreen(loc);
147a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        transitionValues.values.put(PROPNAME_SCREEN_LOCATION, loc);
148733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    }
149733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
150733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    @Override
151733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    public void captureStartValues(@NonNull TransitionValues transitionValues) {
1524e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        captureValues(transitionValues);
1534e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
1544e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1554e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @Override
1564e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public void captureEndValues(@NonNull TransitionValues transitionValues) {
1574e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        captureValues(transitionValues);
158733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    }
159733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
160733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    /**
161733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * Returns whether the view is 'visible' according to the given values
162733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * object. This is determined by testing the same properties in the values
163733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * object that are used to determine whether the object is appearing or
164733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * disappearing in the {@link
165733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * Transition#createAnimator(ViewGroup, TransitionValues, TransitionValues)}
166733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * method. This method can be called by, for example, subclasses that want
167733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * to know whether the object is visible in the same way that Visibility
168733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * determines it for the actual animation.
169733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     *
170733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param values The TransitionValues object that holds the information by
171733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     *               which visibility is determined.
172733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @return True if the view reference by <code>values</code> is visible,
173733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * false otherwise.
174733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     */
175733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    public boolean isVisible(TransitionValues values) {
1764e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        if (values == null) {
1774e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            return false;
1784e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
1794e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        int visibility = (Integer) values.values.get(PROPNAME_VISIBILITY);
1804e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        View parent = (View) values.values.get(PROPNAME_PARENT);
1814e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1824e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        return visibility == View.VISIBLE && parent != null;
1834e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
1844e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
1854e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
1864e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            TransitionValues endValues) {
1874e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        final VisibilityInfo visInfo = new VisibilityInfo();
1884e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        visInfo.mVisibilityChange = false;
1894e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        visInfo.mFadeIn = false;
190a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if (startValues != null && startValues.values.containsKey(PROPNAME_VISIBILITY)) {
1914e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mStartVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
1924e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mStartParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
1934e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        } else {
1944e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mStartVisibility = -1;
1954e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mStartParent = null;
1964e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
197a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if (endValues != null && endValues.values.containsKey(PROPNAME_VISIBILITY)) {
1984e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mEndVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
1994e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mEndParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
2004e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        } else {
2014e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mEndVisibility = -1;
2024e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mEndParent = null;
2034e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
2044e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        if (startValues != null && endValues != null) {
2054e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            if (visInfo.mStartVisibility == visInfo.mEndVisibility
2064e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    && visInfo.mStartParent == visInfo.mEndParent) {
2074e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                return visInfo;
2084e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            } else {
2094e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                if (visInfo.mStartVisibility != visInfo.mEndVisibility) {
2104e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    if (visInfo.mStartVisibility == View.VISIBLE) {
2114e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                        visInfo.mFadeIn = false;
2124e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                        visInfo.mVisibilityChange = true;
2134e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    } else if (visInfo.mEndVisibility == View.VISIBLE) {
2144e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                        visInfo.mFadeIn = true;
2154e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                        visInfo.mVisibilityChange = true;
2164e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    }
2174e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    // no visibilityChange if going between INVISIBLE and GONE
2184e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                } else /* if (visInfo.mStartParent != visInfo.mEndParent) */ {
2194e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    if (visInfo.mEndParent == null) {
2204e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                        visInfo.mFadeIn = false;
2214e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                        visInfo.mVisibilityChange = true;
2224e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    } else if (visInfo.mStartParent == null) {
2234e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                        visInfo.mFadeIn = true;
2244e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                        visInfo.mVisibilityChange = true;
2254e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                    }
2264e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki                }
2274e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            }
228a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        } else if (startValues == null && visInfo.mEndVisibility == View.VISIBLE) {
2294e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mFadeIn = true;
2304e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mVisibilityChange = true;
231a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        } else if (endValues == null && visInfo.mStartVisibility == View.VISIBLE) {
2324e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mFadeIn = false;
2334e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            visInfo.mVisibilityChange = true;
2344e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
2354e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        return visInfo;
2364e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    }
2374e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki
2384e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @Nullable
2394e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @Override
2404e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    public Animator createAnimator(@NonNull ViewGroup sceneRoot,
2414e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            @Nullable TransitionValues startValues, @Nullable TransitionValues endValues) {
2424e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
243a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if (visInfo.mVisibilityChange
244a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                && (visInfo.mStartParent != null || visInfo.mEndParent != null)) {
245a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            if (visInfo.mFadeIn) {
246a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                return onAppear(sceneRoot, startValues, visInfo.mStartVisibility,
247a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                        endValues, visInfo.mEndVisibility);
248a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            } else {
249a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                return onDisappear(sceneRoot, startValues, visInfo.mStartVisibility,
250a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                        endValues, visInfo.mEndVisibility
251a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                );
2524e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki            }
2534e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        }
2544e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        return null;
255733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    }
256733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
257733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    /**
258733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * The default implementation of this method does nothing. Subclasses
259733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * should override if they need to create an Animator when targets appear.
260733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * The method should only be called by the Visibility class; it is
261733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * not intended to be called from external classes.
262733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     *
263733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param sceneRoot       The root of the transition hierarchy
264733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param startValues     The target values in the start scene
265733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param startVisibility The target visibility in the start scene
266733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param endValues       The target values in the end scene
267733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param endVisibility   The target visibility in the end scene
268733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @return An Animator to be started at the appropriate time in the
269733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * overall transition for this scene change. A null value means no animation
270733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * should be run.
271733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     */
2724e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @SuppressWarnings("UnusedParameters")
273733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,
274733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki            TransitionValues endValues, int endVisibility) {
275a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if ((mMode & MODE_IN) != MODE_IN || endValues == null) {
276a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            return null;
277a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
278a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if (startValues == null) {
279a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            View endParent = (View) endValues.view.getParent();
280a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            TransitionValues startParentValues = getMatchedTransitionValues(endParent,
281a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    false);
282a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            TransitionValues endParentValues = getTransitionValues(endParent, false);
283a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            VisibilityInfo parentVisibilityInfo =
284a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    getVisibilityChangeInfo(startParentValues, endParentValues);
285a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            if (parentVisibilityInfo.mVisibilityChange) {
286a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                return null;
287a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            }
288a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
289a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        return onAppear(sceneRoot, endValues.view, startValues, endValues);
290a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
291a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
292a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
293a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * The default implementation of this method returns a null Animator. Subclasses should
294a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * override this method to make targets appear with the desired transition. The
295a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * method should only be called from
296a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
297a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *
298a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param sceneRoot   The root of the transition hierarchy
299a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param view        The View to make appear. This will be in the target scene's View
300a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *                    hierarchy
301a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *                    and
302a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *                    will be VISIBLE.
303a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param startValues The target values in the start scene
304a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param endValues   The target values in the end scene
305a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @return An Animator to be started at the appropriate time in the
306a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * overall transition for this scene change. A null value means no animation
307a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * should be run.
308a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
309a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
310a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            TransitionValues endValues) {
3114e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        return null;
312733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    }
313733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
314733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    /**
315733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * The default implementation of this method does nothing. Subclasses
316733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * should override if they need to create an Animator when targets disappear.
317733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * The method should only be called by the Visibility class; it is
318733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * not intended to be called from external classes.
319733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     *
320733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param sceneRoot       The root of the transition hierarchy
321733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param startValues     The target values in the start scene
322733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param startVisibility The target visibility in the start scene
323733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param endValues       The target values in the end scene
324733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @param endVisibility   The target visibility in the end scene
325733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * @return An Animator to be started at the appropriate time in the
326733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * overall transition for this scene change. A null value means no animation
327733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     * should be run.
328733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki     */
3294e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki    @SuppressWarnings("UnusedParameters")
330733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,
331733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki            int startVisibility, TransitionValues endValues, int endVisibility) {
332a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if ((mMode & MODE_OUT) != MODE_OUT) {
333a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            return null;
334a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
335a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
336a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        View startView = (startValues != null) ? startValues.view : null;
337a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        View endView = (endValues != null) ? endValues.view : null;
338a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        View overlayView = null;
339a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        View viewToKeep = null;
340a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if (endView == null || endView.getParent() == null) {
341a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            if (endView != null) {
342a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                // endView was removed from its parent - add it to the overlay
343a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                overlayView = endView;
344a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            } else if (startView != null) {
345a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                // endView does not exist. Use startView only under certain
346a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                // conditions, because placing a view in an overlay necessitates
347a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                // it being removed from its current parent
348a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                if (startView.getParent() == null) {
349a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    // no parent - safe to use
350a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    overlayView = startView;
351a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                } else if (startView.getParent() instanceof View) {
352a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    View startParent = (View) startView.getParent();
353a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    TransitionValues startParentValues = getTransitionValues(startParent, true);
354a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    TransitionValues endParentValues = getMatchedTransitionValues(startParent,
355a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                            true);
356a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    VisibilityInfo parentVisibilityInfo =
357a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                            getVisibilityChangeInfo(startParentValues, endParentValues);
358a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    if (!parentVisibilityInfo.mVisibilityChange) {
359a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                        overlayView = TransitionUtils.copyViewImage(sceneRoot, startView,
360a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                                startParent);
361a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    } else if (startParent.getParent() == null) {
362a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                        int id = startParent.getId();
363a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                        if (id != View.NO_ID && sceneRoot.findViewById(id) != null
364a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                                && mCanRemoveViews) {
365a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                            // no parent, but its parent is unparented  but the parent
366a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                            // hierarchy has been replaced by a new hierarchy with the same id
367a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                            // and it is safe to un-parent startView
368a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                            overlayView = startView;
369a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                        }
370a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    }
371a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                }
372a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            }
373a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        } else {
374a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            // visibility change
375a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            if (endVisibility == View.INVISIBLE) {
376a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                viewToKeep = endView;
377a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            } else {
378a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                // Becoming GONE
379a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                if (startView == endView) {
380a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    viewToKeep = endView;
381a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                } else {
382a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    overlayView = startView;
383a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                }
384a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            }
385a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
386a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        final int finalVisibility = endVisibility;
387a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
388a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if (overlayView != null && startValues != null) {
389a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            // TODO: Need to do this for general case of adding to overlay
390a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            int[] screenLoc = (int[]) startValues.values.get(PROPNAME_SCREEN_LOCATION);
391a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            int screenX = screenLoc[0];
392a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            int screenY = screenLoc[1];
393a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            int[] loc = new int[2];
394a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            sceneRoot.getLocationOnScreen(loc);
395a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
396a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
397a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            final ViewGroupOverlayImpl overlay = ViewGroupUtils.getOverlay(sceneRoot);
398a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            overlay.add(overlayView);
399a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            Animator animator = onDisappear(sceneRoot, overlayView, startValues, endValues);
400a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            if (animator == null) {
401a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                overlay.remove(overlayView);
402a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            } else {
403a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                final View finalOverlayView = overlayView;
404a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                animator.addListener(new AnimatorListenerAdapter() {
405a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    @Override
406a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    public void onAnimationEnd(Animator animation) {
407a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                        overlay.remove(finalOverlayView);
408a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                    }
409a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki                });
410a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            }
411a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            return animator;
412a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
413a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
414a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        if (viewToKeep != null) {
415ce318dbf0020462e651049fd4f32dc226b656f5bAurimas Liutikas            int originalVisibility = viewToKeep.getVisibility();
416928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            ViewUtils.setTransitionVisibility(viewToKeep, View.VISIBLE);
417a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues);
418a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            if (animator != null) {
419928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                DisappearListener disappearListener = new DisappearListener(viewToKeep,
420928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                        finalVisibility, true);
421928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                animator.addListener(disappearListener);
422928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                AnimatorUtils.addPauseListener(animator, disappearListener);
423928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                addListener(disappearListener);
424a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            } else {
425928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                ViewUtils.setTransitionVisibility(viewToKeep, originalVisibility);
426a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            }
427a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            return animator;
428a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        }
429a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki        return null;
430a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    }
431a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki
432a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    /**
433a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * The default implementation of this method returns a null Animator. Subclasses should
434a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * override this method to make targets disappear with the desired transition. The
435a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * method should only be called from
436a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
437a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *
438a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param sceneRoot   The root of the transition hierarchy
439a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param view        The View to make disappear. This will be in the target scene's View
440a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *                    hierarchy or in an {@link android.view.ViewGroupOverlay} and will be
441a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     *                    VISIBLE.
442a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param startValues The target values in the start scene
443a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @param endValues   The target values in the end scene
444a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * @return An Animator to be started at the appropriate time in the
445a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * overall transition for this scene change. A null value means no animation
446a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     * should be run.
447a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki     */
448a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
449a6f2ebe33d03c42114b0082720cf9c42f7dad5a3Yuichi Araki            TransitionValues endValues) {
4504e5a72756eb66c31baf1a3054c66520f1c3f5b8cYuichi Araki        return null;
451733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    }
452733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
453756a17bb7580d5bdbb4826e81b074ca5fedba1f5Yuichi Araki    @Override
454dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki    public boolean isTransitionRequired(TransitionValues startValues, TransitionValues newValues) {
455dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki        if (startValues == null && newValues == null) {
456756a17bb7580d5bdbb4826e81b074ca5fedba1f5Yuichi Araki            return false;
457756a17bb7580d5bdbb4826e81b074ca5fedba1f5Yuichi Araki        }
458dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki        if (startValues != null && newValues != null
459dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki                && newValues.values.containsKey(PROPNAME_VISIBILITY)
460dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki                != startValues.values.containsKey(PROPNAME_VISIBILITY)) {
461dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki            // The transition wasn't targeted in either the start or end, so it couldn't
462dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki            // have changed.
463dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki            return false;
464dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki        }
465dfbc6c9b02b6eba0f537185aaa4e00b2f31f1a74Yuichi Araki        VisibilityInfo changeInfo = getVisibilityChangeInfo(startValues, newValues);
466756a17bb7580d5bdbb4826e81b074ca5fedba1f5Yuichi Araki        return changeInfo.mVisibilityChange && (changeInfo.mStartVisibility == View.VISIBLE
467756a17bb7580d5bdbb4826e81b074ca5fedba1f5Yuichi Araki                || changeInfo.mEndVisibility == View.VISIBLE);
468756a17bb7580d5bdbb4826e81b074ca5fedba1f5Yuichi Araki    }
469756a17bb7580d5bdbb4826e81b074ca5fedba1f5Yuichi Araki
470928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki    private static class DisappearListener extends AnimatorListenerAdapter
471928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            implements TransitionListener, AnimatorUtilsApi14.AnimatorPauseListenerCompat {
472928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
473928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        private final View mView;
474928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        private final int mFinalVisibility;
475928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        private final ViewGroup mParent;
476928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        private final boolean mSuppressLayout;
477928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
478928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        private boolean mLayoutSuppressed;
479928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        boolean mCanceled = false;
480928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
481928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        DisappearListener(View view, int finalVisibility, boolean suppressLayout) {
482928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            mView = view;
483928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            mFinalVisibility = finalVisibility;
484928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            mParent = (ViewGroup) view.getParent();
485928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            mSuppressLayout = suppressLayout;
486928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            // Prevent a layout from including mView in its calculation.
487928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            suppressLayout(true);
488928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
489928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
490928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        // This overrides both AnimatorListenerAdapter and
491928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        // AnimatorUtilsApi14.AnimatorPauseListenerCompat
492928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
493928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onAnimationPause(Animator animation) {
494928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            if (!mCanceled) {
495928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                ViewUtils.setTransitionVisibility(mView, mFinalVisibility);
496928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            }
497928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
498928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
499928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        // This overrides both AnimatorListenerAdapter and
500928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        // AnimatorUtilsApi14.AnimatorPauseListenerCompat
501928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
502928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onAnimationResume(Animator animation) {
503928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            if (!mCanceled) {
504928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                ViewUtils.setTransitionVisibility(mView, View.VISIBLE);
505928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            }
506928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
507928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
508928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
509928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onAnimationCancel(Animator animation) {
510928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            mCanceled = true;
511928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
512928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
513928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
514928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onAnimationRepeat(Animator animation) {
515928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
516928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
517928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
518928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onAnimationStart(Animator animation) {
519928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
520928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
521928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
522928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onAnimationEnd(Animator animation) {
523928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            hideViewWhenNotCanceled();
524928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
525928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
526928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
527928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onTransitionStart(@NonNull Transition transition) {
528928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            // Do nothing
529928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
530928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
531928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
532928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onTransitionEnd(@NonNull Transition transition) {
533928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            hideViewWhenNotCanceled();
534928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            transition.removeListener(this);
535928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
536928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
537928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
538928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onTransitionCancel(@NonNull Transition transition) {
539928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
540928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
541928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
542928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onTransitionPause(@NonNull Transition transition) {
543928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            suppressLayout(false);
544928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
545928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
546928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        @Override
547928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        public void onTransitionResume(@NonNull Transition transition) {
548928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            suppressLayout(true);
549928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
550928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
551928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        private void hideViewWhenNotCanceled() {
552928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            if (!mCanceled) {
553928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                // Recreate the parent's display list in case it includes mView.
554928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                ViewUtils.setTransitionVisibility(mView, mFinalVisibility);
555928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                if (mParent != null) {
556928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                    mParent.invalidate();
557928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                }
558928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            }
559928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            // Layout is allowed now that the View is in its final state
560928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            suppressLayout(false);
561928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
562928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
563928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        private void suppressLayout(boolean suppress) {
564928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            if (mSuppressLayout && mLayoutSuppressed != suppress && mParent != null) {
565928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                mLayoutSuppressed = suppress;
566928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki                ViewGroupUtils.suppressLayout(mParent, suppress);
567928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki            }
568928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki        }
569928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki    }
570928ae3c90e1410c734136bb39d55517efc79714fYuichi Araki
571733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki    // TODO: Implement API 23; isTransitionRequired
572733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki
573733b5aaadf1b1f5dc3038876dbfbabb79f649b03Yuichi Araki}
574