Home | History | Annotate | Download | only in cts
      1 /*
      2 * Copyright (C) 2014 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.view.animation.cts;
     17 
     18 import static org.junit.Assert.assertEquals;
     19 import static org.junit.Assert.assertFalse;
     20 import static org.junit.Assert.assertNotSame;
     21 import static org.junit.Assert.assertSame;
     22 import static org.junit.Assert.assertTrue;
     23 
     24 import android.animation.Animator;
     25 import android.animation.AnimatorInflater;
     26 import android.animation.AnimatorListenerAdapter;
     27 import android.animation.AnimatorSet;
     28 import android.animation.ObjectAnimator;
     29 import android.animation.StateListAnimator;
     30 import android.app.Instrumentation;
     31 import android.app.UiAutomation;
     32 import android.content.Context;
     33 import android.util.Log;
     34 import android.view.Display;
     35 import android.view.Surface;
     36 import android.view.View;
     37 import android.view.WindowManager;
     38 import android.view.cts.R;
     39 
     40 import androidx.test.InstrumentationRegistry;
     41 import androidx.test.filters.MediumTest;
     42 import androidx.test.rule.ActivityTestRule;
     43 import androidx.test.runner.AndroidJUnit4;
     44 
     45 import org.junit.After;
     46 import org.junit.Before;
     47 import org.junit.Rule;
     48 import org.junit.Test;
     49 import org.junit.runner.RunWith;
     50 
     51 import java.util.HashSet;
     52 import java.util.Set;
     53 import java.util.concurrent.CountDownLatch;
     54 import java.util.concurrent.TimeUnit;
     55 
     56 @MediumTest
     57 @RunWith(AndroidJUnit4.class)
     58 public class AnimatorInflaterTest {
     59     private static final String TAG = "AnimatorInflaterTest";
     60 
     61     private Instrumentation mInstrumentation;
     62     private AnimationTestCtsActivity mActivity;
     63     private View mTestView;
     64     private int mUserRotation;
     65 
     66     Set<Integer> identityHashes = new HashSet<>();
     67 
     68     @Rule
     69     public ActivityTestRule<AnimationTestCtsActivity> mActivityRule =
     70             new ActivityTestRule<>(AnimationTestCtsActivity.class);
     71 
     72     @Before
     73     public void setup() {
     74         mInstrumentation = InstrumentationRegistry.getInstrumentation();
     75         mActivity = mActivityRule.getActivity();
     76         mTestView = mActivity.findViewById(R.id.anim_window);
     77         mUserRotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
     78     }
     79 
     80     @After
     81     public void tearDown() {
     82         mInstrumentation.getUiAutomation().setRotation(mUserRotation);
     83     }
     84 
     85     private void assertUnique(Object object) {
     86         assertUnique(object, "");
     87     }
     88 
     89     private void assertUnique(Object object, String msg) {
     90         final int code = System.identityHashCode(object);
     91         assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code));
     92     }
     93 
     94     @Test
     95     public void testLoadAnimatorWithDifferentInterpolators() throws Throwable {
     96         Animator anim1 = AnimatorInflater .loadAnimator(mActivity, R.anim.changing_test_animator);
     97         if (!rotate()) {
     98             return;//cancel test
     99         }
    100         Animator anim2 = AnimatorInflater .loadAnimator(mActivity, R.anim.changing_test_animator);
    101         assertNotSame(anim1, anim2);
    102         assertNotSame("interpolater is orientation dependent, should change",
    103                 anim1.getInterpolator(), anim2.getInterpolator());
    104     }
    105 
    106     /**
    107      * Tests animators with dimension references.
    108      */
    109     @Test
    110     public void testLoadAnimator() throws Throwable {
    111         // to identify objects
    112         Animator anim1 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
    113         Animator anim2 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
    114         assertNotSame("a different animation should be returned", anim1, anim2);
    115         assertSame("interpolator should be shallow cloned", anim1.getInterpolator(),
    116                 anim2.getInterpolator());
    117         for (int i = 0; i < 2; i++) {
    118             float targetX = mActivity.getResources()
    119                     .getDimension(R.dimen.test_animator_target_x);
    120             // y value changes in landscape orientation
    121             float targetY = mActivity.getResources()
    122                     .getDimension(R.dimen.test_animator_target_y);
    123             for (Animator anim : new Animator[]{anim1, anim2}) {
    124                 assertTrue(anim instanceof AnimatorSet);
    125                 assertUnique(anim);
    126                 AnimatorSet set = (AnimatorSet) anim;
    127                 assertEquals("should have 3 sub animations", 3, set.getChildAnimations().size());
    128                 for (Animator subAnim : set.getChildAnimations()) {
    129                     assertUnique(subAnim);
    130                     assertTrue(subAnim instanceof ObjectAnimator);
    131                 }
    132                 final ObjectAnimator child1 = (ObjectAnimator) set.getChildAnimations().get(0);
    133                 final ObjectAnimator child2 = (ObjectAnimator) set.getChildAnimations().get(1);
    134                 final DummyObject dummyObject = new DummyObject();
    135                 mActivityRule.runOnUiThread(() -> {
    136                     for (ObjectAnimator animator : new ObjectAnimator[]{child1, child2}) {
    137                         animator.setTarget(dummyObject);
    138                         animator.setupStartValues();
    139                         animator.start();
    140                         animator.end();
    141                     }
    142                 });
    143                 assertEquals(targetX, dummyObject.x, 0.0f);
    144                 assertEquals(targetY, dummyObject.y, 0.0f);
    145             }
    146             if (i == 0) {
    147                 if (!rotate()) {
    148                     return;//cancel test
    149                 }
    150             }
    151             anim1 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
    152             anim2 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
    153 
    154         }
    155     }
    156 
    157     private boolean rotate() throws Throwable {
    158         WindowManager mWindowManager = (WindowManager) mActivity
    159                 .getSystemService(Context.WINDOW_SERVICE);
    160         Display display = mWindowManager.getDefaultDisplay();
    161         int orientation = mActivity.getResources().getConfiguration().orientation;
    162 
    163         Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
    164                 mActivity.getClass().getName(), null, false);
    165         mInstrumentation.addMonitor(monitor);
    166         int nextRotation = 0;
    167         switch (display.getRotation()) {
    168             case Surface.ROTATION_0:
    169             case Surface.ROTATION_180:
    170                 nextRotation = UiAutomation.ROTATION_FREEZE_90;
    171                 break;
    172             case Surface.ROTATION_90:
    173             case Surface.ROTATION_270:
    174                 nextRotation = UiAutomation.ROTATION_FREEZE_0;
    175                 break;
    176             default:
    177                 Log.e(TAG, "Cannot get rotation, test is canceled");
    178                 return false;
    179         }
    180         boolean rotated = mInstrumentation.getUiAutomation().setRotation(nextRotation);
    181         Thread.sleep(500);
    182         if (!rotated) {
    183             Log.e(TAG, "Rotation failed, test is canceled");
    184         }
    185         mInstrumentation.waitForIdleSync();
    186         if (!mActivity.waitUntilVisible()) {
    187             Log.e(TAG, "Activity failed to complete rotation, canceling test");
    188             return false;
    189         }
    190         if (mActivity.getWindowManager().getDefaultDisplay().getRotation() != nextRotation) {
    191             Log.e(TAG, "New activity orientation does not match. Canceling test");
    192             return false;
    193         }
    194         if (mActivity.getResources().getConfiguration().orientation == orientation) {
    195             Log.e(TAG, "Screen orientation didn't change, test is canceled");
    196             return false;
    197         }
    198         return true;
    199     }
    200 
    201     /**
    202      * Simple state list animator test that checks for cloning
    203      */
    204     @Test
    205     public void testLoadStateListAnimator() {
    206         StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(mActivity,
    207                 R.anim.test_state_list_animator);
    208         StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(mActivity,
    209                 R.anim.test_state_list_animator);
    210         assertUnique(sla1);
    211         assertUnique(sla2);
    212     }
    213 
    214     /**
    215      * Tests a state list animator which has an @anim reference that has different xmls per
    216      * orientation
    217      */
    218     @Test
    219     public void testLoadStateListAnimatorWithChangingResetState() throws Throwable {
    220         loadStateListAnimatorWithChangingResetStateTest();
    221         if (!rotate()) {
    222             return;//cancel test
    223         }
    224 
    225         loadStateListAnimatorWithChangingResetStateTest();
    226     }
    227 
    228     private void loadStateListAnimatorWithChangingResetStateTest() throws Throwable {
    229         final StateListAnimator sla = AnimatorInflater.loadStateListAnimator(mActivity,
    230                 R.anim.test_state_list_animator_2);
    231         mActivityRule.runOnUiThread(() -> {
    232             mTestView.setStateListAnimator(sla);
    233             mTestView.jumpDrawablesToCurrentState();
    234         });
    235         float resetValue = mActivity.getResources().getDimension(R.dimen.reset_state_value);
    236         mInstrumentation.waitForIdleSync();
    237         assertEquals(resetValue, mTestView.getX(), 0.0f);
    238         assertEquals(resetValue, mTestView.getY(), 0.0f);
    239         assertEquals(resetValue, mTestView.getZ(), 0.0f);
    240     }
    241 
    242     /**
    243      * Tests a state list animator which has different xml descriptions per orientation.
    244      */
    245     @Test
    246     public void testLoadChangingStateListAnimator() throws Throwable {
    247         loadChangingStateListAnimatorTest();
    248         if (!rotate()) {
    249             return;//cancel test
    250         }
    251         loadChangingStateListAnimatorTest();
    252     }
    253 
    254     private void loadChangingStateListAnimatorTest() throws Throwable {
    255         final StateListAnimator sla = AnimatorInflater.loadStateListAnimator(mActivity,
    256                 R.anim.changing_state_list_animator);
    257         mActivityRule.runOnUiThread(() -> {
    258             mTestView.setStateListAnimator(sla);
    259             mTestView.jumpDrawablesToCurrentState();
    260         });
    261         float targetValue = mActivity.getResources()
    262                 .getDimension(R.dimen.changing_state_list_anim_target_x_value);
    263         mInstrumentation.waitForIdleSync();
    264         assertEquals(targetValue, mTestView.getX(), 0.0f);
    265     }
    266 
    267     /**
    268      * Tests that makes sure that reloaded animator is not affected by previous changes
    269      */
    270     @Test
    271     public void testReloadedAnimatorIsNotModified() throws Throwable {
    272         final Animator anim1 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
    273         final CountDownLatch mStarted = new CountDownLatch(1);
    274         final AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
    275             @Override
    276             public void onAnimationEnd(Animator animation) {
    277                 super.onAnimationEnd(animation);
    278             }
    279 
    280             @Override
    281             public void onAnimationStart(Animator animation) {
    282                 super.onAnimationStart(animation);
    283                 mStarted.countDown();
    284             }
    285         };
    286         mActivityRule.runOnUiThread(() -> {
    287             anim1.setTarget(mTestView);
    288             anim1.addListener(listener);
    289             anim1.start();
    290         });
    291         Animator anim2 = AnimatorInflater.loadAnimator(mActivity, R.anim.test_animator);
    292         assertTrue(anim1.isStarted());
    293         assertFalse(anim2.isStarted());
    294         assertFalse("anim2 should not include the listener",
    295                 anim2.getListeners() != null && anim2.getListeners().contains(listener));
    296         assertTrue("animator should start", mStarted.await(10, TimeUnit.SECONDS));
    297         assertFalse(anim2.isRunning());
    298 
    299     }
    300 
    301     class DummyObject {
    302 
    303         float x;
    304         float y;
    305 
    306         public float getX() {
    307             return x;
    308         }
    309 
    310         public void setX(float x) {
    311             this.x = x;
    312         }
    313 
    314         public float getY() {
    315             return y;
    316         }
    317 
    318         public void setY(float y) {
    319             this.y = y;
    320         }
    321     }
    322 }
    323 
    324