12dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos/* 22dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * Copyright (C) 2014 The Android Open Source Project 32dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * 42dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * Licensed under the Apache License, Version 2.0 (the "License"); 52dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * you may not use this file except in compliance with the License. 62dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * You may obtain a copy of the License at 72dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * 82dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * http://www.apache.org/licenses/LICENSE-2.0 92dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * 102dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * Unless required by applicable law or agreed to in writing, software 112dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * distributed under the License is distributed on an "AS IS" BASIS, 122dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * See the License for the specific language governing permissions and 142dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * limitations under the License. 152dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos */ 162dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos 172dcab18c6c9381122df6e06a93912e53dff69408Paul Soulospackage android.transition; 182dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos 192dcab18c6c9381122df6e06a93912e53dff69408Paul Soulosimport android.animation.Animator; 202dcab18c6c9381122df6e06a93912e53dff69408Paul Soulosimport android.animation.AnimatorSet; 21c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Guimport android.animation.TypeEvaluator; 2279b2781aa763cbd770f690c16af4448139f37061George Mountimport android.graphics.Bitmap; 2379b2781aa763cbd770f690c16af4448139f37061George Mountimport android.graphics.Canvas; 24c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Guimport android.graphics.Matrix; 25017b13a50c1225ca338357dc1315befa38dc3e33Dake Guimport android.graphics.Rect; 2679b2781aa763cbd770f690c16af4448139f37061George Mountimport android.graphics.RectF; 2779b2781aa763cbd770f690c16af4448139f37061George Mountimport android.graphics.drawable.BitmapDrawable; 28017b13a50c1225ca338357dc1315befa38dc3e33Dake Guimport android.graphics.drawable.Drawable; 2979b2781aa763cbd770f690c16af4448139f37061George Mountimport android.view.View; 3079b2781aa763cbd770f690c16af4448139f37061George Mountimport android.view.ViewGroup; 3179b2781aa763cbd770f690c16af4448139f37061George Mountimport android.widget.ImageView; 322dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos 332dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos/** 342dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * Static utility methods for Transitions. 352dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * 362dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos * @hide 372dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos */ 382dcab18c6c9381122df6e06a93912e53dff69408Paul Soulospublic class TransitionUtils { 3979b2781aa763cbd770f690c16af4448139f37061George Mount private static int MAX_IMAGE_SIZE = (1024 * 1024); 402dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos 412dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos static Animator mergeAnimators(Animator animator1, Animator animator2) { 422dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos if (animator1 == null) { 432dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos return animator2; 442dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos } else if (animator2 == null) { 452dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos return animator1; 462dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos } else { 472dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos AnimatorSet animatorSet = new AnimatorSet(); 482dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos animatorSet.playTogether(animator1, animator2); 492dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos return animatorSet; 502dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos } 512dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos } 52c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu 53c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount public static Transition mergeTransitions(Transition... transitions) { 54c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount int count = 0; 55c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount int nonNullIndex = -1; 56c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount for (int i = 0; i < transitions.length; i++) { 57c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount if (transitions[i] != null) { 58c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount count++; 59c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount nonNullIndex = i; 60c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount } 61c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount } 62c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount 63c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount if (count == 0) { 64c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount return null; 65c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount } 66c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount 67c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount if (count == 1) { 68c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount return transitions[nonNullIndex]; 69c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount } 70c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount 71c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount TransitionSet transitionSet = new TransitionSet(); 72c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount for (int i = 0; i < transitions.length; i++) { 73c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount if (transitions[i] != null) { 74c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount transitionSet.addTransition(transitions[i]); 75c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount } 76c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount } 77c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount return transitionSet; 78c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount } 79c03da0e7a9ef721709d51cf8a2d539a5bd8a320eGeorge Mount 8079b2781aa763cbd770f690c16af4448139f37061George Mount /** 8179b2781aa763cbd770f690c16af4448139f37061George Mount * Creates a View using the bitmap copy of <code>view</code>. If <code>view</code> is large, 8279b2781aa763cbd770f690c16af4448139f37061George Mount * the copy will use a scaled bitmap of the given view. 8379b2781aa763cbd770f690c16af4448139f37061George Mount * 8479b2781aa763cbd770f690c16af4448139f37061George Mount * @param sceneRoot The ViewGroup in which the view copy will be displayed. 8579b2781aa763cbd770f690c16af4448139f37061George Mount * @param view The view to create a copy of. 8679b2781aa763cbd770f690c16af4448139f37061George Mount * @param parent The parent of view. 8779b2781aa763cbd770f690c16af4448139f37061George Mount */ 8879b2781aa763cbd770f690c16af4448139f37061George Mount public static View copyViewImage(ViewGroup sceneRoot, View view, View parent) { 8979b2781aa763cbd770f690c16af4448139f37061George Mount Matrix matrix = new Matrix(); 9079b2781aa763cbd770f690c16af4448139f37061George Mount matrix.setTranslate(-parent.getScrollX(), -parent.getScrollY()); 9179b2781aa763cbd770f690c16af4448139f37061George Mount view.transformMatrixToGlobal(matrix); 9279b2781aa763cbd770f690c16af4448139f37061George Mount sceneRoot.transformMatrixToLocal(matrix); 9379b2781aa763cbd770f690c16af4448139f37061George Mount RectF bounds = new RectF(0, 0, view.getWidth(), view.getHeight()); 9479b2781aa763cbd770f690c16af4448139f37061George Mount matrix.mapRect(bounds); 9579b2781aa763cbd770f690c16af4448139f37061George Mount int left = Math.round(bounds.left); 9679b2781aa763cbd770f690c16af4448139f37061George Mount int top = Math.round(bounds.top); 9779b2781aa763cbd770f690c16af4448139f37061George Mount int right = Math.round(bounds.right); 9879b2781aa763cbd770f690c16af4448139f37061George Mount int bottom = Math.round(bounds.bottom); 9979b2781aa763cbd770f690c16af4448139f37061George Mount 10079b2781aa763cbd770f690c16af4448139f37061George Mount ImageView copy = new ImageView(view.getContext()); 10179b2781aa763cbd770f690c16af4448139f37061George Mount copy.setScaleType(ImageView.ScaleType.CENTER_CROP); 10279b2781aa763cbd770f690c16af4448139f37061George Mount Bitmap bitmap = createViewBitmap(view, matrix, bounds); 10379b2781aa763cbd770f690c16af4448139f37061George Mount if (bitmap != null) { 10479b2781aa763cbd770f690c16af4448139f37061George Mount copy.setImageBitmap(bitmap); 10579b2781aa763cbd770f690c16af4448139f37061George Mount } 10679b2781aa763cbd770f690c16af4448139f37061George Mount int widthSpec = View.MeasureSpec.makeMeasureSpec(right - left, View.MeasureSpec.EXACTLY); 10779b2781aa763cbd770f690c16af4448139f37061George Mount int heightSpec = View.MeasureSpec.makeMeasureSpec(bottom - top, View.MeasureSpec.EXACTLY); 10879b2781aa763cbd770f690c16af4448139f37061George Mount copy.measure(widthSpec, heightSpec); 10979b2781aa763cbd770f690c16af4448139f37061George Mount copy.layout(left, top, right, bottom); 11079b2781aa763cbd770f690c16af4448139f37061George Mount return copy; 11179b2781aa763cbd770f690c16af4448139f37061George Mount } 11279b2781aa763cbd770f690c16af4448139f37061George Mount 11379b2781aa763cbd770f690c16af4448139f37061George Mount /** 114017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu * Get a copy of bitmap of given drawable, return null if intrinsic size is zero 115017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu */ 116017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu public static Bitmap createDrawableBitmap(Drawable drawable) { 117017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu int width = drawable.getIntrinsicWidth(); 118017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu int height = drawable.getIntrinsicHeight(); 119017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu if (width <= 0 || height <= 0) { 120017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu return null; 121017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu } 122017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu float scale = Math.min(1f, ((float)MAX_IMAGE_SIZE) / (width * height)); 123017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu if (drawable instanceof BitmapDrawable && scale == 1f) { 124017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu // return same bitmap if scale down not needed 125017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu return ((BitmapDrawable) drawable).getBitmap(); 126017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu } 127017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu int bitmapWidth = (int) (width * scale); 128017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu int bitmapHeight = (int) (height * scale); 129017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); 130017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu Canvas canvas = new Canvas(bitmap); 131017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu Rect existingBounds = drawable.getBounds(); 132017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu int left = existingBounds.left; 133017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu int top = existingBounds.top; 134017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu int right = existingBounds.right; 135017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu int bottom = existingBounds.bottom; 136017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu drawable.setBounds(0, 0, bitmapWidth, bitmapHeight); 137017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu drawable.draw(canvas); 138017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu drawable.setBounds(left, top, right, bottom); 139017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu return bitmap; 140017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu } 141017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu 142017b13a50c1225ca338357dc1315befa38dc3e33Dake Gu /** 14379b2781aa763cbd770f690c16af4448139f37061George Mount * Creates a Bitmap of the given view, using the Matrix matrix to transform to the local 14479b2781aa763cbd770f690c16af4448139f37061George Mount * coordinates. <code>matrix</code> will be modified during the bitmap creation. 14579b2781aa763cbd770f690c16af4448139f37061George Mount * 14679b2781aa763cbd770f690c16af4448139f37061George Mount * <p>If the bitmap is large, it will be scaled uniformly down to at most 1MB size.</p> 14779b2781aa763cbd770f690c16af4448139f37061George Mount * @param view The view to create a bitmap for. 14879b2781aa763cbd770f690c16af4448139f37061George Mount * @param matrix The matrix converting the view local coordinates to the coordinates that 14979b2781aa763cbd770f690c16af4448139f37061George Mount * the bitmap will be displayed in. <code>matrix</code> will be modified before 15079b2781aa763cbd770f690c16af4448139f37061George Mount * returning. 15179b2781aa763cbd770f690c16af4448139f37061George Mount * @param bounds The bounds of the bitmap in the destination coordinate system (where the 15279b2781aa763cbd770f690c16af4448139f37061George Mount * view should be presented. Typically, this is matrix.mapRect(viewBounds); 15379b2781aa763cbd770f690c16af4448139f37061George Mount * @return A bitmap of the given view or null if bounds has no width or height. 15479b2781aa763cbd770f690c16af4448139f37061George Mount */ 15579b2781aa763cbd770f690c16af4448139f37061George Mount public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) { 15679b2781aa763cbd770f690c16af4448139f37061George Mount Bitmap bitmap = null; 15779b2781aa763cbd770f690c16af4448139f37061George Mount int bitmapWidth = Math.round(bounds.width()); 15879b2781aa763cbd770f690c16af4448139f37061George Mount int bitmapHeight = Math.round(bounds.height()); 15979b2781aa763cbd770f690c16af4448139f37061George Mount if (bitmapWidth > 0 && bitmapHeight > 0) { 16079b2781aa763cbd770f690c16af4448139f37061George Mount float scale = Math.min(1f, ((float)MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight)); 16179b2781aa763cbd770f690c16af4448139f37061George Mount bitmapWidth *= scale; 16279b2781aa763cbd770f690c16af4448139f37061George Mount bitmapHeight *= scale; 16379b2781aa763cbd770f690c16af4448139f37061George Mount matrix.postTranslate(-bounds.left, -bounds.top); 16479b2781aa763cbd770f690c16af4448139f37061George Mount matrix.postScale(scale, scale); 16579b2781aa763cbd770f690c16af4448139f37061George Mount bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); 16679b2781aa763cbd770f690c16af4448139f37061George Mount Canvas canvas = new Canvas(bitmap); 16779b2781aa763cbd770f690c16af4448139f37061George Mount canvas.concat(matrix); 16879b2781aa763cbd770f690c16af4448139f37061George Mount view.draw(canvas); 16979b2781aa763cbd770f690c16af4448139f37061George Mount } 17079b2781aa763cbd770f690c16af4448139f37061George Mount return bitmap; 17179b2781aa763cbd770f690c16af4448139f37061George Mount } 17279b2781aa763cbd770f690c16af4448139f37061George Mount 173c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu public static class MatrixEvaluator implements TypeEvaluator<Matrix> { 174c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu 175c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu float[] mTempStartValues = new float[9]; 176c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu 177c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu float[] mTempEndValues = new float[9]; 178c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu 179c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu Matrix mTempMatrix = new Matrix(); 180c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu 181c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu @Override 182c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) { 183c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu startValue.getValues(mTempStartValues); 184c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu endValue.getValues(mTempEndValues); 185c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu for (int i = 0; i < 9; i++) { 186c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu float diff = mTempEndValues[i] - mTempStartValues[i]; 187c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu mTempEndValues[i] = mTempStartValues[i] + (fraction * diff); 188c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu } 189c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu mTempMatrix.setValues(mTempEndValues); 190c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu return mTempMatrix; 191c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu } 192c94e2b393f6eba684ee2c84eaa50746fc1459d0fDake Gu } 1932dcab18c6c9381122df6e06a93912e53dff69408Paul Soulos} 194