Merge "Use hardware bitmap for shared element snapshots." into oc-mr1-dev

This commit is contained in:
George Mount
2017-08-23 20:52:34 +00:00
committed by Android (Google) Code Review
4 changed files with 112 additions and 28 deletions

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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<AnimatorSetActivity> {
Activity mActivity;
public FadeTransitionTest() {
@@ -129,6 +131,43 @@ public class FadeTransitionTest extends ActivityInstrumentationTestCase2<Animato
assertEquals(View.INVISIBLE, square1.getVisibility());
}
@SmallTest
public void testSnapshotView() throws Throwable {
final View square1 = mActivity.findViewById(R.id.square1);
final CountDownLatch disappearCalled = new CountDownLatch(1);
final Fade fadeOut = new Fade(Fade.MODE_OUT) {
@Override
public Animator onDisappear(ViewGroup sceneRoot, View view,
TransitionValues startValues,
TransitionValues endValues) {
assertNotSame(square1, view);
assertTrue(view instanceof ImageView);
ImageView imageView = (ImageView) view;
BitmapDrawable background = (BitmapDrawable) imageView.getDrawable();
Bitmap bitmap = background.getBitmap();
assertEquals(Bitmap.Config.HARDWARE, bitmap.getConfig());
Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
assertEquals(0xFFFF0000, copy.getPixel(1, 1));
disappearCalled.countDown();
return super.onDisappear(sceneRoot, view, startValues, endValues);
}
};
runTestOnUiThread(new Runnable() {
@Override
public void run() {
ViewGroup container = mActivity.findViewById(R.id.container);
TransitionManager.beginDelayedTransition(container, fadeOut);
container.removeView(square1);
FrameLayout parent = new FrameLayout(mActivity);
parent.addView(square1);
}
});
assertTrue(disappearCalled.await(1, TimeUnit.SECONDS));
}
public TransitionLatch setVisibilityInTransition(final Transition transition, int viewId,
final int visibility) throws Throwable {
final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.container);

View File

@@ -28,6 +28,8 @@ import android.widget.TextView;
import com.android.frameworks.coretests.R;
import java.lang.reflect.Field;
public class TransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
Activity mActivity;
public TransitionTest() {
@@ -77,27 +79,47 @@ public class TransitionTest extends ActivityInstrumentationTestCase2<AnimatorSet
fade.setEpicenterCallback(epicenterCallback);
Fade clone = (Fade) fade.clone();
assertEquals(fade.mStartDelay, clone.mStartDelay);
assertEquals(fade.mDuration, clone.mDuration);
assertEquals(fade.mInterpolator, clone.mInterpolator);
assertEquals(fade.mPropagation, clone.mPropagation);
assertFieldEquals(fade, clone, "mStartDelay");
assertFieldEquals(fade, clone, "mDuration");
assertFieldEquals(fade, clone, "mInterpolator");
assertFieldEquals(fade, clone, "mPropagation");
assertEquals(fade.getPathMotion(), clone.getPathMotion());
assertEquals(fade.getEpicenterCallback(), clone.getEpicenterCallback());
assertEquals(fade.mNameOverrides, clone.mNameOverrides);
assertEquals(fade.mMatchOrder, clone.mMatchOrder);
assertFieldEquals(fade, clone, "mNameOverrides");
assertFieldEquals(fade, clone, "mMatchOrder");
assertEquals(fade.mTargets, clone.mTargets);
assertEquals(fade.mTargetExcludes, clone.mTargetExcludes);
assertEquals(fade.mTargetChildExcludes, clone.mTargetChildExcludes);
assertFieldEquals(fade, clone, "mTargets");
assertFieldEquals(fade, clone, "mTargetExcludes");
assertFieldEquals(fade, clone, "mTargetChildExcludes");
assertEquals(fade.mTargetIds, clone.mTargetIds);
assertEquals(fade.mTargetIdExcludes, clone.mTargetIdExcludes);
assertEquals(fade.mTargetIdChildExcludes, clone.mTargetIdChildExcludes);
assertFieldEquals(fade, clone, "mTargetIds");
assertFieldEquals(fade, clone, "mTargetIdExcludes");
assertFieldEquals(fade, clone, "mTargetIdChildExcludes");
assertEquals(fade.mTargetNames, clone.mTargetNames);
assertEquals(fade.mTargetNameExcludes, clone.mTargetNameExcludes);
assertFieldEquals(fade, clone, "mTargetNames");
assertFieldEquals(fade, clone, "mTargetNameExcludes");
assertEquals(fade.mTargetTypes, clone.mTargetTypes);
assertEquals(fade.mTargetTypeExcludes, clone.mTargetTypeExcludes);
assertFieldEquals(fade, clone, "mTargetTypes");
assertFieldEquals(fade, clone, "mTargetTypeExcludes");
}
private static void assertFieldEquals(Fade fade1, Fade fade2, String fieldName)
throws NoSuchFieldException, IllegalAccessException {
Field field = findField(Fade.class, fieldName);
field.setAccessible(true);
assertEquals("Field '" + fieldName + "' value mismatch", field.get(fade1),
field.get(fade2));
}
private static Field findField(Class<?> 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);
}
}