1c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki/*
2c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Copyright (C) 2016 The Android Open Source Project
3c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *
4c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Licensed under the Apache License, Version 2.0 (the "License");
5c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * you may not use this file except in compliance with the License.
6c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * You may obtain a copy of the License at
7c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *
8c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *      http://www.apache.org/licenses/LICENSE-2.0
9c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *
10c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * Unless required by applicable law or agreed to in writing, software
11c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * distributed under the License is distributed on an "AS IS" BASIS,
12c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * See the License for the specific language governing permissions and
14c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * limitations under the License.
15c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki */
16c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
17c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakipackage android.support.transition;
18c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
19c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.animation.Animator;
20c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.animation.AnimatorListenerAdapter;
21c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.animation.ObjectAnimator;
22c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.animation.PropertyValuesHolder;
23c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.graphics.Bitmap;
24c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.graphics.Canvas;
25c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.graphics.Rect;
26c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.graphics.drawable.BitmapDrawable;
27c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.view.View;
28c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport android.view.ViewGroup;
29c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
30c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiimport java.util.Map;
31c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
32c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki/**
33c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * This transition captures the layout bounds of target views before and after
34c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * the scene change and animates those changes during the transition.
35c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki *
36c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * <p>A ChangeBounds transition can be described in a resource file by using the
37c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * tag <code>changeBounds</code>, along with the other standard
38c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki * attributes of {@link android.R.styleable#Transition}.</p>
39c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki */
40c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Arakiclass ChangeBoundsPort extends TransitionPort {
41c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
42c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds";
43c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
44c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private static final String PROPNAME_PARENT = "android:changeBounds:parent";
45c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
46c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private static final String PROPNAME_WINDOW_X = "android:changeBounds:windowX";
47c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
48c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private static final String PROPNAME_WINDOW_Y = "android:changeBounds:windowY";
49c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
50c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private static final String[] sTransitionProperties = {
51c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            PROPNAME_BOUNDS,
52c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            PROPNAME_PARENT,
53c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            PROPNAME_WINDOW_X,
54c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            PROPNAME_WINDOW_Y
55c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    };
56c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
57c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private static final String LOG_TAG = "ChangeBounds";
58c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
59c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private static RectEvaluator sRectEvaluator = new RectEvaluator();
60c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
61c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    int[] tempLocation = new int[2];
62c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
63c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    boolean mResizeClip = false;
64c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
65c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    boolean mReparent = false;
66c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
67c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    @Override
68c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public String[] getTransitionProperties() {
69c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        return sTransitionProperties;
70c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
71c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
72c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public void setResizeClip(boolean resizeClip) {
73c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mResizeClip = resizeClip;
74c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
75c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
76c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    /**
77c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * Setting this flag tells ChangeBounds to track the before/after parent
78c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * of every view using this transition. The flag is not enabled by
79c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * default because it requires the parent instances to be the same
80c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * in the two scenes or else all parents must use ids to allow
81c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * the transition to determine which parents are the same.
82c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *
83c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     * @param reparent true if the transition should track the parent
84c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     *                 container of target views and animate parent changes.
85c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki     */
86c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public void setReparent(boolean reparent) {
87c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        mReparent = reparent;
88c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
89c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
90c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    private void captureValues(TransitionValues values) {
91c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        View view = values.view;
92c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(),
93c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                view.getRight(), view.getBottom()));
94c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        values.values.put(PROPNAME_PARENT, values.view.getParent());
95c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        values.view.getLocationInWindow(tempLocation);
96c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        values.values.put(PROPNAME_WINDOW_X, tempLocation[0]);
97c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]);
98c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
99c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
100c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    @Override
101c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public void captureStartValues(TransitionValues transitionValues) {
102c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        captureValues(transitionValues);
103c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
104c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
105c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    @Override
106c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public void captureEndValues(TransitionValues transitionValues) {
107c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        captureValues(transitionValues);
108c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
109c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
110c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    @Override
111c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
112c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            TransitionValues endValues) {
113c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        if (startValues == null || endValues == null) {
114c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            return null;
115c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        }
116c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        Map<String, Object> startParentVals = startValues.values;
117c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        Map<String, Object> endParentVals = endValues.values;
118c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        ViewGroup startParent = (ViewGroup) startParentVals.get(PROPNAME_PARENT);
119c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        ViewGroup endParent = (ViewGroup) endParentVals.get(PROPNAME_PARENT);
120c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        if (startParent == null || endParent == null) {
121c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            return null;
122c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        }
123c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        final View view = endValues.view;
124c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        boolean parentsEqual = (startParent == endParent) ||
125c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                (startParent.getId() == endParent.getId());
126c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        // TODO: Might want reparenting to be separate/subclass transition, or at least
127c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        // triggered by a property on ChangeBounds. Otherwise, we're forcing the requirement that
128c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        // all parents in layouts have IDs to avoid layout-inflation resulting in a side-effect
129c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        // of reparenting the views.
130c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        if (!mReparent || parentsEqual) {
131c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
132c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
133c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int startLeft = startBounds.left;
134c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int endLeft = endBounds.left;
135c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int startTop = startBounds.top;
136c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int endTop = endBounds.top;
137c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int startRight = startBounds.right;
138c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int endRight = endBounds.right;
139c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int startBottom = startBounds.bottom;
140c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int endBottom = endBounds.bottom;
141c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int startWidth = startRight - startLeft;
142c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int startHeight = startBottom - startTop;
143c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int endWidth = endRight - endLeft;
144c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int endHeight = endBottom - endTop;
145c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int numChanges = 0;
146c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) {
147c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                if (startLeft != endLeft) {
148c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    ++numChanges;
149c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                }
150c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                if (startTop != endTop) {
151c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    ++numChanges;
152c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                }
153c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                if (startRight != endRight) {
154c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    ++numChanges;
155c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                }
156c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                if (startBottom != endBottom) {
157c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    ++numChanges;
158c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                }
159c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            }
160c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            if (numChanges > 0) {
161c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                if (!mResizeClip) {
162c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
163c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    int pvhIndex = 0;
164c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startLeft != endLeft) {
165c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setLeft(startLeft);
166c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
167c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startTop != endTop) {
168c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setTop(startTop);
169c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
170c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startRight != endRight) {
171c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setRight(startRight);
172c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
173c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startBottom != endBottom) {
174c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setBottom(startBottom);
175c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
176c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startLeft != endLeft) {
177c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("left", startLeft, endLeft);
178c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
179c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startTop != endTop) {
180c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("top", startTop, endTop);
181c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
182c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startRight != endRight) {
183c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("right",
184c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                startRight, endRight);
185c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
186c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startBottom != endBottom) {
187c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        pvh[pvhIndex++] = PropertyValuesHolder.ofInt("bottom",
188c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                startBottom, endBottom);
189c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
190c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
191c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (view.getParent() instanceof ViewGroup) {
192c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        final ViewGroup parent = (ViewGroup) view.getParent();
193c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                        parent.suppressLayout(true);
194c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        TransitionListener transitionListener = new TransitionListenerAdapter() {
195c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            boolean mCanceled = false;
196c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
197c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            @Override
198c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            public void onTransitionCancel(TransitionPort transition) {
199c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                parent.suppressLayout(false);
200c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                mCanceled = true;
201c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            }
202c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
203c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            @Override
204c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            public void onTransitionEnd(TransitionPort transition) {
205c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                if (!mCanceled) {
206c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                    parent.suppressLayout(false);
207c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                }
208c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            }
209c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
210c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            @Override
211c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            public void onTransitionPause(TransitionPort transition) {
212c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                parent.suppressLayout(false);
213c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            }
214c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
215c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            @Override
216c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            public void onTransitionResume(TransitionPort transition) {
217c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                parent.suppressLayout(true);
218c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            }
219c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        };
220c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        addListener(transitionListener);
221c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
222c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    return anim;
223c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                } else {
224c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startWidth != endWidth) {
225c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setRight(endLeft +
226c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                Math.max(startWidth, endWidth));
227c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
228c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startHeight != endHeight) {
229c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setBottom(endTop +
230c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                Math.max(startHeight, endHeight));
231c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
232c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    // TODO: don't clobber TX/TY
233c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startLeft != endLeft) {
234c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setTranslationX(startLeft - endLeft);
235c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
236c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (startTop != endTop) {
237c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setTranslationY(startTop - endTop);
238c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
239c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    // Animate location with translationX/Y and size with clip bounds
240c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    float transXDelta = endLeft - startLeft;
241c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    float transYDelta = endTop - startTop;
242c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    int widthDelta = endWidth - startWidth;
243c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    int heightDelta = endHeight - startHeight;
244c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    numChanges = 0;
245c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (transXDelta != 0) {
246c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        numChanges++;
247c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
248c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (transYDelta != 0) {
249c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        numChanges++;
250c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
251c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (widthDelta != 0 || heightDelta != 0) {
252c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        numChanges++;
253c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
254c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
255c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    int pvhIndex = 0;
256c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (transXDelta != 0) {
257c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationX",
258c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                view.getTranslationX(), 0);
259c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
260c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (transYDelta != 0) {
261c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationY",
262c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                view.getTranslationY(), 0);
263c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
264c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (widthDelta != 0 || heightDelta != 0) {
265c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        Rect tempStartBounds = new Rect(0, 0, startWidth, startHeight);
266c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        Rect tempEndBounds = new Rect(0, 0, endWidth, endHeight);
267c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                        pvh[pvhIndex++] = PropertyValuesHolder.ofObject("clipBounds",
268c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                sRectEvaluator, tempStartBounds, tempEndBounds);
269c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
270c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
271c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    if (view.getParent() instanceof ViewGroup) {
272c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        final ViewGroup parent = (ViewGroup) view.getParent();
273c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                        parent.suppressLayout(true);
274c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        TransitionListener transitionListener = new TransitionListenerAdapter() {
275c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            boolean mCanceled = false;
276c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
277c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            @Override
278c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            public void onTransitionCancel(TransitionPort transition) {
279c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                parent.suppressLayout(false);
280c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                mCanceled = true;
281c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            }
282c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
283c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            @Override
284c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            public void onTransitionEnd(TransitionPort transition) {
285c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                if (!mCanceled) {
286c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                    parent.suppressLayout(false);
287c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                                }
288c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            }
289c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
290c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            @Override
291c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            public void onTransitionPause(TransitionPort transition) {
292c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                parent.suppressLayout(false);
293c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            }
294c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki
295c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            @Override
296c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            public void onTransitionResume(TransitionPort transition) {
297c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                                parent.suppressLayout(true);
298c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                            }
299c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        };
300c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        addListener(transitionListener);
301c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
302c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    anim.addListener(new AnimatorListenerAdapter() {
303c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        @Override
304c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        public void onAnimationEnd(Animator animation) {
305c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                            view.setClipBounds(null);
306c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        }
307c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    });
308c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    return anim;
309c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                }
310c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            }
311c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        } else {
312c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int startX = (Integer) startValues.values.get(PROPNAME_WINDOW_X);
313c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int startY = (Integer) startValues.values.get(PROPNAME_WINDOW_Y);
314c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int endX = (Integer) endValues.values.get(PROPNAME_WINDOW_X);
315c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            int endY = (Integer) endValues.values.get(PROPNAME_WINDOW_Y);
316c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            // TODO: also handle size changes: check bounds and animate size changes
317c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            if (startX != endX || startY != endY) {
318c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                sceneRoot.getLocationInWindow(tempLocation);
319c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
320c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        Bitmap.Config.ARGB_8888);
321c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                Canvas canvas = new Canvas(bitmap);
322c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                view.draw(canvas);
323c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                final BitmapDrawable drawable = new BitmapDrawable(bitmap);
324c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                view.setVisibility(View.INVISIBLE);
325c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                ViewOverlay.createFrom(sceneRoot).add(drawable);
326c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                sceneRoot.getOverlay().add(drawable);
327c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                Rect startBounds1 = new Rect(startX - tempLocation[0], startY - tempLocation[1],
328c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        startX - tempLocation[0] + view.getWidth(),
329c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        startY - tempLocation[1] + view.getHeight());
330c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                Rect endBounds1 = new Rect(endX - tempLocation[0], endY - tempLocation[1],
331c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        endX - tempLocation[0] + view.getWidth(),
332c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        endY - tempLocation[1] + view.getHeight());
333c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                ObjectAnimator anim = ObjectAnimator.ofObject(drawable, "bounds",
334c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        sRectEvaluator, startBounds1, endBounds1);
335c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                anim.addListener(new AnimatorListenerAdapter() {
336c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    @Override
337c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    public void onAnimationEnd(Animator animation) {
338c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        ViewOverlay.createFrom(sceneRoot).remove(drawable);
339c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki//                        sceneRoot.getOverlay().remove(drawable);
340c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                        view.setVisibility(View.VISIBLE);
341c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                    }
342c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                });
343c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki                return anim;
344c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki            }
345c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        }
346c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki        return null;
347c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki    }
348c876cd8f9334e2423de00836009f3fd7a9566938Yuichi Araki}
349