Merge "Fixed OOM due to visibility transitions." into lmp-dev

This commit is contained in:
George Mount
2014-09-15 18:12:21 +00:00
committed by Android (Google) Code Review
3 changed files with 85 additions and 44 deletions

View File

@@ -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);
}
/**

View File

@@ -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 <code>view</code>. If <code>view</code> 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. <code>matrix</code> will be modified during the bitmap creation.
*
* <p>If the bitmap is large, it will be scaled uniformly down to at most 1MB size.</p>
* @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. <code>matrix</code> 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<Matrix> {
float[] mTempStartValues = new float[9];

View File

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