diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java index d7727435fbd87..060bbe61e4073 100644 --- a/core/java/android/app/SharedElementCallback.java +++ b/core/java/android/app/SharedElementCallback.java @@ -23,6 +23,7 @@ import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.os.Parcelable; +import android.transition.TransitionUtils; import android.view.View; import java.util.List; @@ -141,21 +142,12 @@ public abstract class SharedElementCallback { */ public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, RectF screenBounds) { - int bitmapWidth = Math.round(screenBounds.width()); - int bitmapHeight = Math.round(screenBounds.height()); - Bitmap bitmap = null; - if (bitmapWidth > 0 && bitmapHeight > 0) { - if (mTempMatrix == null) { - mTempMatrix = new Matrix(); - } + if (mTempMatrix == null) { + mTempMatrix = new Matrix(viewToGlobalMatrix); + } else { mTempMatrix.set(viewToGlobalMatrix); - mTempMatrix.postTranslate(-screenBounds.left, -screenBounds.top); - bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - canvas.concat(mTempMatrix); - sharedElement.draw(canvas); } - return bitmap; + return TransitionUtils.createViewBitmap(sharedElement, mTempMatrix, screenBounds); } /** diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java index a84ecd1297d49..03423ffefaa4b 100644 --- a/core/java/android/transition/TransitionUtils.java +++ b/core/java/android/transition/TransitionUtils.java @@ -19,7 +19,14 @@ package android.transition; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.TypeEvaluator; +import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; /** * Static utility methods for Transitions. @@ -27,6 +34,7 @@ import android.graphics.Matrix; * @hide */ public class TransitionUtils { + private static int MAX_IMAGE_SIZE = (1024 * 1024); static Animator mergeAnimators(Animator animator1, Animator animator2) { if (animator1 == null) { @@ -67,6 +75,70 @@ public class TransitionUtils { return transitionSet; } + /** + * Creates a View using the bitmap copy of view. If view is large, + * the copy will use a scaled bitmap of the given view. + * + * @param sceneRoot The ViewGroup in which the view copy will be displayed. + * @param view The view to create a copy of. + * @param parent The parent of view. + */ + public static View copyViewImage(ViewGroup sceneRoot, View view, View parent) { + Matrix matrix = new Matrix(); + matrix.setTranslate(-parent.getScrollX(), -parent.getScrollY()); + view.transformMatrixToGlobal(matrix); + sceneRoot.transformMatrixToLocal(matrix); + RectF bounds = new RectF(0, 0, view.getWidth(), view.getHeight()); + matrix.mapRect(bounds); + int left = Math.round(bounds.left); + int top = Math.round(bounds.top); + int right = Math.round(bounds.right); + int bottom = Math.round(bounds.bottom); + + ImageView copy = new ImageView(view.getContext()); + copy.setScaleType(ImageView.ScaleType.CENTER_CROP); + Bitmap bitmap = createViewBitmap(view, matrix, bounds); + if (bitmap != null) { + copy.setImageBitmap(bitmap); + } + int widthSpec = View.MeasureSpec.makeMeasureSpec(right - left, View.MeasureSpec.EXACTLY); + int heightSpec = View.MeasureSpec.makeMeasureSpec(bottom - top, View.MeasureSpec.EXACTLY); + copy.measure(widthSpec, heightSpec); + copy.layout(left, top, right, bottom); + return copy; + } + + /** + * Creates a Bitmap of the given view, using the Matrix matrix to transform to the local + * coordinates. matrix will be modified during the bitmap creation. + * + *

If the bitmap is large, it will be scaled uniformly down to at most 1MB size.

+ * @param view The view to create a bitmap for. + * @param matrix The matrix converting the view local coordinates to the coordinates that + * the bitmap will be displayed in. matrix will be modified before + * returning. + * @param bounds The bounds of the bitmap in the destination coordinate system (where the + * view should be presented. Typically, this is matrix.mapRect(viewBounds); + * @return A bitmap of the given view or null if bounds has no width or height. + */ + public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) { + Bitmap bitmap = null; + int bitmapWidth = Math.round(bounds.width()); + int bitmapHeight = Math.round(bounds.height()); + if (bitmapWidth > 0 && bitmapHeight > 0) { + float scale = Math.min(1f, ((float)MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight)); + bitmapWidth *= scale; + bitmapHeight *= scale; + matrix.postTranslate(-bounds.left, -bounds.top); + matrix.postScale(scale, scale); + bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.concat(matrix); + view.draw(canvas); + } + return bitmap; + } + public static class MatrixEvaluator implements TypeEvaluator { float[] mTempStartValues = new float[9]; diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index d87d0f99a0a9e..f58291f489496 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -224,11 +224,10 @@ public abstract class Visibility extends Transition { } } } - } - if (startValues == null) { + } else if (startValues == null && visInfo.endVisibility == View.VISIBLE) { visInfo.fadeIn = true; visInfo.visibilityChange = true; - } else if (endValues == null) { + } else if (endValues == null && visInfo.startVisibility == View.VISIBLE) { visInfo.fadeIn = false; visInfo.visibilityChange = true; } @@ -370,16 +369,14 @@ public abstract class Visibility extends Transition { overlayView = startView; } else if (startView.getParent() instanceof View) { View startParent = (View) startView.getParent(); - VisibilityInfo parentVisibilityInfo = null; + TransitionValues startParentValues = getTransitionValues(startParent, true); TransitionValues endParentValues = getMatchedTransitionValues(startParent, true); - if (endParentValues != null) { - TransitionValues startParentValues = getTransitionValues(startParent, true); - parentVisibilityInfo = - getVisibilityChangeInfo(startParentValues, endParentValues); - } - if (parentVisibilityInfo == null || !parentVisibilityInfo.visibilityChange) { - overlayView = copyViewImage(startView); + VisibilityInfo parentVisibilityInfo = + getVisibilityChangeInfo(startParentValues, endParentValues); + if (!parentVisibilityInfo.visibilityChange) { + overlayView = TransitionUtils.copyViewImage(sceneRoot, startView, + startParent); } else if (startParent.getParent() == null) { int id = startParent.getId(); if (id != View.NO_ID && sceneRoot.findViewById(id) != null @@ -485,26 +482,6 @@ public abstract class Visibility extends Transition { return null; } - private View copyViewImage(View view) { - int width = view.getWidth(); - int height = view.getHeight(); - if (width <= 0 || height <= 0) { - return null; - } - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - view.draw(canvas); - final BitmapDrawable drawable = new BitmapDrawable(bitmap); - - View overlayView = new View(view.getContext()); - overlayView.setBackground(drawable); - int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY); - int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); - overlayView.measure(widthSpec, heightSpec); - overlayView.layout(0, 0, width, height); - return overlayView; - } - @Override boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) { VisibilityInfo changeInfo = getVisibilityChangeInfo(oldValues, newValues);