From 080443bcb63418245c2408500db735fece5e7083 Mon Sep 17 00:00:00 2001 From: George Mount Date: Mon, 5 May 2014 10:47:00 -0700 Subject: [PATCH] Add ImageView-specific shared element activity transition code. Bug 14497858 Probably more than 50% of shared elements will be ImageViews and sharing the scale type and matrix between the two Activities will simplify shared element transitions. Also fixed MoveImage, which had a bug when the scale type was FIX_XY. Change-Id: Ic5548b4d1420ced12507c18edf76c9e50e27a929 --- .../app/ActivityTransitionCoordinator.java | 91 ++++++++++++++++++- core/java/android/transition/MoveImage.java | 22 ++++- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index 3c1455b0a4b8b..3eb2fea55b037 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -21,6 +21,7 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Matrix; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; @@ -30,6 +31,7 @@ import android.transition.TransitionManager; import android.transition.TransitionSet; import android.util.ArrayMap; import android.util.Pair; +import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroupOverlay; @@ -138,6 +140,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { private static final String KEY_HEIGHT = "shared_element:height"; private static final String KEY_NAME = "shared_element:name"; private static final String KEY_BITMAP = "shared_element:bitmap"; + private static final String KEY_SCALE_TYPE = "shared_element:scaleType"; + private static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix"; + + private static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values(); /** * Sent by the exiting coordinator (either EnterTransitionCoordinator @@ -322,7 +328,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { final ArrayList accepted = new ArrayList(); final ArrayList rejected = new ArrayList(); createSharedElementImages(accepted, rejected, sharedElementNames, state); - setSharedElementState(state, accepted); + ArrayMap> originalImageViewState = + setSharedElementState(state, accepted); handleRejected(rejected); if (getViewsTransition() != null) { @@ -331,6 +338,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { setViewVisibility(mSharedElements, View.VISIBLE); Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(), true); + setOriginalImageViewState(originalImageViewState); if (allowOverlappingTransitions()) { onStartEnterTransition(transition, mEnteringViews); @@ -568,15 +576,22 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { mEpicenterCallback.setEpicenter(epicenter); } - private void setSharedElementState(Bundle sharedElementState, - final ArrayList acceptedOverlayViews) { + private ArrayMap> setSharedElementState( + Bundle sharedElementState, final ArrayList acceptedOverlayViews) { + ArrayMap> originalImageState = + new ArrayMap>(); final int[] tempLoc = new int[2]; if (sharedElementState != null) { for (int i = 0; i < mSharedElements.size(); i++) { View sharedElement = mSharedElements.get(i); + String name = mTargetSharedNames.get(i); + Pair originalState = getOldImageState(sharedElement, + name, sharedElementState); + if (originalState != null) { + originalImageState.put((ImageView) sharedElement, originalState); + } View parent = (View) sharedElement.getParent(); parent.getLocationOnScreen(tempLoc); - String name = mTargetSharedNames.get(i); setSharedElementState(sharedElement, name, sharedElementState, tempLoc); sharedElement.requestLayout(); } @@ -596,6 +611,29 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } } ); + return originalImageState; + } + + private static Pair getOldImageState(View view, String name, + Bundle transitionArgs) { + if (!(view instanceof ImageView)) { + return null; + } + Bundle bundle = transitionArgs.getBundle(name); + int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1); + if (scaleTypeInt < 0) { + return null; + } + + ImageView imageView = (ImageView) view; + ImageView.ScaleType originalScaleType = imageView.getScaleType(); + + Matrix originalMatrix = null; + if (originalScaleType == ImageView.ScaleType.MATRIX) { + originalMatrix = new Matrix(imageView.getImageMatrix()); + } + + return Pair.create(originalScaleType, originalMatrix); } /** @@ -614,6 +652,21 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { return; } + if (view instanceof ImageView) { + int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1); + if (scaleTypeInt >= 0) { + ImageView imageView = (ImageView) view; + ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt]; + imageView.setScaleType(scaleType); + if (scaleType == ImageView.ScaleType.MATRIX) { + float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX); + Matrix matrix = new Matrix(); + matrix.setValues(matrixValues); + imageView.setImageMatrix(matrix); + } + } + } + float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z); view.setTranslationZ(z); @@ -666,6 +719,17 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { view.draw(canvas); sharedElementBundle.putParcelable(KEY_BITMAP, bitmap); + if (view instanceof ImageView) { + ImageView imageView = (ImageView) view; + int scaleTypeInt = scaleTypeToInt(imageView.getScaleType()); + sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt); + if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) { + float[] matrix = new float[9]; + imageView.getImageMatrix().getValues(matrix); + sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix); + } + } + transitionArgs.putBundle(name, sharedElementBundle); } @@ -829,6 +893,25 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } } + private static void setOriginalImageViewState( + ArrayMap> originalState) { + for (int i = 0; i < originalState.size(); i++) { + ImageView imageView = originalState.keyAt(i); + Pair state = originalState.valueAt(i); + imageView.setScaleType(state.first); + imageView.setImageMatrix(state.second); + } + } + + private static int scaleTypeToInt(ImageView.ScaleType scaleType) { + for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) { + if (scaleType == SCALE_TYPE_VALUES[i]) { + return i; + } + } + return -1; + } + private static class FixedEpicenterCallback extends Transition.EpicenterCallback { private Rect mEpicenter; diff --git a/core/java/android/transition/MoveImage.java b/core/java/android/transition/MoveImage.java index e4c3939956186..183cdd2397a89 100644 --- a/core/java/android/transition/MoveImage.java +++ b/core/java/android/transition/MoveImage.java @@ -125,7 +125,7 @@ public class MoveImage extends Transition { Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX); Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX); - if (!startMatrix.equals(endMatrix)) { + if (startMatrix != null && !startMatrix.equals(endMatrix)) { changes.add(PropertyValuesHolder.ofObject(MatrixClippedDrawable.MATRIX_PROPERTY, new MatrixEvaluator(), startMatrix, endMatrix)); } @@ -230,7 +230,9 @@ public class MoveImage extends Transition { private static void expandClip(Rect bounds, Matrix matrix, Rect clip, Rect otherClip) { RectF boundsF = new RectF(bounds); - matrix.mapRect(boundsF); + if (matrix != null) { + matrix.mapRect(boundsF); + } clip.left = expandMinDimension(boundsF.left, clip.left, otherClip.left); clip.top = expandMinDimension(boundsF.top, clip.top, otherClip.top); clip.right = expandMaxDimension(boundsF.right, clip.right, otherClip.right); @@ -256,10 +258,20 @@ public class MoveImage extends Transition { int drawableWidth = drawable.getIntrinsicWidth(); int drawableHeight = drawable.getIntrinsicHeight(); ImageView.ScaleType scaleType = imageView.getScaleType(); - if (drawableWidth <= 0 || drawableHeight <= 0 || scaleType == ImageView.ScaleType.FIT_XY) { - return null; + Matrix matrix; + if (drawableWidth <= 0 || drawableHeight <= 0) { + matrix = null; + } else if (scaleType == ImageView.ScaleType.FIT_XY) { + matrix = new Matrix(); + float scaleX = imageView.getWidth(); + scaleX /= drawableWidth; + float scaleY = imageView.getHeight(); + scaleY /= drawableHeight; + matrix.setScale(scaleX, scaleY); + } else { + matrix = new Matrix(imageView.getImageMatrix()); } - return new Matrix(imageView.getImageMatrix()); + return matrix; } private Rect findClip(ImageView imageView) {