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