1faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/*
2faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Copyright (C) 2013 The Android Open Source Project
3faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
4faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * you may not use this file except in compliance with the License.
6faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * You may obtain a copy of the License at
7faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
8faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase *
10faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * Unless required by applicable law or agreed to in writing, software
11faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * See the License for the specific language governing permissions and
14faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * limitations under the License.
15faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */
166ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase
17d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haasepackage android.transition;
18faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
19faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.animation.Animator;
20fcfe531e742bd1731664080cb2ed3e66189d7f17George Mountimport android.animation.Animator.AnimatorListener;
21fcfe531e742bd1731664080cb2ed3e66189d7f17George Mountimport android.animation.Animator.AnimatorPauseListener;
227764b920f21e0b9250122ff26533d5dac98df6b3George Mountimport android.annotation.IntDef;
23ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.content.Context;
24ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.content.res.TypedArray;
25ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.util.AttributeSet;
26faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.View;
27faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haaseimport android.view.ViewGroup;
28fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
297764b920f21e0b9250122ff26533d5dac98df6b3George Mountimport com.android.internal.R;
307764b920f21e0b9250122ff26533d5dac98df6b3George Mount
317764b920f21e0b9250122ff26533d5dac98df6b3George Mountimport java.lang.annotation.Retention;
327764b920f21e0b9250122ff26533d5dac98df6b3George Mountimport java.lang.annotation.RetentionPolicy;
337764b920f21e0b9250122ff26533d5dac98df6b3George Mount
34faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase/**
35faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * This transition tracks changes to the visibility of target views in the
36faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * start and end scenes. Visibility is determined not just by the
37faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * {@link View#setVisibility(int)} state of views, but also whether
38faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * views exist in the current view hierarchy. The class is intended to be a
39faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * utility for subclasses such as {@link Fade}, which use this visibility
40faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase * information to determine the specific animations to run when visibility
4135a457a3bac0851a1fabd6cda58d1ea67f997b33Chet Haase * changes occur. Subclasses should implement one or both of the methods
42d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)},
43d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)} or
44d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * {@link #onAppear(ViewGroup, View, TransitionValues, TransitionValues)},
45d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount * {@link #onDisappear(ViewGroup, View, TransitionValues, TransitionValues)}.
46faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase */
47faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haasepublic abstract class Visibility extends Transition {
48faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
496ceac2eafbb43dafd18bf547fee6fe51aee6b59bGeorge Mount    static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
50faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    private static final String PROPNAME_PARENT = "android:visibility:parent";
51d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount    private static final String PROPNAME_SCREEN_LOCATION = "android:visibility:screenLocation";
52d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount
537764b920f21e0b9250122ff26533d5dac98df6b3George Mount    /** @hide */
547764b920f21e0b9250122ff26533d5dac98df6b3George Mount    @Retention(RetentionPolicy.SOURCE)
557764b920f21e0b9250122ff26533d5dac98df6b3George Mount    @IntDef(flag=true, value={MODE_IN, MODE_OUT})
567764b920f21e0b9250122ff26533d5dac98df6b3George Mount    @interface VisibilityMode {}
577764b920f21e0b9250122ff26533d5dac98df6b3George Mount
5818ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount    /**
5918ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     * Mode used in {@link #setMode(int)} to make the transition
6018ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     * operate on targets that are appearing. Maybe be combined with
61ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount     * {@link #MODE_OUT} to target Visibility changes both in and out.
6218ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     */
63ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount    public static final int MODE_IN = 0x1;
6418ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount
6518ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount    /**
6618ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     * Mode used in {@link #setMode(int)} to make the transition
6718ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     * operate on targets that are disappearing. Maybe be combined with
68ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount     * {@link #MODE_IN} to target Visibility changes both in and out.
6918ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     */
70ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount    public static final int MODE_OUT = 0x2;
7118ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount
72af78bdd615ecd5ce9d41a6160ce9f53fa269b119Chet Haase    private static final String[] sTransitionProperties = {
73199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase            PROPNAME_VISIBILITY,
7420559079ab05aa5e976bb0f7aa63fd9e6868f02eGeorge Mount            PROPNAME_PARENT,
75199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    };
76faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
776ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase    private static class VisibilityInfo {
786ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        boolean visibilityChange;
796ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        boolean fadeIn;
806ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        int startVisibility;
816ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        int endVisibility;
8235a457a3bac0851a1fabd6cda58d1ea67f997b33Chet Haase        ViewGroup startParent;
8335a457a3bac0851a1fabd6cda58d1ea67f997b33Chet Haase        ViewGroup endParent;
846ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase    }
856ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase
86ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount    private int mMode = MODE_IN | MODE_OUT;
871349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount    private boolean mSuppressLayout = true;
8818ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount
89ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    public Visibility() {}
90ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
91ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    public Visibility(Context context, AttributeSet attrs) {
92ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        super(context, attrs);
93ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VisibilityTransition);
943b2cd1d59fd894ac67a044c6c540fa69360a34a2Craig Mautner        int mode = a.getInt(R.styleable.VisibilityTransition_transitionVisibilityMode, 0);
95ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        a.recycle();
96ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        if (mode != 0) {
97ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount            setMode(mode);
98ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        }
99ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    }
100ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
10118ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount    /**
1021349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount     * This tells the Visibility transition to suppress layout during the transition and release
1031349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount     * the suppression after the transition.
1041349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount     * @hide
1051349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount     */
1061349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount    public void setSuppressLayout(boolean suppress) {
1071349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount        this.mSuppressLayout = suppress;
1081349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount    }
1091349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount
1101349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount    /**
11118ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     * Changes the transition to support appearing and/or disappearing Views, depending
11218ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     * on <code>mode</code>.
11318ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     *
11418ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     * @param mode The behavior supported by this transition, a combination of
115ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount     *             {@link #MODE_IN} and {@link #MODE_OUT}.
1163b2cd1d59fd894ac67a044c6c540fa69360a34a2Craig Mautner     * @attr ref android.R.styleable#VisibilityTransition_transitionVisibilityMode
11718ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount     */
1187764b920f21e0b9250122ff26533d5dac98df6b3George Mount    public void setMode(@VisibilityMode int mode) {
119ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount        if ((mode & ~(MODE_IN | MODE_OUT)) != 0) {
120ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount            throw new IllegalArgumentException("Only MODE_IN and MODE_OUT flags are allowed");
12118ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount        }
12218ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount        mMode = mode;
12318ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount    }
12418ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount
125ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    /**
126ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount     * Returns whether appearing and/or disappearing Views are supported.
127ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount     *
128ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount     * Returns whether appearing and/or disappearing Views are supported. A combination of
129ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount     *         {@link #MODE_IN} and {@link #MODE_OUT}.
1303b2cd1d59fd894ac67a044c6c540fa69360a34a2Craig Mautner     * @attr ref android.R.styleable#VisibilityTransition_transitionVisibilityMode
131ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount     */
1327764b920f21e0b9250122ff26533d5dac98df6b3George Mount    @VisibilityMode
133ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    public int getMode() {
134ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        return mMode;
135ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    }
136ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
137faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    @Override
138199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    public String[] getTransitionProperties() {
139199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        return sTransitionProperties;
140199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    }
141199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase
142629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount    private void captureValues(TransitionValues transitionValues) {
143629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount        int visibility = transitionValues.view.getVisibility();
144d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        transitionValues.values.put(PROPNAME_VISIBILITY, visibility);
145d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase        transitionValues.values.put(PROPNAME_PARENT, transitionValues.view.getParent());
146d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        int[] loc = new int[2];
147d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        transitionValues.view.getLocationOnScreen(loc);
148d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        transitionValues.values.put(PROPNAME_SCREEN_LOCATION, loc);
149d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    }
150d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase
151d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    @Override
152d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public void captureStartValues(TransitionValues transitionValues) {
153629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount        captureValues(transitionValues);
154d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    }
155d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase
156199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    @Override
157d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public void captureEndValues(TransitionValues transitionValues) {
158629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount        captureValues(transitionValues);
159faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
160faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
161199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    /**
162199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * Returns whether the view is 'visible' according to the given values
163199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * object. This is determined by testing the same properties in the values
164199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * object that are used to determine whether the object is appearing or
165199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * disappearing in the {@link
166d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * Transition#createAnimator(ViewGroup, TransitionValues, TransitionValues)}
167199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * method. This method can be called by, for example, subclasses that want
168199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * to know whether the object is visible in the same way that Visibility
169199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * determines it for the actual animation.
170199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     *
171199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * @param values The TransitionValues object that holds the information by
172199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * which visibility is determined.
173199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * @return True if the view reference by <code>values</code> is visible,
174199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     * false otherwise.
175199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase     */
176199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    public boolean isVisible(TransitionValues values) {
177199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        if (values == null) {
178199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase            return false;
179199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        }
180199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        int visibility = (Integer) values.values.get(PROPNAME_VISIBILITY);
181199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        View parent = (View) values.values.get(PROPNAME_PARENT);
182199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase
183199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase        return visibility == View.VISIBLE && parent != null;
184199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase    }
185199acdfcc98e852975dd7edfbcb822ba5e73146fChet Haase
1860653f2596f769956f6c1bf491505979ec40453e3Todd Volkert    private static VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
187faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            TransitionValues endValues) {
1887660d121b2ef21164ed33e6091e5dd50f5d0f939Chet Haase        final VisibilityInfo visInfo = new VisibilityInfo();
1896ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        visInfo.visibilityChange = false;
1906ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        visInfo.fadeIn = false;
19131a217290cf376d0573fc36e21c8940987485019George Mount        if (startValues != null && startValues.values.containsKey(PROPNAME_VISIBILITY)) {
1926ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
19335a457a3bac0851a1fabd6cda58d1ea67f997b33Chet Haase            visInfo.startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
194faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } else {
1956ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.startVisibility = -1;
1966ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.startParent = null;
197faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
19831a217290cf376d0573fc36e21c8940987485019George Mount        if (endValues != null && endValues.values.containsKey(PROPNAME_VISIBILITY)) {
1996ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
20035a457a3bac0851a1fabd6cda58d1ea67f997b33Chet Haase            visInfo.endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
201faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        } else {
2026ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.endVisibility = -1;
2036ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.endParent = null;
204faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
205faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        if (startValues != null && endValues != null) {
2066ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            if (visInfo.startVisibility == visInfo.endVisibility &&
2076ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                    visInfo.startParent == visInfo.endParent) {
2086ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                return visInfo;
209faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            } else {
2106ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                if (visInfo.startVisibility != visInfo.endVisibility) {
2116ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                    if (visInfo.startVisibility == View.VISIBLE) {
2126ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                        visInfo.fadeIn = false;
2136ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                        visInfo.visibilityChange = true;
2146ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                    } else if (visInfo.endVisibility == View.VISIBLE) {
2156ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                        visInfo.fadeIn = true;
2166ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                        visInfo.visibilityChange = true;
217faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    }
218faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    // no visibilityChange if going between INVISIBLE and GONE
2196ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                } else if (visInfo.startParent != visInfo.endParent) {
2206ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                    if (visInfo.endParent == null) {
2216ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                        visInfo.fadeIn = false;
2226ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                        visInfo.visibilityChange = true;
2236ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                    } else if (visInfo.startParent == null) {
2246ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                        visInfo.fadeIn = true;
2256ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase                        visInfo.visibilityChange = true;
226faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                    }
227faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase                }
228faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
22979b2781aa763cbd770f690c16af4448139f37061George Mount        } else if (startValues == null && visInfo.endVisibility == View.VISIBLE) {
2306ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.fadeIn = true;
2316ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.visibilityChange = true;
23279b2781aa763cbd770f690c16af4448139f37061George Mount        } else if (endValues == null && visInfo.startVisibility == View.VISIBLE) {
2336ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.fadeIn = false;
2346ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            visInfo.visibilityChange = true;
235faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
2366ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        return visInfo;
237faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
238faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
239faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    @Override
240d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
241faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            TransitionValues endValues) {
2426ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
24330da61d477bcb6cc7718f9516c444359352fe148George Mount        if (visInfo.visibilityChange
24430da61d477bcb6cc7718f9516c444359352fe148George Mount                && (visInfo.startParent != null || visInfo.endParent != null)) {
24530da61d477bcb6cc7718f9516c444359352fe148George Mount            if (visInfo.fadeIn) {
24630da61d477bcb6cc7718f9516c444359352fe148George Mount                return onAppear(sceneRoot, startValues, visInfo.startVisibility,
24730da61d477bcb6cc7718f9516c444359352fe148George Mount                        endValues, visInfo.endVisibility);
24830da61d477bcb6cc7718f9516c444359352fe148George Mount            } else {
24930da61d477bcb6cc7718f9516c444359352fe148George Mount                return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
25030da61d477bcb6cc7718f9516c444359352fe148George Mount                        endValues, visInfo.endVisibility
25130da61d477bcb6cc7718f9516c444359352fe148George Mount                );
252faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase            }
253faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        }
254faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase        return null;
255faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
256faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
257faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
258d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * The default implementation of this method calls
259d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * {@link #onAppear(ViewGroup, View, TransitionValues, TransitionValues)}.
260d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * Subclasses should override this method or
261d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * {@link #onAppear(ViewGroup, View, TransitionValues, TransitionValues)}.
262d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * if they need to create an Animator when targets appear.
263d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * The method should only be called by the Visibility class; it is
264d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * not intended to be called from external classes.
265faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     *
266d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param sceneRoot The root of the transition hierarchy
267d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param startValues The target values in the start scene
268d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param startVisibility The target visibility in the start scene
269d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param endValues The target values in the end scene
270d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param endVisibility The target visibility in the end scene
271d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @return An Animator to be started at the appropriate time in the
272d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * overall transition for this scene change. A null value means no animation
273d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * should be run.
274faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
275d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public Animator onAppear(ViewGroup sceneRoot,
2766ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            TransitionValues startValues, int startVisibility,
2776ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            TransitionValues endValues, int endVisibility) {
278ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount        if ((mMode & MODE_IN) != MODE_IN || endValues == null) {
27918ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount            return null;
28018ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount        }
281e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout        if (startValues == null) {
282e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout            VisibilityInfo parentVisibilityInfo = null;
283e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout            View endParent = (View) endValues.view.getParent();
284e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout            TransitionValues startParentValues = getMatchedTransitionValues(endParent,
285e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout                                                                            false);
286e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout            TransitionValues endParentValues = getTransitionValues(endParent, false);
287e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout            parentVisibilityInfo =
288e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout                getVisibilityChangeInfo(startParentValues, endParentValues);
289e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout            if (parentVisibilityInfo.visibilityChange) {
290e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout                return null;
291e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout            }
292e988ee1eb2cc0cd345e42bcc549363a0e8c339aaCraig Stout        }
293d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        return onAppear(sceneRoot, endValues.view, startValues, endValues);
294d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount    }
295d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount
296d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount    /**
297d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * The default implementation of this method returns a null Animator. Subclasses should
298d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * override this method to make targets appear with the desired transition. The
299d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * method should only be called from
300d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
301d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     *
302d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @param sceneRoot The root of the transition hierarchy
303d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @param view The View to make appear. This will be in the target scene's View hierarchy and
304d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     *             will be VISIBLE.
305d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @param startValues The target values in the start scene
306d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @param endValues The target values in the end scene
307d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @return An Animator to be started at the appropriate time in the
308d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * overall transition for this scene change. A null value means no animation
309d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * should be run.
310d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     */
311d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
312d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            TransitionValues endValues) {
3132ea7f8b9c5f903050d42c1af57406bf528979f45Chet Haase        return null;
314faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    }
315faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase
316faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase    /**
317d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * Subclasses should override this method or
318d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * {@link #onDisappear(ViewGroup, View, TransitionValues, TransitionValues)}
319d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * if they need to create an Animator when targets disappear.
320d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * The method should only be called by the Visibility class; it is
321d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * not intended to be called from external classes.
322d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * <p>
323d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * The default implementation of this method attempts to find a View to use to call
324d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * {@link #onDisappear(ViewGroup, View, TransitionValues, TransitionValues)},
325d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * based on the situation of the View in the View hierarchy. For example,
326d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * if a View was simply removed from its parent, then the View will be added
327d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * into a {@link android.view.ViewGroupOverlay} and passed as the <code>view</code>
328d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * parameter in {@link #onDisappear(ViewGroup, View, TransitionValues, TransitionValues)}.
329d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * If a visible View is changed to be {@link View#GONE} or {@link View#INVISIBLE},
330d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * then it can be used as the <code>view</code> and the visibility will be changed
331d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * to {@link View#VISIBLE} for the duration of the animation. However, if a View
332d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * is in a hierarchy which is also altering its visibility, the situation can be
333d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * more complicated. In general, if a view that is no longer in the hierarchy in
334d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * the end scene still has a parent (so its parent hierarchy was removed, but it
335d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * was not removed from its parent), then it will be left alone to avoid side-effects from
336d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * improperly removing it from its parent. The only exception to this is if
337d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * the previous {@link Scene} was {@link Scene#getSceneForLayout(ViewGroup, int,
338d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * android.content.Context) created from a layout resource file}, then it is considered
339d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * safe to un-parent the starting scene view in order to make it disappear.</p>
3406ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase     *
341d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param sceneRoot The root of the transition hierarchy
342d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param startValues The target values in the start scene
343d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param startVisibility The target visibility in the start scene
344d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param endValues The target values in the end scene
345d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @param endVisibility The target visibility in the end scene
346d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * @return An Animator to be started at the appropriate time in the
347d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * overall transition for this scene change. A null value means no animation
348d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase     * should be run.
349faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase     */
350d82c8ac4db7091d2e976af4c89a1734465d20cd2Chet Haase    public Animator onDisappear(ViewGroup sceneRoot,
3516ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            TransitionValues startValues, int startVisibility,
3526ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase            TransitionValues endValues, int endVisibility) {
353ad88e1b1b2c57fa56bde68764b22240d145fa0efGeorge Mount        if ((mMode & MODE_OUT) != MODE_OUT) {
35418ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount            return null;
35518ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount        }
35618ab79967ce8bcde4b1507164ac8186e5135622eGeorge Mount
357d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        View startView = (startValues != null) ? startValues.view : null;
358d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        View endView = (endValues != null) ? endValues.view : null;
359d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        View overlayView = null;
360d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        View viewToKeep = null;
361d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        if (endView == null || endView.getParent() == null) {
362d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            if (endView != null) {
363d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                // endView was removed from its parent - add it to the overlay
364d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                overlayView = endView;
365d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            } else if (startView != null) {
366d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                // endView does not exist. Use startView only under certain
367d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                // conditions, because placing a view in an overlay necessitates
368d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                // it being removed from its current parent
369d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                if (startView.getParent() == null) {
370d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                    // no parent - safe to use
371d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                    overlayView = startView;
372d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                } else if (startView.getParent() instanceof View) {
373d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                    View startParent = (View) startView.getParent();
37479b2781aa763cbd770f690c16af4448139f37061George Mount                    TransitionValues startParentValues = getTransitionValues(startParent, true);
3759f1ac3976ea3aa08c20c06fa6678e367e1ed424dGeorge Mount                    TransitionValues endParentValues = getMatchedTransitionValues(startParent,
3769f1ac3976ea3aa08c20c06fa6678e367e1ed424dGeorge Mount                            true);
37779b2781aa763cbd770f690c16af4448139f37061George Mount                    VisibilityInfo parentVisibilityInfo =
37879b2781aa763cbd770f690c16af4448139f37061George Mount                            getVisibilityChangeInfo(startParentValues, endParentValues);
37979b2781aa763cbd770f690c16af4448139f37061George Mount                    if (!parentVisibilityInfo.visibilityChange) {
38079b2781aa763cbd770f690c16af4448139f37061George Mount                        overlayView = TransitionUtils.copyViewImage(sceneRoot, startView,
38179b2781aa763cbd770f690c16af4448139f37061George Mount                                startParent);
382d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                    } else if (startParent.getParent() == null) {
383d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                        int id = startParent.getId();
384d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                        if (id != View.NO_ID && sceneRoot.findViewById(id) != null
385d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                                && mCanRemoveViews) {
386d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                            // no parent, but its parent is unparented  but the parent
387d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                            // hierarchy has been replaced by a new hierarchy with the same id
388d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                            // and it is safe to un-parent startView
389d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                            overlayView = startView;
390d4c3c91dd0757eec9703ef90ea4c5a7ee99f18caGeorge Mount                        }
391d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                    }
392d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                }
393d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            }
394d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        } else {
395d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            // visibility change
396d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            if (endVisibility == View.INVISIBLE) {
397d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                viewToKeep = endView;
398d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            } else {
399d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                // Becoming GONE
400d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                if (startView == endView) {
401d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                    viewToKeep = endView;
402d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                } else {
403d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                    overlayView = startView;
404d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                }
405d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            }
406d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        }
407d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        final int finalVisibility = endVisibility;
408d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        final ViewGroup finalSceneRoot = sceneRoot;
409d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount
410d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        if (overlayView != null) {
411d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            // TODO: Need to do this for general case of adding to overlay
412d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            int[] screenLoc = (int[]) startValues.values.get(PROPNAME_SCREEN_LOCATION);
413d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            int screenX = screenLoc[0];
414d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            int screenY = screenLoc[1];
415d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            int[] loc = new int[2];
416d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            sceneRoot.getLocationOnScreen(loc);
417d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
418d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
419d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            sceneRoot.getOverlay().add(overlayView);
420d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            Animator animator = onDisappear(sceneRoot, overlayView, startValues, endValues);
421d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            if (animator == null) {
422d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                sceneRoot.getOverlay().remove(overlayView);
423d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            } else {
424d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                final View finalOverlayView = overlayView;
425fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount                addListener(new TransitionListenerAdapter() {
426d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                    @Override
427fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount                    public void onTransitionEnd(Transition transition) {
428d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                        finalSceneRoot.getOverlay().remove(finalOverlayView);
42925f98a4c0156ec40d1d92cfe5a24459d9ffa6f91George Mount                        transition.removeListener(this);
430d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                    }
431d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount                });
432d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            }
433d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            return animator;
434d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        }
435d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount
436d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        if (viewToKeep != null) {
437629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount            int originalVisibility = viewToKeep.getVisibility();
438629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount            viewToKeep.setTransitionVisibility(View.VISIBLE);
439d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues);
440b5ef7f8c6d4629b2998de6c0b27bc1a4779b3e49George Mount            if (animator != null) {
441fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount                DisappearListener disappearListener = new DisappearListener(viewToKeep,
4421349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount                        finalVisibility, mSuppressLayout);
443fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount                animator.addListener(disappearListener);
4440b056a0ac3147b4a856b342b8fe25c745cf21058George Mount                animator.addPauseListener(disappearListener);
445fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount                addListener(disappearListener);
446629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount            } else {
447e5a93aa81ce79bf7fa529b09b50d7473f07a74a2George Mount                viewToKeep.setTransitionVisibility(originalVisibility);
448d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            }
449d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            return animator;
450d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        }
451d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount        return null;
452d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount    }
453d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount
4544c20ea29728a80b42487b3ba1600d11d5ea47bccGeorge Mount    @Override
455aef1ae33915471983f10342dfbf6e37cb6f8c7a5George Mount    public boolean isTransitionRequired(TransitionValues startValues, TransitionValues newValues) {
456aef1ae33915471983f10342dfbf6e37cb6f8c7a5George Mount        if (startValues == null && newValues == null) {
4574c20ea29728a80b42487b3ba1600d11d5ea47bccGeorge Mount            return false;
4584c20ea29728a80b42487b3ba1600d11d5ea47bccGeorge Mount        }
459aef1ae33915471983f10342dfbf6e37cb6f8c7a5George Mount        if (startValues != null && newValues != null &&
460cba01b2310e78fc2114ceed285f4e134469ae62bGeorge Mount                newValues.values.containsKey(PROPNAME_VISIBILITY) !=
461aef1ae33915471983f10342dfbf6e37cb6f8c7a5George Mount                        startValues.values.containsKey(PROPNAME_VISIBILITY)) {
462cba01b2310e78fc2114ceed285f4e134469ae62bGeorge Mount            // The transition wasn't targeted in either the start or end, so it couldn't
463cba01b2310e78fc2114ceed285f4e134469ae62bGeorge Mount            // have changed.
464cba01b2310e78fc2114ceed285f4e134469ae62bGeorge Mount            return false;
465cba01b2310e78fc2114ceed285f4e134469ae62bGeorge Mount        }
466aef1ae33915471983f10342dfbf6e37cb6f8c7a5George Mount        VisibilityInfo changeInfo = getVisibilityChangeInfo(startValues, newValues);
4674c20ea29728a80b42487b3ba1600d11d5ea47bccGeorge Mount        return changeInfo.visibilityChange && (changeInfo.startVisibility == View.VISIBLE ||
468cba01b2310e78fc2114ceed285f4e134469ae62bGeorge Mount                changeInfo.endVisibility == View.VISIBLE);
4694c20ea29728a80b42487b3ba1600d11d5ea47bccGeorge Mount    }
4704c20ea29728a80b42487b3ba1600d11d5ea47bccGeorge Mount
471d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount    /**
472d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * The default implementation of this method returns a null Animator. Subclasses should
473d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * override this method to make targets disappear with the desired transition. The
474d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * method should only be called from
475d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
476d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     *
477d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @param sceneRoot The root of the transition hierarchy
478d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @param view The View to make disappear. This will be in the target scene's View
479d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     *             hierarchy or in an {@link android.view.ViewGroupOverlay} and will be
480d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     *             VISIBLE.
481d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @param startValues The target values in the start scene
482d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @param endValues The target values in the end scene
483d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * @return An Animator to be started at the appropriate time in the
484d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * overall transition for this scene change. A null value means no animation
485d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     * should be run.
486d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount     */
487d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
488d6107a3170df61d9e776fcd5666acfc9135c6f16George Mount            TransitionValues endValues) {
4896ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase        return null;
4906ebe3de331efd00ba23bc4191d4a82cfa4c39160Chet Haase    }
491fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
492fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount    private static class DisappearListener
493fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            extends TransitionListenerAdapter implements AnimatorListener, AnimatorPauseListener {
494fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        private final View mView;
495fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        private final int mFinalVisibility;
49621290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount        private final ViewGroup mParent;
4971349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount        private final boolean mSuppressLayout;
498fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
499a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount        private boolean mLayoutSuppressed;
500fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        boolean mCanceled = false;
501fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
5021349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount        public DisappearListener(View view, int finalVisibility, boolean suppressLayout) {
503fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            this.mView = view;
504fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            this.mFinalVisibility = finalVisibility;
50521290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount            this.mParent = (ViewGroup) view.getParent();
5061349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount            this.mSuppressLayout = suppressLayout;
507a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount            // Prevent a layout from including mView in its calculation.
508a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount            suppressLayout(true);
509fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
510fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
511fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        @Override
512fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        public void onAnimationPause(Animator animation) {
513629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount            if (!mCanceled) {
514e5a93aa81ce79bf7fa529b09b50d7473f07a74a2George Mount                mView.setTransitionVisibility(mFinalVisibility);
515fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            }
516fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
517fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
518fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        @Override
519fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        public void onAnimationResume(Animator animation) {
520629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount            if (!mCanceled) {
521e5a93aa81ce79bf7fa529b09b50d7473f07a74a2George Mount                mView.setTransitionVisibility(View.VISIBLE);
522fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            }
523fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
524fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
525fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        @Override
526fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        public void onAnimationCancel(Animator animation) {
527fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            mCanceled = true;
528fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
529fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
530fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        @Override
531fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        public void onAnimationRepeat(Animator animation) {
532fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
533fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
534fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        @Override
535fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        public void onAnimationStart(Animator animation) {
536fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
537fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
538fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        @Override
539fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        public void onAnimationEnd(Animator animation) {
540fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            hideViewWhenNotCanceled();
541fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
542fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
543fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        @Override
544fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        public void onTransitionEnd(Transition transition) {
545fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            hideViewWhenNotCanceled();
54625f98a4c0156ec40d1d92cfe5a24459d9ffa6f91George Mount            transition.removeListener(this);
547fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
548fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount
54921290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount        @Override
55021290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount        public void onTransitionPause(Transition transition) {
551a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount            suppressLayout(false);
55221290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount        }
55321290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount
55421290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount        @Override
55521290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount        public void onTransitionResume(Transition transition) {
556a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount            suppressLayout(true);
55721290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount        }
55821290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount
559fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        private void hideViewWhenNotCanceled() {
560a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount            if (!mCanceled) {
561629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount                // Recreate the parent's display list in case it includes mView.
562629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount                mView.setTransitionVisibility(mFinalVisibility);
563629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount                if (mParent != null) {
564629767288a7f551d651f0405fdd9ed04e807d56bGeorge Mount                    mParent.invalidate();
56521290a62a58581eecd29f4895bb7319a0cb5721aGeorge Mount                }
566a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount            }
567a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount            // Layout is allowed now that the View is in its final state
568a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount            suppressLayout(false);
569a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount        }
570a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount
571a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount        private void suppressLayout(boolean suppress) {
5721349bb9c336e33bdb8a7edd3fdec9a7ecf8015d0George Mount            if (mSuppressLayout && mLayoutSuppressed != suppress && mParent != null) {
573a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount                mLayoutSuppressed = suppress;
574a7478ab9a7d36fbd8a0adaada613dff2a9fe77b4George Mount                mParent.suppressLayout(suppress);
575fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount            }
576fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount        }
577fcfe531e742bd1731664080cb2ed3e66189d7f17George Mount    }
578faebd8f0795b7d275fb4e503533c8c0c4a9acc21Chet Haase}
579