1 /* 2 * Copyright (C) 2016 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 package android.transition.cts; 17 18 import android.animation.Animator; 19 import android.animation.AnimatorListenerAdapter; 20 import android.graphics.Matrix; 21 import android.graphics.drawable.Drawable; 22 import android.transition.ChangeImageTransform; 23 import android.transition.TransitionManager; 24 import android.transition.TransitionValues; 25 import android.util.DisplayMetrics; 26 import android.util.TypedValue; 27 import android.view.ViewGroup; 28 import android.view.ViewGroup.LayoutParams; 29 import android.widget.ImageView; 30 import android.widget.ImageView.ScaleType; 31 32 public class ChangeImageTransformTest extends BaseTransitionTest { 33 ChangeImageTransform mChangeImageTransform; 34 Matrix mStartMatrix; 35 Matrix mEndMatrix; 36 Drawable mImage; 37 ImageView mImageView; 38 39 @Override setUp()40 protected void setUp() throws Exception { 41 super.setUp(); 42 resetTransition(); 43 mStartMatrix = null; 44 mEndMatrix = null; 45 mImage = null; 46 mImageView = null; 47 } 48 resetTransition()49 private void resetTransition() { 50 mChangeImageTransform = new CaptureMatrix(); 51 mChangeImageTransform.setDuration(100); 52 mTransition = mChangeImageTransform; 53 resetListener(); 54 } 55 testCenterToFitXY()56 public void testCenterToFitXY() throws Throwable { 57 transformImage(ScaleType.CENTER, ScaleType.FIT_XY); 58 assertMatrixMatches(centerMatrix(), mStartMatrix); 59 assertMatrixMatches(fitXYMatrix(), mEndMatrix); 60 } 61 testCenterCropToFitCenter()62 public void testCenterCropToFitCenter() throws Throwable { 63 transformImage(ScaleType.CENTER_CROP, ScaleType.FIT_CENTER); 64 assertMatrixMatches(centerCropMatrix(), mStartMatrix); 65 assertMatrixMatches(fitCenterMatrix(), mEndMatrix); 66 } 67 testCenterInsideToFitEnd()68 public void testCenterInsideToFitEnd() throws Throwable { 69 transformImage(ScaleType.CENTER_INSIDE, ScaleType.FIT_END); 70 // CENTER_INSIDE and CENTER are the same when the image is smaller than the View 71 assertMatrixMatches(centerMatrix(), mStartMatrix); 72 assertMatrixMatches(fitEndMatrix(), mEndMatrix); 73 } 74 testFitStartToCenter()75 public void testFitStartToCenter() throws Throwable { 76 transformImage(ScaleType.FIT_START, ScaleType.CENTER); 77 assertMatrixMatches(fitStartMatrix(), mStartMatrix); 78 assertMatrixMatches(centerMatrix(), mEndMatrix); 79 } 80 centerMatrix()81 private Matrix centerMatrix() { 82 int imageWidth = mImage.getIntrinsicWidth(); 83 int imageViewWidth = mImageView.getWidth(); 84 float tx = Math.round((imageViewWidth - imageWidth)/2f); 85 86 int imageHeight = mImage.getIntrinsicHeight(); 87 int imageViewHeight = mImageView.getHeight(); 88 float ty = Math.round((imageViewHeight - imageHeight)/2f); 89 90 Matrix matrix = new Matrix(); 91 matrix.postTranslate(tx, ty); 92 return matrix; 93 } 94 fitXYMatrix()95 private Matrix fitXYMatrix() { 96 int imageWidth = mImage.getIntrinsicWidth(); 97 int imageViewWidth = mImageView.getWidth(); 98 float scaleX = ((float)imageViewWidth)/imageWidth; 99 100 int imageHeight = mImage.getIntrinsicHeight(); 101 int imageViewHeight = mImageView.getHeight(); 102 float scaleY = ((float)imageViewHeight)/imageHeight; 103 104 Matrix matrix = new Matrix(); 105 matrix.postScale(scaleX, scaleY); 106 return matrix; 107 } 108 centerCropMatrix()109 private Matrix centerCropMatrix() { 110 int imageWidth = mImage.getIntrinsicWidth(); 111 int imageViewWidth = mImageView.getWidth(); 112 float scaleX = ((float)imageViewWidth)/imageWidth; 113 114 int imageHeight = mImage.getIntrinsicHeight(); 115 int imageViewHeight = mImageView.getHeight(); 116 float scaleY = ((float)imageViewHeight)/imageHeight; 117 118 float maxScale = Math.max(scaleX, scaleY); 119 120 float width = imageWidth * maxScale; 121 float height = imageHeight * maxScale; 122 float tx = Math.round((imageViewWidth - width) / 2f); 123 float ty = Math.round((imageViewHeight - height) / 2f); 124 125 Matrix matrix = new Matrix(); 126 matrix.postScale(maxScale, maxScale); 127 matrix.postTranslate(tx, ty); 128 return matrix; 129 } 130 fitCenterMatrix()131 private Matrix fitCenterMatrix() { 132 int imageWidth = mImage.getIntrinsicWidth(); 133 int imageViewWidth = mImageView.getWidth(); 134 float scaleX = ((float)imageViewWidth)/imageWidth; 135 136 int imageHeight = mImage.getIntrinsicHeight(); 137 int imageViewHeight = mImageView.getHeight(); 138 float scaleY = ((float)imageViewHeight)/imageHeight; 139 140 float minScale = Math.min(scaleX, scaleY); 141 142 float width = imageWidth * minScale; 143 float height = imageHeight * minScale; 144 float tx = (imageViewWidth - width) / 2f; 145 float ty = (imageViewHeight - height) / 2f; 146 147 Matrix matrix = new Matrix(); 148 matrix.postScale(minScale, minScale); 149 matrix.postTranslate(tx, ty); 150 return matrix; 151 } 152 fitStartMatrix()153 private Matrix fitStartMatrix() { 154 int imageWidth = mImage.getIntrinsicWidth(); 155 int imageViewWidth = mImageView.getWidth(); 156 float scaleX = ((float)imageViewWidth)/imageWidth; 157 158 int imageHeight = mImage.getIntrinsicHeight(); 159 int imageViewHeight = mImageView.getHeight(); 160 float scaleY = ((float)imageViewHeight)/imageHeight; 161 162 float minScale = Math.min(scaleX, scaleY); 163 164 Matrix matrix = new Matrix(); 165 matrix.postScale(minScale, minScale); 166 return matrix; 167 } 168 fitEndMatrix()169 private Matrix fitEndMatrix() { 170 int imageWidth = mImage.getIntrinsicWidth(); 171 int imageViewWidth = mImageView.getWidth(); 172 float scaleX = ((float)imageViewWidth)/imageWidth; 173 174 int imageHeight = mImage.getIntrinsicHeight(); 175 int imageViewHeight = mImageView.getHeight(); 176 float scaleY = ((float)imageViewHeight)/imageHeight; 177 178 float minScale = Math.min(scaleX, scaleY); 179 180 float width = imageWidth * minScale; 181 float height = imageHeight * minScale; 182 float tx = imageViewWidth - width; 183 float ty = imageViewHeight - height; 184 185 Matrix matrix = new Matrix(); 186 matrix.postScale(minScale, minScale); 187 matrix.postTranslate(tx, ty); 188 return matrix; 189 } 190 assertMatrixMatches(Matrix expected, Matrix matrix)191 private void assertMatrixMatches(Matrix expected, Matrix matrix) { 192 if (expected == null) { 193 assertNull(matrix); 194 return; 195 } 196 assertNotNull(matrix); 197 float[] expectedValues = new float[9]; 198 expected.getValues(expectedValues); 199 200 float[] values = new float[9]; 201 matrix.getValues(values); 202 203 for (int i = 0; i < values.length; i++) { 204 final float expectedValue = expectedValues[i]; 205 final float value = values[i]; 206 assertEquals("Value [" + i + "]", expectedValue, value, 0.01f); 207 } 208 } 209 transformImage(ScaleType startScale, final ScaleType endScale)210 private void transformImage(ScaleType startScale, final ScaleType endScale) throws Throwable { 211 final ImageView imageView = enterImageViewScene(startScale); 212 runTestOnUiThread(new Runnable() { 213 @Override 214 public void run() { 215 TransitionManager.beginDelayedTransition(mSceneRoot, mChangeImageTransform); 216 imageView.setScaleType(endScale); 217 } 218 }); 219 waitForStart(); 220 int expectedEndCount = (startScale == endScale) ? 0 : 1; 221 assertEquals(expectedEndCount, mListener.endLatch.getCount()); 222 waitForEnd(200); 223 } 224 enterImageViewScene(final ScaleType scaleType)225 private ImageView enterImageViewScene(final ScaleType scaleType) throws Throwable { 226 enterScene(R.layout.scene4); 227 final ViewGroup container = (ViewGroup) mActivity.findViewById(R.id.holder); 228 final ImageView[] imageViews = new ImageView[1]; 229 runTestOnUiThread(new Runnable() { 230 @Override 231 public void run() { 232 mImageView = new ImageView(mActivity); 233 mImage = mActivity.getDrawable(android.R.drawable.ic_media_play); 234 mImageView.setImageDrawable(mImage); 235 mImageView.setScaleType(scaleType); 236 imageViews[0] = mImageView; 237 container.addView(mImageView); 238 LayoutParams layoutParams = mImageView.getLayoutParams(); 239 DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics(); 240 float size = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, metrics); 241 layoutParams.width = Math.round(size); 242 layoutParams.height = Math.round(size * 2); 243 mImageView.setLayoutParams(layoutParams); 244 } 245 }); 246 getInstrumentation().waitForIdleSync(); 247 return imageViews[0]; 248 } 249 250 private class CaptureMatrix extends ChangeImageTransform { 251 @Override createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues)252 public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, 253 TransitionValues endValues) { 254 Animator animator = super.createAnimator(sceneRoot, startValues, endValues); 255 animator.addListener(new CaptureMatrixListener((ImageView) endValues.view)); 256 return animator; 257 } 258 } 259 260 private class CaptureMatrixListener extends AnimatorListenerAdapter { 261 private final ImageView mImageView; 262 CaptureMatrixListener(ImageView view)263 public CaptureMatrixListener(ImageView view) { 264 mImageView = view; 265 } 266 267 @Override onAnimationStart(Animator animation)268 public void onAnimationStart(Animator animation) { 269 mStartMatrix = copyMatrix(); 270 } 271 272 @Override onAnimationEnd(Animator animation)273 public void onAnimationEnd(Animator animation) { 274 mEndMatrix = copyMatrix(); 275 } 276 copyMatrix()277 private Matrix copyMatrix() { 278 Matrix matrix = mImageView.getImageMatrix(); 279 if (matrix != null) { 280 matrix = new Matrix(matrix); 281 } 282 return matrix; 283 } 284 } 285 } 286 287