1 /* 2 * Copyright (C) 2015 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.Rect; 21 import android.os.Debug; 22 import android.os.SystemClock; 23 import android.transition.ArcMotion; 24 import android.transition.AutoTransition; 25 import android.transition.ChangeBounds; 26 import android.transition.PathMotion; 27 import android.transition.Scene; 28 import android.transition.Transition; 29 import android.transition.Transition.EpicenterCallback; 30 import android.transition.Transition.TransitionListener; 31 import android.transition.TransitionManager; 32 import android.transition.TransitionPropagation; 33 import android.transition.TransitionValues; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.view.animation.AccelerateInterpolator; 37 import android.widget.ImageView; 38 import android.widget.RelativeLayout; 39 import android.widget.TextView; 40 41 import java.util.HashMap; 42 import java.util.concurrent.CountDownLatch; 43 import java.util.concurrent.TimeUnit; 44 45 public class TransitionTest extends BaseTransitionTest { 46 TransitionTest()47 public TransitionTest() { 48 } 49 testAddListener()50 public void testAddListener() throws Throwable { 51 startTransition(R.layout.scene1); 52 waitForStart(); 53 54 final SimpleTransitionListener listener2 = new SimpleTransitionListener(); 55 56 runTestOnUiThread(new Runnable() { 57 @Override 58 public void run() { 59 AutoTransition autoTransition = new AutoTransition(); 60 autoTransition.setDuration(100); 61 autoTransition.addListener(listener2); 62 Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity); 63 TransitionManager.go(scene, autoTransition); 64 } 65 }); 66 67 waitForStart(listener2); 68 69 assertEquals(0, mListener.pauseLatch.getCount()); 70 assertEquals(0, mListener.resumeLatch.getCount()); 71 assertEquals(1, mListener.cancelLatch.getCount()); 72 assertEquals(1, mListener.endLatch.getCount()); 73 assertEquals(0, mListener.startLatch.getCount()); 74 75 assertEquals(1, listener2.pauseLatch.getCount()); 76 assertEquals(1, listener2.resumeLatch.getCount()); 77 assertEquals(1, listener2.cancelLatch.getCount()); 78 assertEquals(1, listener2.endLatch.getCount()); 79 assertEquals(0, listener2.startLatch.getCount()); 80 endTransition(); 81 } 82 testRemoveListener()83 public void testRemoveListener() throws Throwable { 84 startTransition(R.layout.scene1); 85 waitForStart(); 86 87 runTestOnUiThread(new Runnable() { 88 @Override 89 public void run() { 90 mTransition.removeListener(mListener); 91 } 92 }); 93 94 assertFalse(mListener.endLatch.await(250, TimeUnit.MILLISECONDS)); 95 } 96 testAddTargetId()97 public void testAddTargetId() throws Throwable { 98 enterScene(R.layout.scene4); 99 assertNotNull(mTransition.getTargetIds()); 100 assertTrue(mTransition.getTargetIds().isEmpty()); 101 mTransition.addTarget(R.id.holder); 102 mTransition.addTarget(R.id.hello); 103 assertEquals(2, mTransition.getTargetIds().size()); 104 startTransition(R.layout.scene1); 105 assertEquals(1, mTargets.size()); 106 assertEquals(R.id.hello, mTargets.get(0).getId()); 107 endTransition(); 108 } 109 testRemoveTargetId()110 public void testRemoveTargetId() throws Throwable { 111 enterScene(R.layout.scene4); 112 mTransition.addTarget(R.id.holder); 113 mTransition.addTarget(R.id.hello); 114 mTransition.addTarget(R.id.redSquare); 115 assertEquals(3, mTransition.getTargetIds().size()); 116 mTransition.removeTarget(0); // nothing should happen 117 mTransition.removeTarget(R.id.redSquare); 118 assertEquals(2, mTransition.getTargetIds().size()); 119 120 startTransition(R.layout.scene1); 121 assertEquals(1, mTargets.size()); 122 assertEquals(R.id.hello, mTargets.get(0).getId()); 123 endTransition(); 124 } 125 testAddTargetClass()126 public void testAddTargetClass() throws Throwable { 127 enterScene(R.layout.scene4); 128 assertNull(mTransition.getTargetTypes()); 129 mTransition.addTarget(RelativeLayout.class); 130 mTransition.addTarget(TextView.class); 131 assertEquals(2, mTransition.getTargetTypes().size()); 132 startTransition(R.layout.scene1); 133 assertEquals(1, mTargets.size()); 134 assertTrue(mTargets.get(0) instanceof TextView); 135 endTransition(); 136 } 137 testRemoveTargetClass()138 public void testRemoveTargetClass() throws Throwable { 139 enterScene(R.layout.scene4); 140 mTransition.addTarget(TextView.class); 141 mTransition.addTarget(View.class); 142 mTransition.addTarget(RelativeLayout.class); 143 assertEquals(3, mTransition.getTargetTypes().size()); 144 mTransition.removeTarget(ImageView.class); // should do nothing 145 mTransition.removeTarget(View.class); 146 assertEquals(2, mTransition.getTargetTypes().size()); 147 startTransition(R.layout.scene1); 148 assertEquals(1, mTargets.size()); 149 assertTrue(mTargets.get(0) instanceof TextView); 150 endTransition(); 151 } 152 testAddTargetView()153 public void testAddTargetView() throws Throwable { 154 enterScene(R.layout.scene1); 155 156 final View[] target = new View[1]; 157 runTestOnUiThread(new Runnable() { 158 @Override 159 public void run() { 160 target[0] = mActivity.findViewById(R.id.hello); 161 } 162 }); 163 mTransition.addTarget(target[0]); 164 assertEquals(1, mTransition.getTargets().size()); 165 runTestOnUiThread(new Runnable() { 166 @Override 167 public void run() { 168 TransitionManager.beginDelayedTransition(mSceneRoot, mTransition); 169 target[0].setVisibility(View.GONE); 170 } 171 }); 172 waitForStart(); 173 assertEquals(1, mTargets.size()); 174 assertEquals(target[0], mTargets.get(0)); 175 endTransition(); 176 } 177 testRemoveTargetView()178 public void testRemoveTargetView() throws Throwable { 179 enterScene(R.layout.scene1); 180 181 final View[] target = new View[3]; 182 runTestOnUiThread(new Runnable() { 183 @Override 184 public void run() { 185 target[0] = mActivity.findViewById(R.id.hello); 186 target[1] = mActivity.findViewById(R.id.greenSquare); 187 target[2] = mActivity.findViewById(R.id.redSquare); 188 } 189 }); 190 191 mTransition.addTarget(target[0]); 192 mTransition.addTarget(target[1]); 193 assertEquals(2, mTransition.getTargets().size()); 194 mTransition.removeTarget(target[2]); // should do nothing 195 mTransition.removeTarget(target[1]); 196 assertEquals(1, mTransition.getTargets().size()); 197 runTestOnUiThread(new Runnable() { 198 @Override 199 public void run() { 200 TransitionManager.beginDelayedTransition(mSceneRoot, mTransition); 201 target[0].setVisibility(View.GONE); 202 } 203 }); 204 waitForStart(); 205 assertEquals(1, mTargets.size()); 206 assertEquals(target[0], mTargets.get(0)); 207 endTransition(); 208 } 209 testAddTargetName()210 public void testAddTargetName() throws Throwable { 211 enterScene(R.layout.scene4); 212 assertNull(mTransition.getTargetNames()); 213 mTransition.addTarget("red"); 214 mTransition.addTarget("holder"); 215 assertEquals(2, mTransition.getTargetNames().size()); 216 assertEquals(0, mTargets.size()); 217 startTransition(R.layout.scene2); 218 assertEquals(1, mTargets.size()); 219 assertEquals(R.id.redSquare, mTargets.get(0).getId()); 220 endTransition(); 221 } 222 testRemoveTargetName()223 public void testRemoveTargetName() throws Throwable { 224 enterScene(R.layout.scene4); 225 mTransition.addTarget("holder"); 226 mTransition.addTarget("red"); 227 mTransition.addTarget("green"); 228 assertEquals(3, mTransition.getTargetNames().size()); 229 mTransition.removeTarget("purple"); // should do nothing 230 // try to force a different String instance 231 String greenName = new StringBuilder("gre").append("en").toString(); 232 mTransition.removeTarget(greenName); 233 assertEquals(2, mTransition.getTargetNames().size()); 234 startTransition(R.layout.scene1); 235 assertEquals(1, mTargets.size()); 236 assertEquals(R.id.redSquare, mTargets.get(0).getId()); 237 endTransition(); 238 } 239 testIsTransitionRequired()240 public void testIsTransitionRequired() throws Throwable { 241 enterScene(R.layout.scene1); 242 mTransition = new NotRequiredTransition(); 243 resetListener(); 244 runTestOnUiThread(new Runnable() { 245 @Override 246 public void run() { 247 TransitionManager.beginDelayedTransition(mSceneRoot, mTransition); 248 mActivity.findViewById(R.id.hello).setVisibility(View.GONE); 249 } 250 }); 251 waitForStart(); 252 assertEquals(0, mTargets.size()); 253 endTransition(); 254 } 255 testCanRemoveViews()256 public void testCanRemoveViews() throws Throwable { 257 enterScene(R.layout.scene1); 258 assertFalse(mTransition.canRemoveViews()); 259 mTransition.addListener(new TransitionListener() { 260 @Override 261 public void onTransitionStart(Transition transition) { 262 assertTrue(transition.canRemoveViews()); 263 } 264 265 @Override 266 public void onTransitionEnd(Transition transition) { 267 } 268 269 @Override 270 public void onTransitionCancel(Transition transition) { 271 } 272 273 @Override 274 public void onTransitionPause(Transition transition) { 275 } 276 277 @Override 278 public void onTransitionResume(Transition transition) { 279 } 280 }); 281 startTransition(R.layout.scene2); 282 } 283 testExcludeChildrenView()284 public void testExcludeChildrenView() throws Throwable { 285 View layout1 = loadLayout(R.layout.scene1); 286 Scene scene1 = loadScene(layout1); 287 enterScene(R.layout.scene1); 288 View holder1 = layout1.findViewById(R.id.holder); 289 mTransition.excludeChildren(holder1, true); 290 View layout2 = loadLayout(R.layout.scene2); 291 Scene scene2 = loadScene(layout2); 292 View holder2 = layout2.findViewById(R.id.holder); 293 mTransition.excludeChildren(holder2, true); 294 startTransition(scene2); 295 waitForEnd(0); // Should already be ended, since no children are transitioning 296 297 mTransition.excludeChildren(holder1, false); // remove it 298 mTransition.excludeChildren(holder2, false); // remove it 299 resetListener(); 300 startTransition(scene1); 301 assertEquals(1, mListener.endLatch.getCount()); // it is running as expected 302 endTransition(); 303 } 304 testExcludeChildrenId()305 public void testExcludeChildrenId() throws Throwable { 306 enterScene(R.layout.scene1); 307 mTransition.excludeChildren(R.id.holder, true); 308 startTransition(R.layout.scene2); 309 waitForEnd(0); // Should already be ended, since no children are transitioning 310 311 resetListener(); 312 mTransition.excludeChildren(R.id.holder, false); // remove it 313 startTransition(R.layout.scene1); 314 assertEquals(1, mListener.endLatch.getCount()); // It is running 315 endTransition(); 316 } 317 testExcludeTargetView()318 public void testExcludeTargetView() throws Throwable { 319 View layout1 = loadLayout(R.layout.scene1); 320 Scene scene1 = loadScene(layout1); 321 enterScene(R.layout.scene1); 322 View redSquare1 = layout1.findViewById(R.id.redSquare); 323 mTransition.excludeTarget(redSquare1, true); 324 startTransition(R.layout.scene7); 325 waitForEnd(0); // Should already be ended, since no children are transitioning 326 327 mTransition.excludeTarget(redSquare1, false); // remove it 328 resetListener(); 329 startTransition(scene1); 330 assertEquals(1, mListener.endLatch.getCount()); // it is running as expected 331 endTransition(); 332 } 333 testExcludeTargetId()334 public void testExcludeTargetId() throws Throwable { 335 enterScene(R.layout.scene1); 336 mTransition.excludeTarget(R.id.redSquare, true); 337 startTransition(R.layout.scene7); 338 waitForEnd(0); // Should already be ended, since no children are transitioning 339 340 resetListener(); 341 mTransition.excludeTarget(R.id.redSquare, false); // remove it 342 startTransition(R.layout.scene1); 343 assertEquals(1, mListener.endLatch.getCount()); // It is running 344 endTransition(); 345 } 346 testExcludeTargetClass()347 public void testExcludeTargetClass() throws Throwable { 348 enterScene(R.layout.scene1); 349 mTransition.excludeTarget(TextView.class, true); 350 startTransition(R.layout.scene3); 351 waitForEnd(0); // Should already be ended, since no children are transitioning 352 353 resetListener(); 354 mTransition.excludeTarget(TextView.class, false); // remove it 355 startTransition(R.layout.scene1); 356 assertEquals(1, mListener.endLatch.getCount()); // It is running 357 endTransition(); 358 } 359 testExcludeTargetName()360 public void testExcludeTargetName() throws Throwable { 361 enterScene(R.layout.scene1); 362 mTransition.excludeTarget("hello", true); 363 startTransition(R.layout.scene3); 364 waitForEnd(0); // Should already be ended, since no children are transitioning 365 366 resetListener(); 367 mTransition.excludeTarget("hello", false); // remove it 368 startTransition(R.layout.scene1); 369 assertEquals(1, mListener.endLatch.getCount()); // It is running 370 endTransition(); 371 } 372 testDuration()373 public void testDuration() throws Throwable { 374 assertEquals(-1, mTransition.getDuration()); 375 enterScene(R.layout.scene1); 376 mTransition.setDuration(500); 377 assertEquals(500, mTransition.getDuration()); 378 startTransition(R.layout.scene3); 379 long startTime = SystemClock.uptimeMillis(); 380 waitForEnd(600); 381 long endTime = SystemClock.uptimeMillis(); 382 assertEquals(500, endTime - startTime, 100); 383 } 384 testEpicenter()385 public void testEpicenter() throws Throwable { 386 EpicenterCallback callback = new EpicenterCallback() { 387 @Override 388 public Rect onGetEpicenter(Transition transition) { 389 return new Rect(0, 0, 1, 1); 390 } 391 }; 392 mTransition.setEpicenterCallback(callback); 393 assertEquals(callback, mTransition.getEpicenterCallback()); 394 } 395 testInterpolator()396 public void testInterpolator() throws Throwable { 397 enterScene(R.layout.scene1); 398 View redSquare = mActivity.findViewById(R.id.redSquare); 399 CaptureAnimatorTransition transition = new CaptureAnimatorTransition(); 400 assertNull(transition.getInterpolator()); 401 AccelerateInterpolator interpolator = new AccelerateInterpolator(); 402 transition.setInterpolator(interpolator); 403 assertSame(interpolator, transition.getInterpolator()); 404 mTransition = transition; 405 resetListener(); 406 startTransition(R.layout.scene4); 407 assertFalse(transition.animators.isEmpty()); 408 Animator animator = transition.animators.get(redSquare); 409 AnimationStartListener listener = transition.listeners.get(redSquare); 410 assertTrue(listener.startLatch.await(100, TimeUnit.MILLISECONDS)); 411 assertSame(interpolator, animator.getInterpolator()); 412 endTransition(); 413 } 414 testName()415 public void testName() throws Throwable { 416 assertEquals("android.transition.cts.BaseTransitionTest$TestTransition", 417 mTransition.getName()); 418 } 419 testPathMotion()420 public void testPathMotion() throws Throwable { 421 PathMotion pathMotion = new ArcMotion(); 422 mTransition.setPathMotion(pathMotion); 423 assertEquals(pathMotion, mTransition.getPathMotion()); 424 } 425 testPropagation()426 public void testPropagation() throws Throwable { 427 enterScene(R.layout.scene1); 428 CaptureAnimatorTransition transition = new CaptureAnimatorTransition(); 429 mTransition = transition; 430 TransitionPropagation yPropagation = new TransitionPropagation() { 431 private static final String TOP = "top value"; 432 private final String[] PROPERTIES = {TOP}; 433 434 @Override 435 public long getStartDelay(ViewGroup viewGroup, Transition transition, 436 TransitionValues startValues, TransitionValues endValues) { 437 int startTop = startValues == null ? 0 : (Integer) startValues.values.get(TOP); 438 int endTop = endValues == null ? 0 : (Integer) endValues.values.get(TOP); 439 return (startTop == 0) ? endTop : startTop; 440 } 441 442 @Override 443 public void captureValues(TransitionValues transitionValues) { 444 if (transitionValues.view != null) { 445 transitionValues.values.put(TOP, transitionValues.view.getTop()); 446 } 447 } 448 449 @Override 450 public String[] getPropagationProperties() { 451 return PROPERTIES; 452 } 453 }; 454 mTransition.setPropagation(yPropagation); 455 resetListener(); 456 457 View redSquare = mActivity.findViewById(R.id.redSquare); 458 View greenSquare = mActivity.findViewById(R.id.greenSquare); 459 int diffTop = greenSquare.getTop() - redSquare.getTop(); 460 startTransition(R.layout.scene4); 461 Animator redSquareAnimator = transition.animators.get(redSquare); 462 Animator greenSquareAnimator = transition.animators.get(greenSquare); 463 AnimationStartListener listener = transition.listeners.get(redSquare); 464 assertTrue(listener.startLatch.await(100, TimeUnit.MILLISECONDS)); 465 assertEquals(0, redSquareAnimator.getStartDelay()); 466 assertEquals(diffTop, greenSquareAnimator.getStartDelay()); 467 endTransition(); 468 } 469 testStartDelay()470 public void testStartDelay() throws Throwable { 471 CaptureAnimatorTransition transition = new CaptureAnimatorTransition(); 472 mTransition = transition; 473 resetListener(); 474 enterScene(R.layout.scene1); 475 View redSquare = mActivity.findViewById(R.id.redSquare); 476 477 assertEquals(-1, mTransition.getStartDelay()); 478 mTransition.setStartDelay(200); 479 assertEquals(200, mTransition.getStartDelay()); 480 481 startTransition(R.layout.scene4); 482 483 Animator animator = transition.animators.get(redSquare); 484 assertFalse(animator.isRunning()); 485 AnimationStartListener listener = transition.listeners.get(redSquare); 486 assertTrue(listener.startLatch.await(250, TimeUnit.MILLISECONDS)); 487 endTransition(); 488 } 489 testTransitionValues()490 public void testTransitionValues() throws Throwable { 491 enterScene(R.layout.scene1); 492 mTransition = new CheckTransitionValuesTransition(); 493 mTransition.setDuration(10); 494 resetListener(); 495 startTransition(R.layout.scene4); 496 // The transition has all the asserts in it, so we can just end it now. 497 endTransition(); 498 } 499 testMatchOrder()500 public void testMatchOrder() throws Throwable { 501 mTransition = new ChangeBounds(); 502 resetListener(); 503 enterScene(R.layout.scene1); 504 startTransition(R.layout.scene8); 505 506 // scene 8 swaps the ids, but not the names. No transition should happen. 507 waitForEnd(0); 508 509 // now change the match order to prefer the id 510 mTransition.setMatchOrder(new int[] {Transition.MATCH_ID, Transition.MATCH_NAME}); 511 512 resetListener(); 513 startTransition(R.layout.scene1); 514 assertEquals(1, mListener.endLatch.getCount()); 515 waitForEnd(400); 516 } 517 518 private class NotRequiredTransition extends TestTransition { 519 @Override isTransitionRequired(TransitionValues startValues, TransitionValues newValues)520 public boolean isTransitionRequired(TransitionValues startValues, 521 TransitionValues newValues) { 522 return false; 523 } 524 } 525 526 private class CaptureAnimatorTransition extends TestTransition { 527 public HashMap<View, Animator> animators = new HashMap<>(); 528 public HashMap<View, AnimationStartListener> listeners = new HashMap<>(); 529 530 @Override onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)531 public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, 532 TransitionValues endValues) { 533 return setupAnimator(super.onAppear(sceneRoot, view, startValues, endValues), 534 endValues.view); 535 } 536 537 @Override onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)538 public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, 539 TransitionValues endValues) { 540 return setupAnimator(super.onDisappear(sceneRoot, view, startValues, endValues), 541 startValues.view); 542 } 543 setupAnimator(Animator animator, View view)544 private Animator setupAnimator(Animator animator, View view) { 545 animators.put(view, animator); 546 AnimationStartListener listener = new AnimationStartListener(); 547 animator.addListener(listener); 548 listeners.put(view, listener); 549 return animator; 550 } 551 } 552 553 private class CheckTransitionValuesTransition extends TestTransition { 554 @Override onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)555 public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, 556 TransitionValues endValues) { 557 assertNull(getTransitionValues(endValues.view, true)); 558 assertEquals(endValues, getTransitionValues(endValues.view, false)); 559 return super.onAppear(sceneRoot, view, startValues, endValues); 560 } 561 562 @Override onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues)563 public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, 564 TransitionValues endValues) { 565 assertNull(getTransitionValues(startValues.view, false)); 566 assertEquals(startValues, getTransitionValues(startValues.view, true)); 567 return super.onDisappear(sceneRoot, view, startValues, endValues); 568 } 569 } 570 571 private class AnimationStartListener extends AnimatorListenerAdapter { 572 public CountDownLatch startLatch = new CountDownLatch(1); 573 574 @Override onAnimationStart(Animator animation)575 public void onAnimationStart(Animator animation) { 576 startLatch.countDown(); 577 } 578 } 579 } 580 581