1608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount/*
2608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * Copyright (C) 2014 The Android Open Source Project
3608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *
4608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * Licensed under the Apache License, Version 2.0 (the "License");
5608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * you may not use this file except in compliance with the License.
6608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * You may obtain a copy of the License at
7608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *
8608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *      http://www.apache.org/licenses/LICENSE-2.0
9608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *
10608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * Unless required by applicable law or agreed to in writing, software
11608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * distributed under the License is distributed on an "AS IS" BASIS,
12608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * See the License for the specific language governing permissions and
14608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * limitations under the License.
15608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount */
16608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountpackage android.transition;
17608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
18608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.animation.Animator;
19c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Guimport android.animation.AnimatorListenerAdapter;
20fa35d14e431dbfc2418fe736b826922fde6503e7George Mountimport android.animation.FloatArrayEvaluator;
21608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.animation.ObjectAnimator;
22fa35d14e431dbfc2418fe736b826922fde6503e7George Mountimport android.animation.PropertyValuesHolder;
23ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.content.Context;
24c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Guimport android.content.res.TypedArray;
25c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Guimport android.graphics.Matrix;
26fa35d14e431dbfc2418fe736b826922fde6503e7George Mountimport android.graphics.Path;
27fa35d14e431dbfc2418fe736b826922fde6503e7George Mountimport android.graphics.PointF;
28ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.util.AttributeSet;
29608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.util.Property;
30c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Guimport android.view.GhostView;
31608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.view.View;
32608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.view.ViewGroup;
33c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Guimport com.android.internal.R;
34608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
35608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount/**
36608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * This Transition captures scale and rotation for Views before and after the
37608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * scene change and animates those changes during the transition.
38608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *
39c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu * A change in parent is handled as well by capturing the transforms from
40c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu * the parent before and after the scene change and animating those during the
41c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu * transition.
42608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount */
43608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountpublic class ChangeTransform extends Transition {
44608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
45608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    private static final String TAG = "ChangeTransform";
46608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
47c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private static final String PROPNAME_MATRIX = "android:changeTransform:matrix";
48c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private static final String PROPNAME_TRANSFORMS = "android:changeTransform:transforms";
49c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private static final String PROPNAME_PARENT = "android:changeTransform:parent";
50c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private static final String PROPNAME_PARENT_MATRIX = "android:changeTransform:parentMatrix";
51dc19ac008c5065521ac9843d66c8701af8845264George Mount    private static final String PROPNAME_INTERMEDIATE_PARENT_MATRIX =
52dc19ac008c5065521ac9843d66c8701af8845264George Mount            "android:changeTransform:intermediateParentMatrix";
53dc19ac008c5065521ac9843d66c8701af8845264George Mount    private static final String PROPNAME_INTERMEDIATE_MATRIX =
54dc19ac008c5065521ac9843d66c8701af8845264George Mount            "android:changeTransform:intermediateMatrix";
55608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
56608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    private static final String[] sTransitionProperties = {
57c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            PROPNAME_MATRIX,
58c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            PROPNAME_TRANSFORMS,
59c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            PROPNAME_PARENT_MATRIX,
60608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    };
61608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
62fa35d14e431dbfc2418fe736b826922fde6503e7George Mount    /**
63fa35d14e431dbfc2418fe736b826922fde6503e7George Mount     * This property sets the animation matrix properties that are not translations.
64fa35d14e431dbfc2418fe736b826922fde6503e7George Mount     */
65fa35d14e431dbfc2418fe736b826922fde6503e7George Mount    private static final Property<PathAnimatorMatrix, float[]> NON_TRANSLATIONS_PROPERTY =
66fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            new Property<PathAnimatorMatrix, float[]>(float[].class, "nonTranslations") {
67c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                @Override
68fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                public float[] get(PathAnimatorMatrix object) {
69c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    return null;
70c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                }
71608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
72c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                @Override
73fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                public void set(PathAnimatorMatrix object, float[] value) {
74fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                    object.setValues(value);
75fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                }
76fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            };
77fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
78fa35d14e431dbfc2418fe736b826922fde6503e7George Mount    /**
79fa35d14e431dbfc2418fe736b826922fde6503e7George Mount     * This property sets the translation animation matrix properties.
80fa35d14e431dbfc2418fe736b826922fde6503e7George Mount     */
81fa35d14e431dbfc2418fe736b826922fde6503e7George Mount    private static final Property<PathAnimatorMatrix, PointF> TRANSLATIONS_PROPERTY =
82fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            new Property<PathAnimatorMatrix, PointF>(PointF.class, "translations") {
83fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                @Override
84fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                public PointF get(PathAnimatorMatrix object) {
85fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                    return null;
86fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                }
87fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
88fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                @Override
89fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                public void set(PathAnimatorMatrix object, PointF value) {
90fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                    object.setTranslation(value);
91608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount                }
92c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            };
93c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
94c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private boolean mUseOverlay = true;
95c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private boolean mReparent = true;
96c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private Matrix mTempMatrix = new Matrix();
97608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
98ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    public ChangeTransform() {}
99ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
100ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    public ChangeTransform(Context context, AttributeSet attrs) {
101ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        super(context, attrs);
102c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChangeTransform);
103c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        mUseOverlay = a.getBoolean(R.styleable.ChangeTransform_reparentWithOverlay, true);
104c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        mReparent = a.getBoolean(R.styleable.ChangeTransform_reparent, true);
105c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        a.recycle();
106c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
107c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
108c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    /**
109c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * Returns whether changes to parent should use an overlay or not. When the parent
110c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * change doesn't use an overlay, it affects the transforms of the child. The
111c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * default value is <code>true</code>.
112c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     *
113c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when
114c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * it moves outside the bounds of its parent. Setting
115c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * {@link android.view.ViewGroup#setClipChildren(boolean)} and
116c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when
117c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * Overlays are not used and the parent is animating its location, the position of the
118c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * child view will be relative to its parent's final position, so it may appear to "jump"
119c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * at the beginning.</p>
120c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     *
121c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * @return <code>true</code> when a changed parent should execute the transition
122c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * inside the scene root's overlay or <code>false</code> if a parent change only
123c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * affects the transform of the transitioning view.
124f9557619a7643c971e64e5b35583476202e77b7bGeorge Mount     * @attr ref android.R.styleable#ChangeTransform_reparentWithOverlay
125c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     */
126c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    public boolean getReparentWithOverlay() {
127c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        return mUseOverlay;
128c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
129c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
130c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    /**
131c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * Sets whether changes to parent should use an overlay or not. When the parent
132c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * change doesn't use an overlay, it affects the transforms of the child. The
133c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * default value is <code>true</code>.
134c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     *
135c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when
136c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * it moves outside the bounds of its parent. Setting
137c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * {@link android.view.ViewGroup#setClipChildren(boolean)} and
138c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when
139c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * Overlays are not used and the parent is animating its location, the position of the
140c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * child view will be relative to its parent's final position, so it may appear to "jump"
141c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * at the beginning.</p>
142c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     *
143c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * @return <code>true</code> when a changed parent should execute the transition
144c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * inside the scene root's overlay or <code>false</code> if a parent change only
145c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * affects the transform of the transitioning view.
146f9557619a7643c971e64e5b35583476202e77b7bGeorge Mount     * @attr ref android.R.styleable#ChangeTransform_reparentWithOverlay
147c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     */
148c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    public void setReparentWithOverlay(boolean reparentWithOverlay) {
149c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        mUseOverlay = reparentWithOverlay;
150c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
151c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
152c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    /**
153c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * Returns whether parent changes will be tracked by the ChangeTransform. If parent
154c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * changes are tracked, then the transform will adjust to the transforms of the
155c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * different parents. If they aren't tracked, only the transforms of the transitioning
156c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * view will be tracked. Default is true.
157c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     *
158c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * @return whether parent changes will be tracked by the ChangeTransform.
159f9557619a7643c971e64e5b35583476202e77b7bGeorge Mount     * @attr ref android.R.styleable#ChangeTransform_reparent
160c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     */
161c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    public boolean getReparent() {
162c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        return mReparent;
163c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
164c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
165c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    /**
166c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * Sets whether parent changes will be tracked by the ChangeTransform. If parent
167c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * changes are tracked, then the transform will adjust to the transforms of the
168c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * different parents. If they aren't tracked, only the transforms of the transitioning
169c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * view will be tracked. Default is true.
170c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     *
171c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     * @param reparent Set to true to track parent changes or false to only track changes
172c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     *                 of the transitioning view without considering the parent change.
173f9557619a7643c971e64e5b35583476202e77b7bGeorge Mount     * @attr ref android.R.styleable#ChangeTransform_reparent
174c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu     */
175c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    public void setReparent(boolean reparent) {
176c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        mReparent = reparent;
177ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    }
178ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
179608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    @Override
180608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    public String[] getTransitionProperties() {
181608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        return sTransitionProperties;
182608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
183608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
184c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private void captureValues(TransitionValues transitionValues) {
185c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        View view = transitionValues.view;
186608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        if (view.getVisibility() == View.GONE) {
187608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            return;
188608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
189c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        transitionValues.values.put(PROPNAME_PARENT, view.getParent());
190c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Transforms transforms = new Transforms(view);
191c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        transitionValues.values.put(PROPNAME_TRANSFORMS, transforms);
192c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix matrix = view.getMatrix();
193c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (matrix == null || matrix.isIdentity()) {
194c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            matrix = null;
195c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        } else {
196c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            matrix = new Matrix(matrix);
197c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
198c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        transitionValues.values.put(PROPNAME_MATRIX, matrix);
199c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (mReparent) {
200c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            Matrix parentMatrix = new Matrix();
201c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            ViewGroup parent = (ViewGroup) view.getParent();
202c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            parent.transformMatrixToGlobal(parentMatrix);
203c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            parentMatrix.preTranslate(-parent.getScrollX(), -parent.getScrollY());
204c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            transitionValues.values.put(PROPNAME_PARENT_MATRIX, parentMatrix);
205dc19ac008c5065521ac9843d66c8701af8845264George Mount            transitionValues.values.put(PROPNAME_INTERMEDIATE_MATRIX,
206dc19ac008c5065521ac9843d66c8701af8845264George Mount                    view.getTag(R.id.transitionTransform));
207dc19ac008c5065521ac9843d66c8701af8845264George Mount            transitionValues.values.put(PROPNAME_INTERMEDIATE_PARENT_MATRIX,
208dc19ac008c5065521ac9843d66c8701af8845264George Mount                    view.getTag(R.id.parentMatrix));
209c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
210c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        return;
211608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
212608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
213608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    @Override
214608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    public void captureStartValues(TransitionValues transitionValues) {
215608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        captureValues(transitionValues);
216608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
217608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
218608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    @Override
219608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    public void captureEndValues(TransitionValues transitionValues) {
220608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        captureValues(transitionValues);
221608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
222608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
223608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    @Override
224c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
225c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            TransitionValues endValues) {
226c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (startValues == null || endValues == null ||
227c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                !startValues.values.containsKey(PROPNAME_PARENT) ||
228c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                !endValues.values.containsKey(PROPNAME_PARENT)) {
229c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            return null;
230c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
231c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
232c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        ViewGroup startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
233c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
234c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        boolean handleParentChange = mReparent && !parentsMatch(startParent, endParent);
235c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
236dc19ac008c5065521ac9843d66c8701af8845264George Mount        Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_INTERMEDIATE_MATRIX);
237c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (startMatrix != null) {
238c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            startValues.values.put(PROPNAME_MATRIX, startMatrix);
239c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
240c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
241dc19ac008c5065521ac9843d66c8701af8845264George Mount        Matrix startParentMatrix = (Matrix)
242dc19ac008c5065521ac9843d66c8701af8845264George Mount                startValues.values.get(PROPNAME_INTERMEDIATE_PARENT_MATRIX);
243c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (startParentMatrix != null) {
244c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            startValues.values.put(PROPNAME_PARENT_MATRIX, startParentMatrix);
245c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
246c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
247c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        // First handle the parent change:
248c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (handleParentChange) {
249c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            setMatricesForParent(startValues, endValues);
250c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
251c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
252c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        // Next handle the normal matrix transform:
25324314e7d10d0354cd548de35a2c4795a87fbfb21George Mount        ObjectAnimator transformAnimator = createTransformAnimator(startValues, endValues,
25424314e7d10d0354cd548de35a2c4795a87fbfb21George Mount                handleParentChange);
255c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
256c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (handleParentChange && transformAnimator != null && mUseOverlay) {
257c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            createGhostView(sceneRoot, startValues, endValues);
258c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
259c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
260c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        return transformAnimator;
261c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
262c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
263c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private ObjectAnimator createTransformAnimator(TransitionValues startValues,
26424314e7d10d0354cd548de35a2c4795a87fbfb21George Mount            TransitionValues endValues, final boolean handleParentChange) {
265c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
266c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
267c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
268c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (startMatrix == null) {
269c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            startMatrix = Matrix.IDENTITY_MATRIX;
270c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
271c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
272c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (endMatrix == null) {
273c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            endMatrix = Matrix.IDENTITY_MATRIX;
274c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
275c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
276c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (startMatrix.equals(endMatrix)) {
277608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            return null;
278608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
279608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
280c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        final Transforms transforms = (Transforms) endValues.values.get(PROPNAME_TRANSFORMS);
281c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
282c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        // clear the transform properties so that we can use the animation matrix instead
283c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        final View view = endValues.view;
284c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        setIdentityTransforms(view);
285c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
286fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        final float[] startMatrixValues = new float[9];
287fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        startMatrix.getValues(startMatrixValues);
288fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        final float[] endMatrixValues = new float[9];
289fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        endMatrix.getValues(endMatrixValues);
290fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        final PathAnimatorMatrix pathAnimatorMatrix =
291fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                new PathAnimatorMatrix(view, startMatrixValues);
292fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
293fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        PropertyValuesHolder valuesProperty = PropertyValuesHolder.ofObject(
294fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                NON_TRANSLATIONS_PROPERTY, new FloatArrayEvaluator(new float[9]),
295fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                startMatrixValues, endMatrixValues);
296fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        Path path = getPathMotion().getPath(startMatrixValues[Matrix.MTRANS_X],
297fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                startMatrixValues[Matrix.MTRANS_Y], endMatrixValues[Matrix.MTRANS_X],
298fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                endMatrixValues[Matrix.MTRANS_Y]);
299fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        PropertyValuesHolder translationProperty = PropertyValuesHolder.ofObject(
300fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                TRANSLATIONS_PROPERTY, null, path);
301fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(pathAnimatorMatrix,
302fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                valuesProperty, translationProperty);
303c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
304dc19ac008c5065521ac9843d66c8701af8845264George Mount        final Matrix finalEndMatrix = endMatrix;
305dc19ac008c5065521ac9843d66c8701af8845264George Mount
306c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
307c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            private boolean mIsCanceled;
308dc19ac008c5065521ac9843d66c8701af8845264George Mount            private Matrix mTempMatrix = new Matrix();
309c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
310c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            @Override
311c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            public void onAnimationCancel(Animator animation) {
312c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                mIsCanceled = true;
313c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            }
314c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
315c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            @Override
316c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            public void onAnimationEnd(Animator animation) {
317c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                if (!mIsCanceled) {
31824314e7d10d0354cd548de35a2c4795a87fbfb21George Mount                    if (handleParentChange && mUseOverlay) {
31924314e7d10d0354cd548de35a2c4795a87fbfb21George Mount                        setCurrentMatrix(finalEndMatrix);
32024314e7d10d0354cd548de35a2c4795a87fbfb21George Mount                    } else {
32124314e7d10d0354cd548de35a2c4795a87fbfb21George Mount                        view.setTagInternal(R.id.transitionTransform, null);
32224314e7d10d0354cd548de35a2c4795a87fbfb21George Mount                        view.setTagInternal(R.id.parentMatrix, null);
32324314e7d10d0354cd548de35a2c4795a87fbfb21George Mount                    }
324c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                }
325fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                view.setAnimationMatrix(null);
326c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                transforms.restore(view);
327c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            }
328c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
329c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            @Override
330c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            public void onAnimationPause(Animator animation) {
331fa35d14e431dbfc2418fe736b826922fde6503e7George Mount                Matrix currentMatrix = pathAnimatorMatrix.getMatrix();
332dc19ac008c5065521ac9843d66c8701af8845264George Mount                setCurrentMatrix(currentMatrix);
333c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            }
334c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
335c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            @Override
336c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            public void onAnimationResume(Animator animation) {
337c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                setIdentityTransforms(view);
338c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            }
339dc19ac008c5065521ac9843d66c8701af8845264George Mount
340dc19ac008c5065521ac9843d66c8701af8845264George Mount            private void setCurrentMatrix(Matrix currentMatrix) {
341dc19ac008c5065521ac9843d66c8701af8845264George Mount                mTempMatrix.set(currentMatrix);
342dc19ac008c5065521ac9843d66c8701af8845264George Mount                view.setTagInternal(R.id.transitionTransform, mTempMatrix);
343dc19ac008c5065521ac9843d66c8701af8845264George Mount                transforms.restore(view);
344dc19ac008c5065521ac9843d66c8701af8845264George Mount            }
345c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        };
346c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
347c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        animator.addListener(listener);
348c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        animator.addPauseListener(listener);
349c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        return animator;
350c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
351c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
352c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private boolean parentsMatch(ViewGroup startParent, ViewGroup endParent) {
353c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        boolean parentsMatch = false;
354c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (!isValidTarget(startParent) || !isValidTarget(endParent)) {
355c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            parentsMatch = startParent == endParent;
356c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        } else {
357c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            TransitionValues endValues = getMatchedTransitionValues(startParent, true);
358c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            if (endValues != null) {
359c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                parentsMatch = endParent == endValues.view;
360608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            }
361608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
362c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        return parentsMatch;
363608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
364608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
365c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private void createGhostView(final ViewGroup sceneRoot, TransitionValues startValues,
366c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            TransitionValues endValues) {
367c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        View view = endValues.view;
368c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
369c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX);
370c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix localEndMatrix = new Matrix(endMatrix);
371c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        sceneRoot.transformMatrixToLocal(localEndMatrix);
372c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
373c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        GhostView ghostView = GhostView.addGhost(view, sceneRoot, localEndMatrix);
374c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
375c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Transition outerTransition = this;
376c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        while (outerTransition.mParent != null) {
377c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            outerTransition = outerTransition.mParent;
378608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
3796c211ff43e1e8055ecd08d30fa8d7fdde04942aeGeorge Mount        GhostListener listener = new GhostListener(view, startValues.view, ghostView);
380c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        outerTransition.addListener(listener);
381c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
382c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (startValues.view != endValues.view) {
383c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            startValues.view.setTransitionAlpha(0);
384c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
385c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setTransitionAlpha(1);
386608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
387608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
388c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private void setMatricesForParent(TransitionValues startValues, TransitionValues endValues) {
389c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix endParentMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX);
390c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        endValues.view.setTagInternal(R.id.parentMatrix, endParentMatrix);
391c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
392c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix toLocal = mTempMatrix;
393c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        toLocal.reset();
394c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        endParentMatrix.invert(toLocal);
395608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
396c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix startLocal = (Matrix) startValues.values.get(PROPNAME_MATRIX);
397c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        if (startLocal == null) {
398c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            startLocal = new Matrix();
399c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            startValues.values.put(PROPNAME_MATRIX, startLocal);
400c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
401c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
402c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        Matrix startParentMatrix = (Matrix) startValues.values.get(PROPNAME_PARENT_MATRIX);
403c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        startLocal.postConcat(startParentMatrix);
404c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        startLocal.postConcat(toLocal);
405608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
406608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
407c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private static void setIdentityTransforms(View view) {
408c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        setTransforms(view, 0, 0, 0, 1, 1, 0, 0, 0);
409c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
410c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
411c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private static void setTransforms(View view, float translationX, float translationY,
412c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            float translationZ, float scaleX, float scaleY, float rotationX,
413c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            float rotationY, float rotationZ) {
414c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setTranslationX(translationX);
415c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setTranslationY(translationY);
416c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setTranslationZ(translationZ);
417c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setScaleX(scaleX);
418c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setScaleY(scaleY);
419c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setRotationX(rotationX);
420c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setRotationY(rotationY);
421c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        view.setRotation(rotationZ);
422c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
423c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
424c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private static class Transforms {
425c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public final float translationX;
426c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public final float translationY;
427c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public final float translationZ;
428c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public final float scaleX;
429c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public final float scaleY;
430c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public final float rotationX;
431c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public final float rotationY;
432c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public final float rotationZ;
433c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
434c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public Transforms(View view) {
435c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            translationX = view.getTranslationX();
436c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            translationY = view.getTranslationY();
437c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            translationZ = view.getTranslationZ();
438c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            scaleX = view.getScaleX();
439c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            scaleY = view.getScaleY();
440c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            rotationX = view.getRotationX();
441c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            rotationY = view.getRotationY();
442c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            rotationZ = view.getRotation();
443c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
444c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
445c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public void restore(View view) {
446c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            setTransforms(view, translationX, translationY, translationZ, scaleX, scaleY,
447c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    rotationX, rotationY, rotationZ);
448c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
449c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
450c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        @Override
451c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public boolean equals(Object that) {
452c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            if (!(that instanceof Transforms)) {
453c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                return false;
454608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            }
455c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            Transforms thatTransform = (Transforms) that;
456c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            return thatTransform.translationX == translationX &&
457c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    thatTransform.translationY == translationY &&
458c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    thatTransform.translationZ == translationZ &&
459c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    thatTransform.scaleX == scaleX &&
460c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    thatTransform.scaleY == scaleY &&
461c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    thatTransform.rotationX == rotationX &&
462c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    thatTransform.rotationY == rotationY &&
463c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu                    thatTransform.rotationZ == rotationZ;
464c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
465c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    }
466c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
467c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu    private static class GhostListener extends Transition.TransitionListenerAdapter {
468c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        private View mView;
4696c211ff43e1e8055ecd08d30fa8d7fdde04942aeGeorge Mount        private View mStartView;
470c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        private GhostView mGhostView;
471c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
4726c211ff43e1e8055ecd08d30fa8d7fdde04942aeGeorge Mount        public GhostListener(View view, View startView, GhostView ghostView) {
473c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            mView = view;
4746c211ff43e1e8055ecd08d30fa8d7fdde04942aeGeorge Mount            mStartView = startView;
475c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            mGhostView = ghostView;
476c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
477c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
478c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        @Override
479c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public void onTransitionEnd(Transition transition) {
480c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            transition.removeListener(this);
481c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            GhostView.removeGhost(mView);
482dc19ac008c5065521ac9843d66c8701af8845264George Mount            mView.setTagInternal(R.id.transitionTransform, null);
483dc19ac008c5065521ac9843d66c8701af8845264George Mount            mView.setTagInternal(R.id.parentMatrix, null);
4846c211ff43e1e8055ecd08d30fa8d7fdde04942aeGeorge Mount            mStartView.setTransitionAlpha(1);
485c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
486c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
487c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        @Override
488c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public void onTransitionPause(Transition transition) {
489c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            mGhostView.setVisibility(View.INVISIBLE);
490c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        }
491c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu
492c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        @Override
493c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu        public void onTransitionResume(Transition transition) {
494c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu            mGhostView.setVisibility(View.VISIBLE);
495608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
496608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
497fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
498fa35d14e431dbfc2418fe736b826922fde6503e7George Mount    /**
499fa35d14e431dbfc2418fe736b826922fde6503e7George Mount     * PathAnimatorMatrix allows the translations and the rest of the matrix to be set
500fa35d14e431dbfc2418fe736b826922fde6503e7George Mount     * separately. This allows the PathMotion to affect the translations while scale
501fa35d14e431dbfc2418fe736b826922fde6503e7George Mount     * and rotation are evaluated separately.
502fa35d14e431dbfc2418fe736b826922fde6503e7George Mount     */
503fa35d14e431dbfc2418fe736b826922fde6503e7George Mount    private static class PathAnimatorMatrix {
504fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        private final Matrix mMatrix = new Matrix();
505fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        private final View mView;
506fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        private final float[] mValues;
507fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        private float mTranslationX;
508fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        private float mTranslationY;
509fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
510fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        public PathAnimatorMatrix(View view, float[] values) {
511fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mView = view;
512fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mValues = values.clone();
513fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mTranslationX = mValues[Matrix.MTRANS_X];
514fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mTranslationY = mValues[Matrix.MTRANS_Y];
515fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            setAnimationMatrix();
516fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        }
517fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
518fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        public void setValues(float[] values) {
519fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            System.arraycopy(values, 0, mValues, 0, values.length);
520fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            setAnimationMatrix();
521fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        }
522fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
523fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        public void setTranslation(PointF translation) {
524fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mTranslationX = translation.x;
525fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mTranslationY = translation.y;
526fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            setAnimationMatrix();
527fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        }
528fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
529fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        private void setAnimationMatrix() {
530fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mValues[Matrix.MTRANS_X] = mTranslationX;
531fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mValues[Matrix.MTRANS_Y] = mTranslationY;
532fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mMatrix.setValues(mValues);
533fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            mView.setAnimationMatrix(mMatrix);
534fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        }
535fa35d14e431dbfc2418fe736b826922fde6503e7George Mount
536fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        public Matrix getMatrix() {
537fa35d14e431dbfc2418fe736b826922fde6503e7George Mount            return mMatrix;
538fa35d14e431dbfc2418fe736b826922fde6503e7George Mount        }
539fa35d14e431dbfc2418fe736b826922fde6503e7George Mount    }
540608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount}
541