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