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 17 package com.android.server.wm; 18 19 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 20 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 21 import static android.view.WindowManager.TRANSIT_CHANGE; 22 import static android.view.WindowManager.TRANSIT_CLOSE; 23 import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; 24 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; 25 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; 26 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; 27 import static android.view.WindowManager.TRANSIT_NONE; 28 import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE; 29 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; 30 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; 31 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; 32 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; 33 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; 34 import static android.view.WindowManager.TRANSIT_OLD_UNSET; 35 import static android.view.WindowManager.TRANSIT_OPEN; 36 37 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 38 39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; 40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; 43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 45 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; 46 import static com.android.server.wm.WindowContainer.POSITION_TOP; 47 48 import static org.junit.Assert.assertEquals; 49 import static org.junit.Assert.assertFalse; 50 import static org.junit.Assert.assertNull; 51 import static org.junit.Assert.assertTrue; 52 import static org.junit.Assume.assumeFalse; 53 import static org.mockito.ArgumentMatchers.any; 54 import static org.mockito.ArgumentMatchers.anyBoolean; 55 import static org.mockito.Mockito.mock; 56 import static org.mockito.Mockito.never; 57 58 import android.graphics.Rect; 59 import android.os.Binder; 60 import android.os.IBinder; 61 import android.os.RemoteException; 62 import android.platform.test.annotations.Presubmit; 63 import android.util.ArraySet; 64 import android.view.Display; 65 import android.view.IRemoteAnimationFinishedCallback; 66 import android.view.IRemoteAnimationRunner; 67 import android.view.RemoteAnimationAdapter; 68 import android.view.RemoteAnimationTarget; 69 import android.view.SurfaceControl; 70 import android.view.WindowManager; 71 import android.view.animation.Animation; 72 import android.window.ITaskFragmentOrganizer; 73 import android.window.TaskFragmentOrganizer; 74 75 import androidx.test.filters.SmallTest; 76 77 import com.android.internal.policy.TransitionAnimation; 78 79 import org.junit.Before; 80 import org.junit.Test; 81 import org.junit.runner.RunWith; 82 83 /** 84 * Test class for {@link AppTransition}. 85 * 86 * Build/Install/Run: 87 * atest WmTests:AppTransitionTests 88 */ 89 @SmallTest 90 @Presubmit 91 @RunWith(WindowTestRunner.class) 92 public class AppTransitionTests extends WindowTestsBase { 93 private DisplayContent mDc; 94 95 @Before setUp()96 public void setUp() throws Exception { 97 doNothing().when(mWm.mRoot).performSurfacePlacement(); 98 mDc = mWm.getDefaultDisplayContentLocked(); 99 } 100 101 @Test testKeyguardOverride()102 public void testKeyguardOverride() { 103 final DisplayContent dc = createNewDisplay(Display.STATE_ON); 104 final ActivityRecord activity = createActivityRecord(dc); 105 106 mDc.prepareAppTransition(TRANSIT_OPEN); 107 mDc.prepareAppTransition(TRANSIT_KEYGUARD_OCCLUDE); 108 mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY); 109 mDc.mOpeningApps.add(activity); 110 assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY, 111 AppTransitionController.getTransitCompatType(mDc.mAppTransition, 112 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 113 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 114 null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); 115 } 116 117 @Test testKeyguardUnoccludeOcclude()118 public void testKeyguardUnoccludeOcclude() { 119 final DisplayContent dc = createNewDisplay(Display.STATE_ON); 120 final ActivityRecord activity = createActivityRecord(dc); 121 122 mDc.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE); 123 mDc.prepareAppTransition(TRANSIT_KEYGUARD_OCCLUDE); 124 mDc.mOpeningApps.add(activity); 125 assertEquals(TRANSIT_NONE, 126 AppTransitionController.getTransitCompatType(mDc.mAppTransition, 127 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 128 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 129 null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); 130 131 } 132 133 @Test testKeyguardKeep()134 public void testKeyguardKeep() { 135 final DisplayContent dc = createNewDisplay(Display.STATE_ON); 136 final ActivityRecord activity = createActivityRecord(dc); 137 138 mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY); 139 mDc.prepareAppTransition(TRANSIT_OPEN); 140 mDc.mOpeningApps.add(activity); 141 assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY, 142 AppTransitionController.getTransitCompatType(mDc.mAppTransition, 143 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 144 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 145 null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); 146 } 147 148 @Test testCrashing()149 public void testCrashing() { 150 final DisplayContent dc = createNewDisplay(Display.STATE_ON); 151 final ActivityRecord activity = createActivityRecord(dc); 152 153 mDc.prepareAppTransition(TRANSIT_OPEN); 154 mDc.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); 155 mDc.mClosingApps.add(activity); 156 assertEquals(TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE, 157 AppTransitionController.getTransitCompatType(mDc.mAppTransition, 158 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 159 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 160 null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); 161 } 162 163 @Test testKeepKeyguard_withCrashing()164 public void testKeepKeyguard_withCrashing() { 165 final DisplayContent dc = createNewDisplay(Display.STATE_ON); 166 final ActivityRecord activity = createActivityRecord(dc); 167 168 mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY); 169 mDc.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); 170 mDc.mClosingApps.add(activity); 171 assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY, 172 AppTransitionController.getTransitCompatType(mDc.mAppTransition, 173 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 174 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 175 null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); 176 } 177 178 @Test testSkipTransitionAnimation()179 public void testSkipTransitionAnimation() { 180 final DisplayContent dc = createNewDisplay(Display.STATE_ON); 181 final ActivityRecord activity = createActivityRecord(dc); 182 183 mDc.prepareAppTransition(TRANSIT_OPEN); 184 mDc.prepareAppTransition(TRANSIT_CLOSE); 185 mDc.mClosingApps.add(activity); 186 assertEquals(TRANSIT_OLD_UNSET, 187 AppTransitionController.getTransitCompatType(mDc.mAppTransition, 188 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 189 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 190 null /* oldWallpaper */, true /*skipAppTransitionAnimation*/)); 191 } 192 193 @Test testTaskChangeWindowingMode()194 public void testTaskChangeWindowingMode() { 195 final ActivityRecord activity = createActivityRecord(mDc); 196 197 mDc.prepareAppTransition(TRANSIT_OPEN); 198 mDc.prepareAppTransition(TRANSIT_CHANGE); 199 mDc.mOpeningApps.add(activity); // Make sure TRANSIT_CHANGE has the priority 200 mDc.mChangingContainers.add(activity.getTask()); 201 202 assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, 203 AppTransitionController.getTransitCompatType(mDc.mAppTransition, 204 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 205 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 206 null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); 207 } 208 209 @Test testTaskFragmentChange()210 public void testTaskFragmentChange() { 211 final ActivityRecord activity = createActivityRecord(mDc); 212 final TaskFragment taskFragment = new TaskFragment(mAtm, new Binder(), 213 true /* createdByOrganizer */, true /* isEmbedded */); 214 activity.getTask().addChild(taskFragment, POSITION_TOP); 215 activity.reparent(taskFragment, POSITION_TOP); 216 217 mDc.prepareAppTransition(TRANSIT_OPEN); 218 mDc.prepareAppTransition(TRANSIT_CHANGE); 219 mDc.mOpeningApps.add(activity); // Make sure TRANSIT_CHANGE has the priority 220 mDc.mChangingContainers.add(taskFragment); 221 222 assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, 223 AppTransitionController.getTransitCompatType(mDc.mAppTransition, 224 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 225 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 226 null /* oldWallpaper */, false /*skipAppTransitionAnimation*/)); 227 } 228 229 @Test testTaskFragmentOpeningTransition()230 public void testTaskFragmentOpeningTransition() { 231 final ActivityRecord activity = createHierarchyForTaskFragmentTest(); 232 activity.setVisible(false); 233 234 mDisplayContent.prepareAppTransition(TRANSIT_OPEN); 235 mDisplayContent.mOpeningApps.add(activity); 236 assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN, 237 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 238 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 239 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 240 null /* oldWallpaper */, false /* skipAppTransitionAnimation */)); 241 } 242 243 @Test testTaskFragmentClosingTransition()244 public void testTaskFragmentClosingTransition() { 245 final ActivityRecord activity = createHierarchyForTaskFragmentTest(); 246 activity.setVisible(true); 247 248 mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); 249 mDisplayContent.mClosingApps.add(activity); 250 assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, 251 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 252 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 253 mDisplayContent.mChangingContainers, null /* wallpaperTarget */, 254 null /* oldWallpaper */, false /* skipAppTransitionAnimation */)); 255 } 256 257 /** 258 * Creates a {@link Task} with two {@link TaskFragment TaskFragments}. 259 * The bottom TaskFragment is to prevent 260 * {@link AppTransitionController#getAnimationTargets(ArraySet, ArraySet, boolean) the animation 261 * target} to promote to Task or above. 262 * 263 * @return The Activity to be put in either opening or closing Activity 264 */ createHierarchyForTaskFragmentTest()265 private ActivityRecord createHierarchyForTaskFragmentTest() { 266 final Task parentTask = createTask(mDisplayContent); 267 final TaskFragment bottomTaskFragment = createTaskFragmentWithActivity(parentTask); 268 final ActivityRecord bottomActivity = bottomTaskFragment.getTopMostActivity(); 269 bottomActivity.setOccludesParent(true); 270 bottomActivity.setVisible(true); 271 272 final TaskFragment verifiedTaskFragment = createTaskFragmentWithActivity(parentTask); 273 final ActivityRecord activity = verifiedTaskFragment.getTopMostActivity(); 274 activity.setOccludesParent(true); 275 276 return activity; 277 } 278 279 @Test testAppTransitionStateForMultiDisplay()280 public void testAppTransitionStateForMultiDisplay() { 281 // Create 2 displays & presume both display the state is ON for ready to display & animate. 282 final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); 283 final DisplayContent dc2 = createNewDisplay(Display.STATE_ON); 284 285 // Create 2 app window tokens to represent 2 activity window. 286 final ActivityRecord activity1 = createActivityRecord(dc1); 287 final ActivityRecord activity2 = createActivityRecord(dc2); 288 289 activity1.allDrawn = true; 290 activity1.startingMoved = true; 291 292 // Simulate activity resume / finish flows to prepare app transition & set visibility, 293 // make sure transition is set as expected for each display. 294 dc1.prepareAppTransition(TRANSIT_OPEN); 295 dc2.prepareAppTransition(TRANSIT_CLOSE); 296 // One activity window is visible for resuming & the other activity window is invisible 297 // for finishing in different display. 298 activity1.setVisibility(true); 299 activity2.setVisibility(false); 300 301 // Make sure each display is in animating stage. 302 assertTrue(dc1.mOpeningApps.size() > 0); 303 assertTrue(dc2.mClosingApps.size() > 0); 304 assertTrue(dc1.isAppTransitioning()); 305 assertTrue(dc2.isAppTransitioning()); 306 } 307 308 @Test testCleanAppTransitionWhenRootTaskReparent()309 public void testCleanAppTransitionWhenRootTaskReparent() { 310 // Create 2 displays & presume both display the state is ON for ready to display & animate. 311 final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); 312 final DisplayContent dc2 = createNewDisplay(Display.STATE_ON); 313 314 final Task rootTask1 = createTask(dc1); 315 final Task task1 = createTaskInRootTask(rootTask1, 0 /* userId */); 316 final ActivityRecord activity1 = createNonAttachedActivityRecord(dc1); 317 task1.addChild(activity1, 0); 318 319 // Simulate same app is during opening / closing transition set stage. 320 dc1.mClosingApps.add(activity1); 321 assertTrue(dc1.mClosingApps.size() > 0); 322 323 dc1.prepareAppTransition(TRANSIT_OPEN); 324 assertTrue(dc1.mAppTransition.containsTransitRequest(TRANSIT_OPEN)); 325 assertTrue(dc1.mAppTransition.isTransitionSet()); 326 327 dc1.mOpeningApps.add(activity1); 328 assertTrue(dc1.mOpeningApps.size() > 0); 329 330 // Move root task to another display. 331 rootTask1.reparent(dc2.getDefaultTaskDisplayArea(), true); 332 333 // Verify if token are cleared from both pending transition list in former display. 334 assertFalse(dc1.mOpeningApps.contains(activity1)); 335 assertFalse(dc1.mOpeningApps.contains(activity1)); 336 } 337 338 @Test testLoadAnimationSafely()339 public void testLoadAnimationSafely() { 340 DisplayContent dc = createNewDisplay(Display.STATE_ON); 341 assertNull(dc.mAppTransition.loadAnimationSafely( 342 getInstrumentation().getTargetContext(), -1)); 343 } 344 345 @Test testCancelRemoteAnimationWhenFreeze()346 public void testCancelRemoteAnimationWhenFreeze() { 347 final DisplayContent dc = createNewDisplay(Display.STATE_ON); 348 doReturn(false).when(dc).onDescendantOrientationChanged(any()); 349 final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION, 350 dc, "exiting app"); 351 final ActivityRecord exitingActivity = exitingAppWindow.mActivityRecord; 352 // Wait until everything in animation handler get executed to prevent the exiting window 353 // from being removed during WindowSurfacePlacer Traversal. 354 waitUntilHandlersIdle(); 355 356 // Set a remote animator. 357 final TestRemoteAnimationRunner runner = new TestRemoteAnimationRunner(); 358 final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( 359 runner, 100, 50, true /* changeNeedsSnapshot */); 360 // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid. 361 adapter.setCallingPidUid(123, 456); 362 363 // Simulate activity finish flows to prepare app transition & set visibility, 364 // make sure transition is set as expected. 365 dc.prepareAppTransition(TRANSIT_CLOSE); 366 assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_CLOSE)); 367 dc.mAppTransition.overridePendingAppTransitionRemote(adapter); 368 exitingActivity.setVisibility(false); 369 assertTrue(dc.mClosingApps.size() > 0); 370 371 // Make sure window is in animating stage before freeze, and cancel after freeze. 372 assertTrue(dc.isAppTransitioning()); 373 assertFalse(runner.mCancelled); 374 dc.mAppTransition.freeze(); 375 assertFalse(dc.isAppTransitioning()); 376 assertTrue(runner.mCancelled); 377 } 378 379 @Test testDelayWhileRecents()380 public void testDelayWhileRecents() { 381 final DisplayContent dc = createNewDisplay(Display.STATE_ON); 382 doReturn(false).when(dc).onDescendantOrientationChanged(any()); 383 final Task task = createTask(dc); 384 385 // Simulate activity1 launches activity2. 386 final ActivityRecord activity1 = createActivityRecord(task); 387 activity1.setVisible(true); 388 activity1.setVisibleRequested(false); 389 activity1.allDrawn = true; 390 final ActivityRecord activity2 = createActivityRecord(task); 391 activity2.setVisible(false); 392 activity2.setVisibleRequested(true); 393 activity2.allDrawn = true; 394 395 dc.mClosingApps.add(activity1); 396 dc.mOpeningApps.add(activity2); 397 dc.prepareAppTransition(TRANSIT_OPEN); 398 assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN)); 399 400 // Wait until everything in animation handler get executed to prevent the exiting window 401 // from being removed during WindowSurfacePlacer Traversal. 402 waitUntilHandlersIdle(); 403 404 // Start recents 405 doReturn(true).when(task) 406 .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS)); 407 408 dc.mAppTransitionController.handleAppTransitionReady(); 409 410 verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean()); 411 verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean()); 412 } 413 414 @Test testGetAnimationStyleResId()415 public void testGetAnimationStyleResId() { 416 // Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without 417 // specifying window type. 418 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(); 419 attrs.windowAnimations = 0x12345678; 420 assertEquals(attrs.windowAnimations, mDc.mAppTransition.getAnimationStyleResId(attrs)); 421 422 // Verify getAnimationStyleResId will return system resource Id when the window type is 423 // starting window. 424 attrs.type = TYPE_APPLICATION_STARTING; 425 assertEquals(mDc.mAppTransition.getDefaultWindowAnimationStyleResId(), 426 mDc.mAppTransition.getAnimationStyleResId(attrs)); 427 } 428 429 @Test testActivityRecordReparentedToTaskFragment()430 public void testActivityRecordReparentedToTaskFragment() { 431 final ActivityRecord activity = createActivityRecord(mDc); 432 final SurfaceControl activityLeash = mock(SurfaceControl.class); 433 doNothing().when(activity).setDropInputMode(anyInt()); 434 activity.setVisibility(true); 435 activity.setSurfaceControl(activityLeash); 436 final Task task = activity.getTask(); 437 438 // Add a TaskFragment of half of the Task size. 439 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 440 final ITaskFragmentOrganizer iOrganizer = 441 ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); 442 mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); 443 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 444 .setParentTask(task) 445 .setOrganizer(organizer) 446 .build(); 447 final Rect taskBounds = new Rect(); 448 task.getBounds(taskBounds); 449 taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom); 450 spyOn(taskFragment); 451 mockSurfaceFreezerSnapshot(taskFragment.mSurfaceFreezer); 452 453 assertTrue(mDc.mChangingContainers.isEmpty()); 454 assertFalse(mDc.mAppTransition.isTransitionSet()); 455 456 // Schedule app transition when reparent activity to a TaskFragment of different size. 457 final Rect startBounds = new Rect(activity.getBounds()); 458 activity.reparent(taskFragment, POSITION_TOP); 459 460 // It should transit at TaskFragment level with snapshot on the activity surface. 461 verify(taskFragment).initializeChangeTransition(activity.getBounds(), activityLeash); 462 assertTrue(mDc.mChangingContainers.contains(taskFragment)); 463 assertTrue(mDc.mAppTransition.containsTransitRequest(TRANSIT_CHANGE)); 464 assertEquals(startBounds, taskFragment.mSurfaceFreezer.mFreezeBounds); 465 } 466 467 @Test testGetNextAppTransitionBackgroundColor()468 public void testGetNextAppTransitionBackgroundColor() { 469 assumeFalse(WindowManagerService.sEnableShellTransitions); 470 471 // No override by default. 472 assertEquals(0, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); 473 474 // Override with a custom color. 475 mDc.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); 476 final int testColor = 123; 477 mDc.mAppTransition.overridePendingAppTransition("testPackage", 0 /* enterAnim */, 478 0 /* exitAnim */, testColor, null /* startedCallback */, null /* endedCallback */, 479 false /* overrideTaskTransaction */); 480 481 assertEquals(testColor, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); 482 assertTrue(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); 483 484 // Override with ActivityEmbedding remote animation. Background color should be kept. 485 mDc.mAppTransition.overridePendingAppTransitionRemote(mock(RemoteAnimationAdapter.class), 486 false /* sync */, true /* isActivityEmbedding */); 487 488 assertEquals(testColor, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); 489 assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); 490 491 // Background color should not be cleared anymore after #clear(). 492 mDc.mAppTransition.clear(); 493 assertEquals(0, mDc.mAppTransition.getNextAppTransitionBackgroundColor()); 494 assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); 495 } 496 497 @Test testGetNextAppRequestedAnimation()498 public void testGetNextAppRequestedAnimation() { 499 assumeFalse(WindowManagerService.sEnableShellTransitions); 500 final String packageName = "testPackage"; 501 final int enterAnimResId = 1; 502 final int exitAnimResId = 2; 503 final int testColor = 123; 504 final Animation enterAnim = mock(Animation.class); 505 final Animation exitAnim = mock(Animation.class); 506 final TransitionAnimation transitionAnimation = mDc.mAppTransition.mTransitionAnimation; 507 spyOn(transitionAnimation); 508 doReturn(enterAnim).when(transitionAnimation) 509 .loadAppTransitionAnimation(packageName, enterAnimResId); 510 doReturn(exitAnim).when(transitionAnimation) 511 .loadAppTransitionAnimation(packageName, exitAnimResId); 512 513 // No override by default. 514 assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); 515 assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); 516 517 // Override with a custom animation. 518 mDc.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); 519 mDc.mAppTransition.overridePendingAppTransition(packageName, enterAnimResId, exitAnimResId, 520 testColor, null /* startedCallback */, null /* endedCallback */, 521 false /* overrideTaskTransaction */); 522 523 assertEquals(enterAnim, mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); 524 assertEquals(exitAnim, mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); 525 assertTrue(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); 526 527 // Override with ActivityEmbedding remote animation. Custom animation should be kept. 528 mDc.mAppTransition.overridePendingAppTransitionRemote(mock(RemoteAnimationAdapter.class), 529 false /* sync */, true /* isActivityEmbedding */); 530 531 assertEquals(enterAnim, mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); 532 assertEquals(exitAnim, mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); 533 assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested()); 534 535 // Custom animation should not be cleared anymore after #clear(). 536 mDc.mAppTransition.clear(); 537 assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */)); 538 assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */)); 539 } 540 541 private class TestRemoteAnimationRunner implements IRemoteAnimationRunner { 542 boolean mCancelled = false; 543 @Override onAnimationStart(@indowManager.TransitionOldType int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback)544 public void onAnimationStart(@WindowManager.TransitionOldType int transit, 545 RemoteAnimationTarget[] apps, 546 RemoteAnimationTarget[] wallpapers, 547 RemoteAnimationTarget[] nonApps, 548 IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { 549 } 550 551 @Override onAnimationCancelled()552 public void onAnimationCancelled() { 553 mCancelled = true; 554 } 555 556 @Override asBinder()557 public IBinder asBinder() { 558 return null; 559 } 560 } 561 } 562