From 3f81c33a35e69fcfcb6e1f3d486bc1f01015615b Mon Sep 17 00:00:00 2001 From: George Mount Date: Tue, 22 Aug 2017 08:19:56 -0700 Subject: [PATCH] Use hardware bitmap for shared element snapshots. Bug: 64851247 Drawing to software bitmaps does not support many features, most especially hardware bitmaps. This changes the implementation to using hardware bitmaps for View snapshots. Also fixed broken TransitionTest discovered while testing. Test: I4ede02db67e578ea4a25069b683f1989c611e06c Change-Id: I185bbfe1f789055c9efdba5297a74e481607afaf --- .../android/app/SharedElementCallback.java | 18 +++++-- .../android/transition/TransitionUtils.java | 23 +++++--- .../transition/FadeTransitionTest.java | 45 ++++++++++++++-- .../android/transition/TransitionTest.java | 54 +++++++++++++------ 4 files changed, 112 insertions(+), 28 deletions(-) diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java index bac84a4fcc9d8..af13e695108fd 100644 --- a/core/java/android/app/SharedElementCallback.java +++ b/core/java/android/app/SharedElementCallback.java @@ -18,6 +18,7 @@ package android.app; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.GraphicBuffer; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; @@ -44,6 +45,8 @@ import java.util.Map; public abstract class SharedElementCallback { private Matrix mTempMatrix; private static final String BUNDLE_SNAPSHOT_BITMAP = "sharedElement:snapshot:bitmap"; + private static final String BUNDLE_SNAPSHOT_GRAPHIC_BUFFER = + "sharedElement:snapshot:graphicBuffer"; private static final String BUNDLE_SNAPSHOT_IMAGE_SCALETYPE = "sharedElement:snapshot:imageScaleType"; private static final String BUNDLE_SNAPSHOT_IMAGE_MATRIX = "sharedElement:snapshot:imageMatrix"; @@ -176,7 +179,12 @@ public abstract class SharedElementCallback { Bitmap bitmap = TransitionUtils.createDrawableBitmap(d); if (bitmap != null) { Bundle bundle = new Bundle(); - bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap); + if (bitmap.getConfig() != Bitmap.Config.HARDWARE) { + bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap); + } else { + GraphicBuffer graphicBuffer = bitmap.createGraphicBufferHandle(); + bundle.putParcelable(BUNDLE_SNAPSHOT_GRAPHIC_BUFFER, graphicBuffer); + } bundle.putString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE, imageView.getScaleType().toString()); if (imageView.getScaleType() == ScaleType.MATRIX) { @@ -218,10 +226,14 @@ public abstract class SharedElementCallback { View view = null; if (snapshot instanceof Bundle) { Bundle bundle = (Bundle) snapshot; - Bitmap bitmap = (Bitmap) bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP); - if (bitmap == null) { + GraphicBuffer buffer = bundle.getParcelable(BUNDLE_SNAPSHOT_GRAPHIC_BUFFER); + Bitmap bitmap = bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP); + if (buffer == null && bitmap == null) { return null; } + if (bitmap == null) { + bitmap = Bitmap.createHardwareBitmap(buffer); + } ImageView imageView = new ImageView(context); view = imageView; imageView.setImageBitmap(bitmap); diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java index 49ceb3b5365e7..4951237e5cc9c 100644 --- a/core/java/android/transition/TransitionUtils.java +++ b/core/java/android/transition/TransitionUtils.java @@ -20,12 +20,14 @@ 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.Rect; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.view.DisplayListCanvas; +import android.view.RenderNode; +import android.view.ThreadedRenderer; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -126,8 +128,11 @@ public class TransitionUtils { } int bitmapWidth = (int) (width * scale); int bitmapHeight = (int) (height * scale); - Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); + final RenderNode node = RenderNode.create("TransitionUtils", null); + node.setLeftTopRightBottom(0, 0, width, height); + node.setClipToBounds(false); + final DisplayListCanvas canvas = node.start(width, height); + // Do stuff with the canvas Rect existingBounds = drawable.getBounds(); int left = existingBounds.left; int top = existingBounds.top; @@ -136,7 +141,8 @@ public class TransitionUtils { drawable.setBounds(0, 0, bitmapWidth, bitmapHeight); drawable.draw(canvas); drawable.setBounds(left, top, right, bottom); - return bitmap; + node.end(canvas); + return ThreadedRenderer.createHardwareBitmap(node, width, height); } /** @@ -162,10 +168,15 @@ public class TransitionUtils { 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); + + final RenderNode node = RenderNode.create("TransitionUtils", null); + node.setLeftTopRightBottom(0, 0, bitmapWidth, bitmapHeight); + node.setClipToBounds(false); + final DisplayListCanvas canvas = node.start(bitmapWidth, bitmapHeight); canvas.concat(matrix); view.draw(canvas); + node.end(canvas); + bitmap = ThreadedRenderer.createHardwareBitmap(node, bitmapWidth, bitmapHeight); } return bitmap; } diff --git a/core/tests/coretests/src/android/transition/FadeTransitionTest.java b/core/tests/coretests/src/android/transition/FadeTransitionTest.java index 674b36355ab09..22365bac64a2b 100644 --- a/core/tests/coretests/src/android/transition/FadeTransitionTest.java +++ b/core/tests/coretests/src/android/transition/FadeTransitionTest.java @@ -16,22 +16,24 @@ package android.transition; +import android.animation.Animator; import android.animation.AnimatorSetActivity; import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.SmallTest; import android.transition.Transition.TransitionListener; -import android.transition.TransitionListenerAdapter; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; import com.android.frameworks.coretests.R; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static android.support.test.espresso.Espresso.onView; - public class FadeTransitionTest extends ActivityInstrumentationTestCase2 { Activity mActivity; public FadeTransitionTest() { @@ -129,6 +131,43 @@ public class FadeTransitionTest extends ActivityInstrumentationTestCase2 { Activity mActivity; public TransitionTest() { @@ -77,27 +79,47 @@ public class TransitionTest extends ActivityInstrumentationTestCase2 type, String fieldName) throws NoSuchFieldException { + while (type != null) { + try { + return type.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + // try the parent + type = type.getSuperclass(); + } + } + throw new NoSuchFieldException(fieldName); } }