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