1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.transition; 18 19import android.animation.Animator; 20import android.animation.AnimatorSet; 21import android.animation.TypeEvaluator; 22import android.graphics.Bitmap; 23import android.graphics.Canvas; 24import android.graphics.Matrix; 25import android.graphics.RectF; 26import android.view.View; 27import android.view.ViewGroup; 28import android.widget.ImageView; 29 30class TransitionUtils { 31 32 private static final int MAX_IMAGE_SIZE = 1024 * 1024; 33 34 /** 35 * Creates a View using the bitmap copy of <code>view</code>. If <code>view</code> is large, 36 * the copy will use a scaled bitmap of the given view. 37 * 38 * @param sceneRoot The ViewGroup in which the view copy will be displayed. 39 * @param view The view to create a copy of. 40 * @param parent The parent of view. 41 */ 42 static View copyViewImage(ViewGroup sceneRoot, View view, View parent) { 43 Matrix matrix = new Matrix(); 44 matrix.setTranslate(-parent.getScrollX(), -parent.getScrollY()); 45 ViewUtils.transformMatrixToGlobal(view, matrix); 46 ViewUtils.transformMatrixToLocal(sceneRoot, matrix); 47 RectF bounds = new RectF(0, 0, view.getWidth(), view.getHeight()); 48 matrix.mapRect(bounds); 49 int left = Math.round(bounds.left); 50 int top = Math.round(bounds.top); 51 int right = Math.round(bounds.right); 52 int bottom = Math.round(bounds.bottom); 53 54 ImageView copy = new ImageView(view.getContext()); 55 copy.setScaleType(ImageView.ScaleType.CENTER_CROP); 56 Bitmap bitmap = createViewBitmap(view, matrix, bounds); 57 if (bitmap != null) { 58 copy.setImageBitmap(bitmap); 59 } 60 int widthSpec = View.MeasureSpec.makeMeasureSpec(right - left, View.MeasureSpec.EXACTLY); 61 int heightSpec = View.MeasureSpec.makeMeasureSpec(bottom - top, View.MeasureSpec.EXACTLY); 62 copy.measure(widthSpec, heightSpec); 63 copy.layout(left, top, right, bottom); 64 return copy; 65 } 66 67 /** 68 * Creates a Bitmap of the given view, using the Matrix matrix to transform to the local 69 * coordinates. <code>matrix</code> will be modified during the bitmap creation. 70 * 71 * <p>If the bitmap is large, it will be scaled uniformly down to at most 1MB size.</p> 72 * 73 * @param view The view to create a bitmap for. 74 * @param matrix The matrix converting the view local coordinates to the coordinates that 75 * the bitmap will be displayed in. <code>matrix</code> will be modified before 76 * returning. 77 * @param bounds The bounds of the bitmap in the destination coordinate system (where the 78 * view should be presented. Typically, this is matrix.mapRect(viewBounds); 79 * @return A bitmap of the given view or null if bounds has no width or height. 80 */ 81 private static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) { 82 Bitmap bitmap = null; 83 int bitmapWidth = Math.round(bounds.width()); 84 int bitmapHeight = Math.round(bounds.height()); 85 if (bitmapWidth > 0 && bitmapHeight > 0) { 86 float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight)); 87 bitmapWidth = (int) (bitmapWidth * scale); 88 bitmapHeight = (int) (bitmapHeight * scale); 89 matrix.postTranslate(-bounds.left, -bounds.top); 90 matrix.postScale(scale, scale); 91 bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); 92 Canvas canvas = new Canvas(bitmap); 93 canvas.concat(matrix); 94 view.draw(canvas); 95 } 96 return bitmap; 97 } 98 99 static Animator mergeAnimators(Animator animator1, Animator animator2) { 100 if (animator1 == null) { 101 return animator2; 102 } else if (animator2 == null) { 103 return animator1; 104 } else { 105 AnimatorSet animatorSet = new AnimatorSet(); 106 animatorSet.playTogether(animator1, animator2); 107 return animatorSet; 108 } 109 } 110 111 static class MatrixEvaluator implements TypeEvaluator<Matrix> { 112 113 final float[] mTempStartValues = new float[9]; 114 115 final float[] mTempEndValues = new float[9]; 116 117 final Matrix mTempMatrix = new Matrix(); 118 119 @Override 120 public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) { 121 startValue.getValues(mTempStartValues); 122 endValue.getValues(mTempEndValues); 123 for (int i = 0; i < 9; i++) { 124 float diff = mTempEndValues[i] - mTempStartValues[i]; 125 mTempEndValues[i] = mTempStartValues[i] + (fraction * diff); 126 } 127 mTempMatrix.setValues(mTempEndValues); 128 return mTempMatrix; 129 } 130 131 } 132 133} 134