Allow PathMotion to affect translations in ChangeTransform.
Bug 18207599
Change-Id: I813976527de426ba6fbdc89291d2ecde0135c19d
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index 3fd28a6..a159b40 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -17,11 +17,14 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.FloatArrayEvaluator;
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
+import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.PointF;
 import android.util.AttributeSet;
 import android.util.Property;
 import android.view.GhostView;
@@ -56,16 +59,35 @@
             PROPNAME_PARENT_MATRIX,
     };
 
-    private static final Property<View, Matrix> ANIMATION_MATRIX_PROPERTY =
-            new Property<View, Matrix>(Matrix.class, "animationMatrix") {
+    /**
+     * This property sets the animation matrix properties that are not translations.
+     */
+    private static final Property<PathAnimatorMatrix, float[]> NON_TRANSLATIONS_PROPERTY =
+            new Property<PathAnimatorMatrix, float[]>(float[].class, "nonTranslations") {
                 @Override
-                public Matrix get(View object) {
+                public float[] get(PathAnimatorMatrix object) {
                     return null;
                 }
 
                 @Override
-                public void set(View object, Matrix value) {
-                    object.setAnimationMatrix(value);
+                public void set(PathAnimatorMatrix object, float[] value) {
+                    object.setValues(value);
+                }
+            };
+
+    /**
+     * This property sets the translation animation matrix properties.
+     */
+    private static final Property<PathAnimatorMatrix, PointF> TRANSLATIONS_PROPERTY =
+            new Property<PathAnimatorMatrix, PointF>(PointF.class, "translations") {
+                @Override
+                public PointF get(PathAnimatorMatrix object) {
+                    return null;
+                }
+
+                @Override
+                public void set(PathAnimatorMatrix object, PointF value) {
+                    object.setTranslation(value);
                 }
             };
 
@@ -261,8 +283,23 @@
         final View view = endValues.view;
         setIdentityTransforms(view);
 
-        ObjectAnimator animator = ObjectAnimator.ofObject(view, ANIMATION_MATRIX_PROPERTY,
-                new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
+        final float[] startMatrixValues = new float[9];
+        startMatrix.getValues(startMatrixValues);
+        final float[] endMatrixValues = new float[9];
+        endMatrix.getValues(endMatrixValues);
+        final PathAnimatorMatrix pathAnimatorMatrix =
+                new PathAnimatorMatrix(view, startMatrixValues);
+
+        PropertyValuesHolder valuesProperty = PropertyValuesHolder.ofObject(
+                NON_TRANSLATIONS_PROPERTY, new FloatArrayEvaluator(new float[9]),
+                startMatrixValues, endMatrixValues);
+        Path path = getPathMotion().getPath(startMatrixValues[Matrix.MTRANS_X],
+                startMatrixValues[Matrix.MTRANS_Y], endMatrixValues[Matrix.MTRANS_X],
+                endMatrixValues[Matrix.MTRANS_Y]);
+        PropertyValuesHolder translationProperty = PropertyValuesHolder.ofObject(
+                TRANSLATIONS_PROPERTY, null, path);
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(pathAnimatorMatrix,
+                valuesProperty, translationProperty);
 
         final Matrix finalEndMatrix = endMatrix;
 
@@ -285,14 +322,13 @@
                         view.setTagInternal(R.id.parentMatrix, null);
                     }
                 }
-                ANIMATION_MATRIX_PROPERTY.set(view, null);
+                view.setAnimationMatrix(null);
                 transforms.restore(view);
             }
 
             @Override
             public void onAnimationPause(Animator animation) {
-                ValueAnimator animator = (ValueAnimator) animation;
-                Matrix currentMatrix = (Matrix) animator.getAnimatedValue();
+                Matrix currentMatrix = pathAnimatorMatrix.getMatrix();
                 setCurrentMatrix(currentMatrix);
             }
 
@@ -457,4 +493,47 @@
             mGhostView.setVisibility(View.VISIBLE);
         }
     }
+
+    /**
+     * PathAnimatorMatrix allows the translations and the rest of the matrix to be set
+     * separately. This allows the PathMotion to affect the translations while scale
+     * and rotation are evaluated separately.
+     */
+    private static class PathAnimatorMatrix {
+        private final Matrix mMatrix = new Matrix();
+        private final View mView;
+        private final float[] mValues;
+        private float mTranslationX;
+        private float mTranslationY;
+
+        public PathAnimatorMatrix(View view, float[] values) {
+            mView = view;
+            mValues = values.clone();
+            mTranslationX = mValues[Matrix.MTRANS_X];
+            mTranslationY = mValues[Matrix.MTRANS_Y];
+            setAnimationMatrix();
+        }
+
+        public void setValues(float[] values) {
+            System.arraycopy(values, 0, mValues, 0, values.length);
+            setAnimationMatrix();
+        }
+
+        public void setTranslation(PointF translation) {
+            mTranslationX = translation.x;
+            mTranslationY = translation.y;
+            setAnimationMatrix();
+        }
+
+        private void setAnimationMatrix() {
+            mValues[Matrix.MTRANS_X] = mTranslationX;
+            mValues[Matrix.MTRANS_Y] = mTranslationY;
+            mMatrix.setValues(mValues);
+            mView.setAnimationMatrix(mMatrix);
+        }
+
+        public Matrix getMatrix() {
+            return mMatrix;
+        }
+    }
 }