1 /* 2 * Copyright (C) 2018 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.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 24 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 25 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 26 import static android.view.WindowManager.TRANSIT_CHANGE; 27 import static android.view.WindowManager.TRANSIT_CLOSE; 28 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; 29 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; 30 import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE; 31 import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN; 32 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; 33 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; 34 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; 35 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; 36 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; 37 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; 38 import static android.view.WindowManager.TRANSIT_OPEN; 39 import static android.view.WindowManager.TRANSIT_TO_FRONT; 40 41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 44 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; 45 46 import static org.junit.Assert.assertEquals; 47 import static org.junit.Assert.assertFalse; 48 import static org.junit.Assert.assertNull; 49 import static org.junit.Assert.assertTrue; 50 import static org.junit.Assert.fail; 51 import static org.junit.Assume.assumeFalse; 52 import static org.mockito.ArgumentMatchers.any; 53 import static org.mockito.ArgumentMatchers.anyInt; 54 import static org.mockito.Mockito.clearInvocations; 55 import static org.mockito.Mockito.mock; 56 import static org.mockito.Mockito.never; 57 import static org.mockito.Mockito.verify; 58 59 import android.annotation.Nullable; 60 import android.graphics.Rect; 61 import android.gui.DropInputMode; 62 import android.os.Binder; 63 import android.os.IBinder; 64 import android.os.RemoteException; 65 import android.platform.test.annotations.Presubmit; 66 import android.util.ArraySet; 67 import android.view.IRemoteAnimationFinishedCallback; 68 import android.view.IRemoteAnimationRunner; 69 import android.view.RemoteAnimationAdapter; 70 import android.view.RemoteAnimationDefinition; 71 import android.view.RemoteAnimationTarget; 72 import android.view.WindowManager; 73 import android.window.ITaskFragmentOrganizer; 74 import android.window.TaskFragmentOrganizer; 75 76 import androidx.test.filters.SmallTest; 77 78 import org.junit.Before; 79 import org.junit.Test; 80 import org.junit.runner.RunWith; 81 82 /** 83 * Build/Install/Run: 84 * atest WmTests:AppTransitionControllerTest 85 */ 86 @SmallTest 87 @Presubmit 88 @RunWith(WindowTestRunner.class) 89 public class AppTransitionControllerTest extends WindowTestsBase { 90 91 private AppTransitionController mAppTransitionController; 92 93 @Before setUp()94 public void setUp() throws Exception { 95 assumeFalse(WindowManagerService.sEnableShellTransitions); 96 mAppTransitionController = new AppTransitionController(mWm, mDisplayContent); 97 } 98 99 @Test testSkipOccludedActivityCloseTransition()100 public void testSkipOccludedActivityCloseTransition() { 101 final ActivityRecord behind = createActivityRecord(mDisplayContent, 102 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 103 final ActivityRecord topOpening = createActivityRecord(behind.getTask()); 104 topOpening.setOccludesParent(true); 105 topOpening.setVisible(true); 106 107 mDisplayContent.prepareAppTransition(TRANSIT_OPEN); 108 mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); 109 mDisplayContent.mClosingApps.add(behind); 110 111 assertEquals(WindowManager.TRANSIT_OLD_UNSET, 112 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 113 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 114 mDisplayContent.mChangingContainers, null, null, false)); 115 } 116 117 @Test testClearTaskSkipAppExecuteTransition()118 public void testClearTaskSkipAppExecuteTransition() { 119 final ActivityRecord behind = createActivityRecord(mDisplayContent, 120 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 121 final Task task = behind.getTask(); 122 final ActivityRecord top = createActivityRecord(task); 123 top.setState(ActivityRecord.State.RESUMED, "test"); 124 behind.setState(ActivityRecord.State.STARTED, "test"); 125 behind.setVisibleRequested(true); 126 127 task.removeActivities("test", false /* excludingTaskOverlay */); 128 assertFalse(mDisplayContent.mAppTransition.isReady()); 129 } 130 131 @Test testTranslucentOpen()132 public void testTranslucentOpen() { 133 final ActivityRecord behind = createActivityRecord(mDisplayContent, 134 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 135 final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent, 136 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 137 doReturn(false).when(translucentOpening).fillsParent(); 138 translucentOpening.setVisible(false); 139 mDisplayContent.prepareAppTransition(TRANSIT_OPEN); 140 mDisplayContent.mOpeningApps.add(behind); 141 mDisplayContent.mOpeningApps.add(translucentOpening); 142 143 assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN, 144 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 145 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 146 mDisplayContent.mChangingContainers, null, null, false)); 147 } 148 149 @Test testTranslucentClose()150 public void testTranslucentClose() { 151 final ActivityRecord behind = createActivityRecord(mDisplayContent, 152 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 153 final ActivityRecord translucentClosing = createActivityRecord(mDisplayContent, 154 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 155 doReturn(false).when(translucentClosing).fillsParent(); 156 mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); 157 mDisplayContent.mClosingApps.add(translucentClosing); 158 assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE, 159 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 160 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 161 mDisplayContent.mChangingContainers, null, null, false)); 162 } 163 164 @Test testDreamActivityOpenTransition()165 public void testDreamActivityOpenTransition() { 166 final ActivityRecord dreamActivity = createActivityRecord(mDisplayContent, 167 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM); 168 mDisplayContent.prepareAppTransition(TRANSIT_OPEN); 169 mDisplayContent.mOpeningApps.add(dreamActivity); 170 171 assertEquals(TRANSIT_OLD_DREAM_ACTIVITY_OPEN, 172 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 173 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 174 mDisplayContent.mChangingContainers, null, null, false)); 175 } 176 177 @Test testDreamActivityCloseTransition()178 public void testDreamActivityCloseTransition() { 179 final ActivityRecord dreamActivity = createActivityRecord(mDisplayContent, 180 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM); 181 mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); 182 mDisplayContent.mClosingApps.add(dreamActivity); 183 184 assertEquals(TRANSIT_OLD_DREAM_ACTIVITY_CLOSE, 185 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 186 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 187 mDisplayContent.mChangingContainers, null, null, false)); 188 } 189 190 @Test testChangeIsNotOverwritten()191 public void testChangeIsNotOverwritten() { 192 final ActivityRecord behind = createActivityRecord(mDisplayContent, 193 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 194 final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent, 195 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 196 translucentOpening.setOccludesParent(false); 197 translucentOpening.setVisible(false); 198 mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); 199 mDisplayContent.mOpeningApps.add(behind); 200 mDisplayContent.mOpeningApps.add(translucentOpening); 201 mDisplayContent.mChangingContainers.add(translucentOpening.getTask()); 202 assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, 203 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 204 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 205 mDisplayContent.mChangingContainers, null, null, false)); 206 } 207 208 @Test testTransitWithinTask()209 public void testTransitWithinTask() { 210 final ActivityRecord opening = createActivityRecord(mDisplayContent, 211 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); 212 opening.setOccludesParent(false); 213 final ActivityRecord closing = createActivityRecord(mDisplayContent, 214 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); 215 closing.setOccludesParent(false); 216 final Task task = opening.getTask(); 217 mDisplayContent.mOpeningApps.add(opening); 218 mDisplayContent.mClosingApps.add(closing); 219 assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_ACTIVITY_OPEN, task)); 220 closing.getTask().removeChild(closing); 221 task.addChild(closing, 0); 222 assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_ACTIVITY_OPEN, task)); 223 assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_TASK_OPEN, task)); 224 } 225 226 227 @Test testIntraWallpaper_open()228 public void testIntraWallpaper_open() { 229 final ActivityRecord opening = createActivityRecord(mDisplayContent, 230 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 231 opening.setVisible(false); 232 final WindowManager.LayoutParams attrOpening = new WindowManager.LayoutParams( 233 TYPE_BASE_APPLICATION); 234 attrOpening.setTitle("WallpaperOpening"); 235 attrOpening.flags |= FLAG_SHOW_WALLPAPER; 236 final TestWindowState appWindowOpening = createWindowState(attrOpening, opening); 237 opening.addWindow(appWindowOpening); 238 239 final ActivityRecord closing = createActivityRecord(mDisplayContent, 240 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 241 final WindowManager.LayoutParams attrClosing = new WindowManager.LayoutParams( 242 TYPE_BASE_APPLICATION); 243 attrOpening.setTitle("WallpaperClosing"); 244 attrClosing.flags |= FLAG_SHOW_WALLPAPER; 245 final TestWindowState appWindowClosing = createWindowState(attrClosing, closing); 246 closing.addWindow(appWindowClosing); 247 248 mDisplayContent.prepareAppTransition(TRANSIT_OPEN); 249 mDisplayContent.mOpeningApps.add(opening); 250 mDisplayContent.mClosingApps.add(closing); 251 252 assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN, 253 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 254 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 255 mDisplayContent.mChangingContainers, appWindowClosing, null, false)); 256 } 257 258 @Test testIntraWallpaper_toFront()259 public void testIntraWallpaper_toFront() { 260 final ActivityRecord opening = createActivityRecord(mDisplayContent, 261 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 262 opening.setVisible(false); 263 final WindowManager.LayoutParams attrOpening = new WindowManager.LayoutParams( 264 TYPE_BASE_APPLICATION); 265 attrOpening.setTitle("WallpaperOpening"); 266 attrOpening.flags |= FLAG_SHOW_WALLPAPER; 267 final TestWindowState appWindowOpening = createWindowState(attrOpening, opening); 268 opening.addWindow(appWindowOpening); 269 270 final ActivityRecord closing = createActivityRecord(mDisplayContent, 271 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 272 final WindowManager.LayoutParams attrClosing = new WindowManager.LayoutParams( 273 TYPE_BASE_APPLICATION); 274 attrOpening.setTitle("WallpaperClosing"); 275 attrClosing.flags |= FLAG_SHOW_WALLPAPER; 276 final TestWindowState appWindowClosing = createWindowState(attrClosing, closing); 277 closing.addWindow(appWindowClosing); 278 279 mDisplayContent.prepareAppTransition(TRANSIT_TO_FRONT); 280 mDisplayContent.mOpeningApps.add(opening); 281 mDisplayContent.mClosingApps.add(closing); 282 283 assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN, 284 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, 285 mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, 286 mDisplayContent.mChangingContainers, appWindowClosing, null, false)); 287 } 288 289 @Test testGetAnimationTargets_visibilityAlreadyUpdated()290 public void testGetAnimationTargets_visibilityAlreadyUpdated() { 291 // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, visible) 292 // +- [Task2] - [ActivityRecord2] (closing, invisible) 293 final ActivityRecord activity1 = createActivityRecord(mDisplayContent); 294 295 final ActivityRecord activity2 = createActivityRecord(mDisplayContent); 296 activity2.setVisible(false); 297 activity2.setVisibleRequested(false); 298 299 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 300 opening.add(activity1); 301 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 302 closing.add(activity2); 303 304 // No animation, since visibility of the opening and closing apps are already updated 305 // outside of AppTransition framework. 306 assertEquals( 307 new ArraySet<>(), 308 AppTransitionController.getAnimationTargets( 309 opening, closing, true /* visible */)); 310 assertEquals( 311 new ArraySet<>(), 312 AppTransitionController.getAnimationTargets( 313 opening, closing, false /* visible */)); 314 } 315 316 @Test testGetAnimationTargets_visibilityAlreadyUpdated_butForcedTransitionRequested()317 public void testGetAnimationTargets_visibilityAlreadyUpdated_butForcedTransitionRequested() { 318 // [DisplayContent] -+- [Task1] - [ActivityRecord1] (closing, invisible) 319 // +- [Task2] - [ActivityRecord2] (opening, visible) 320 final ActivityRecord activity1 = createActivityRecord(mDisplayContent); 321 activity1.setVisible(true); 322 activity1.setVisibleRequested(true); 323 activity1.mRequestForceTransition = true; 324 325 final ActivityRecord activity2 = createActivityRecord(mDisplayContent); 326 activity2.setVisible(false); 327 activity2.setVisibleRequested(false); 328 activity2.mRequestForceTransition = true; 329 330 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 331 opening.add(activity1); 332 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 333 closing.add(activity2); 334 335 // The visibility are already updated, but since forced transition is requested, it will 336 // be included. 337 assertEquals( 338 new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}), 339 AppTransitionController.getAnimationTargets( 340 opening, closing, true /* visible */)); 341 assertEquals( 342 new ArraySet<>(new WindowContainer[]{activity2.getRootTask()}), 343 AppTransitionController.getAnimationTargets( 344 opening, closing, false /* visible */)); 345 } 346 347 @Test testGetAnimationTargets_exitingBeforeTransition()348 public void testGetAnimationTargets_exitingBeforeTransition() { 349 // Create another non-empty task so the animation target won't promote to task display area. 350 createActivityRecord(mDisplayContent); 351 final ActivityRecord activity = createActivityRecord(mDisplayContent); 352 activity.setVisible(false); 353 activity.mIsExiting = true; 354 355 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 356 closing.add(activity); 357 358 // Animate closing apps even if it's not visible when it is exiting before we had a chance 359 // to play the transition animation. 360 assertEquals( 361 new ArraySet<>(new WindowContainer[]{activity.getRootTask()}), 362 AppTransitionController.getAnimationTargets( 363 new ArraySet<>(), closing, false /* visible */)); 364 } 365 366 @Test testExitAnimationDone_beforeAppTransition()367 public void testExitAnimationDone_beforeAppTransition() { 368 final Task task = createTask(mDisplayContent); 369 final WindowState win = createAppWindow(task, ACTIVITY_TYPE_STANDARD, "Win"); 370 spyOn(win); 371 win.mAnimatingExit = true; 372 mDisplayContent.mAppTransition.setTimeout(); 373 mDisplayContent.mAppTransitionController.handleAppTransitionReady(); 374 375 verify(win).onExitAnimationDone(); 376 } 377 378 @Test testGetAnimationTargets_openingClosingInDifferentTask()379 public void testGetAnimationTargets_openingClosingInDifferentTask() { 380 // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible) 381 // | +- [ActivityRecord2] (invisible) 382 // | 383 // +- [Task2] -+- [ActivityRecord3] (closing, visible) 384 // +- [ActivityRecord4] (invisible) 385 final ActivityRecord activity1 = createActivityRecord(mDisplayContent); 386 activity1.setVisible(false); 387 activity1.setVisibleRequested(true); 388 final ActivityRecord activity2 = createActivityRecord(mDisplayContent, 389 activity1.getTask()); 390 activity2.setVisible(false); 391 activity2.setVisibleRequested(false); 392 393 final ActivityRecord activity3 = createActivityRecord(mDisplayContent); 394 final ActivityRecord activity4 = createActivityRecord(mDisplayContent, 395 activity3.getTask()); 396 activity4.setVisible(false); 397 activity4.setVisibleRequested(false); 398 399 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 400 opening.add(activity1); 401 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 402 closing.add(activity3); 403 404 // Promote animation targets to root Task level. Invisible ActivityRecords don't affect 405 // promotion decision. 406 assertEquals( 407 new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}), 408 AppTransitionController.getAnimationTargets( 409 opening, closing, true /* visible */)); 410 assertEquals( 411 new ArraySet<>(new WindowContainer[]{activity3.getRootTask()}), 412 AppTransitionController.getAnimationTargets( 413 opening, closing, false /* visible */)); 414 } 415 416 @Test testGetAnimationTargets_openingClosingInSameTask()417 public void testGetAnimationTargets_openingClosingInSameTask() { 418 // [DisplayContent] - [Task] -+- [ActivityRecord1] (opening, invisible) 419 // +- [ActivityRecord2] (closing, visible) 420 final ActivityRecord activity1 = createActivityRecord(mDisplayContent); 421 activity1.setVisible(false); 422 activity1.setVisibleRequested(true); 423 final ActivityRecord activity2 = createActivityRecord(mDisplayContent, 424 activity1.getTask()); 425 426 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 427 opening.add(activity1); 428 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 429 closing.add(activity2); 430 431 // Don't promote an animation target to Task level, since the same task contains both 432 // opening and closing app. 433 assertEquals( 434 new ArraySet<>(new WindowContainer[]{activity1}), 435 AppTransitionController.getAnimationTargets( 436 opening, closing, true /* visible */)); 437 assertEquals( 438 new ArraySet<>(new WindowContainer[]{activity2}), 439 AppTransitionController.getAnimationTargets( 440 opening, closing, false /* visible */)); 441 } 442 443 @Test testGetAnimationTargets_animateOnlyTranslucentApp()444 public void testGetAnimationTargets_animateOnlyTranslucentApp() { 445 // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible) 446 // | +- [ActivityRecord2] (visible) 447 // | 448 // +- [Task2] -+- [ActivityRecord3] (closing, visible) 449 // +- [ActivityRecord4] (visible) 450 451 final ActivityRecord activity1 = createActivityRecord(mDisplayContent); 452 activity1.setVisible(false); 453 activity1.setVisibleRequested(true); 454 activity1.setOccludesParent(false); 455 456 final ActivityRecord activity2 = createActivityRecord(mDisplayContent, 457 activity1.getTask()); 458 459 final ActivityRecord activity3 = createActivityRecord(mDisplayContent); 460 activity3.setOccludesParent(false); 461 final ActivityRecord activity4 = createActivityRecord(mDisplayContent, 462 activity3.getTask()); 463 464 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 465 opening.add(activity1); 466 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 467 closing.add(activity3); 468 469 // Don't promote an animation target to Task level, since opening (closing) app is 470 // translucent and is displayed over other non-animating app. 471 assertEquals( 472 new ArraySet<>(new WindowContainer[]{activity1}), 473 AppTransitionController.getAnimationTargets( 474 opening, closing, true /* visible */)); 475 assertEquals( 476 new ArraySet<>(new WindowContainer[]{activity3}), 477 AppTransitionController.getAnimationTargets( 478 opening, closing, false /* visible */)); 479 } 480 481 @Test testGetAnimationTargets_animateTranslucentAndOpaqueApps()482 public void testGetAnimationTargets_animateTranslucentAndOpaqueApps() { 483 // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible) 484 // | +- [ActivityRecord2] (opening, invisible) 485 // | 486 // +- [Task2] -+- [ActivityRecord3] (closing, visible) 487 // +- [ActivityRecord4] (closing, visible) 488 489 final ActivityRecord activity1 = createActivityRecord(mDisplayContent); 490 activity1.setVisible(false); 491 activity1.setVisibleRequested(true); 492 activity1.setOccludesParent(false); 493 494 final ActivityRecord activity2 = createActivityRecord(mDisplayContent, 495 activity1.getTask()); 496 activity2.setVisible(false); 497 activity2.setVisibleRequested(true); 498 499 final ActivityRecord activity3 = createActivityRecord(mDisplayContent); 500 activity3.setOccludesParent(false); 501 final ActivityRecord activity4 = createActivityRecord(mDisplayContent, 502 activity3.getTask()); 503 504 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 505 opening.add(activity1); 506 opening.add(activity2); 507 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 508 closing.add(activity3); 509 closing.add(activity4); 510 511 // Promote animation targets to TaskStack level even though opening (closing) app is 512 // translucent as long as all visible siblings animate at the same time. 513 assertEquals( 514 new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}), 515 AppTransitionController.getAnimationTargets( 516 opening, closing, true /* visible */)); 517 assertEquals( 518 new ArraySet<>(new WindowContainer[]{activity3.getRootTask()}), 519 AppTransitionController.getAnimationTargets( 520 opening, closing, false /* visible */)); 521 } 522 523 @Test testGetAnimationTargets_taskContainsMultipleTasks()524 public void testGetAnimationTargets_taskContainsMultipleTasks() { 525 // [DisplayContent] - [Task] -+- [Task1] - [ActivityRecord1] (opening, invisible) 526 // +- [Task2] - [ActivityRecord2] (closing, visible) 527 final Task parentTask = createTask(mDisplayContent); 528 final ActivityRecord activity1 = createActivityRecordWithParentTask(parentTask); 529 activity1.setVisible(false); 530 activity1.setVisibleRequested(true); 531 final ActivityRecord activity2 = createActivityRecordWithParentTask(parentTask); 532 533 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 534 opening.add(activity1); 535 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 536 closing.add(activity2); 537 538 // Promote animation targets up to Task level, not beyond. 539 assertEquals( 540 new ArraySet<>(new WindowContainer[]{activity1.getTask()}), 541 AppTransitionController.getAnimationTargets( 542 opening, closing, true /* visible */)); 543 assertEquals( 544 new ArraySet<>(new WindowContainer[]{activity2.getTask()}), 545 AppTransitionController.getAnimationTargets( 546 opening, closing, false /* visible */)); 547 } 548 549 @Test testGetAnimationTargets_splitScreenOpening()550 public void testGetAnimationTargets_splitScreenOpening() { 551 // [DisplayContent] - [Task] -+- [split task 1] -+- [Task1] - [AR1] (opening, invisible) 552 // +- [split task 2] -+- [Task2] - [AR2] (opening, invisible) 553 final Task singleTopRoot = createTask(mDisplayContent); 554 final TaskBuilder builder = new TaskBuilder(mSupervisor) 555 .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW) 556 .setParentTask(singleTopRoot) 557 .setCreatedByOrganizer(true); 558 final Task splitRoot1 = builder.build(); 559 final Task splitRoot2 = builder.build(); 560 splitRoot1.setAdjacentTaskFragment(splitRoot2); 561 final ActivityRecord activity1 = createActivityRecordWithParentTask(splitRoot1); 562 activity1.setVisible(false); 563 activity1.setVisibleRequested(true); 564 final ActivityRecord activity2 = createActivityRecordWithParentTask(splitRoot2); 565 activity2.setVisible(false); 566 activity2.setVisibleRequested(true); 567 568 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 569 opening.add(activity1); 570 opening.add(activity2); 571 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 572 573 // Promote animation targets up to Task level, not beyond. 574 assertEquals( 575 new ArraySet<>(new WindowContainer[]{splitRoot1, splitRoot2}), 576 AppTransitionController.getAnimationTargets( 577 opening, closing, true /* visible */)); 578 } 579 580 @Test testGetAnimationTargets_openingClosingTaskFragment()581 public void testGetAnimationTargets_openingClosingTaskFragment() { 582 // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible) 583 // +- [TaskFragment2] - [ActivityRecord2] (closing, visible) 584 final Task parentTask = createTask(mDisplayContent); 585 final TaskFragment taskFragment1 = createTaskFragmentWithActivity(parentTask); 586 final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); 587 activity1.setVisible(false); 588 activity1.setVisibleRequested(true); 589 590 final TaskFragment taskFragment2 = createTaskFragmentWithActivity(parentTask); 591 final ActivityRecord activity2 = taskFragment2.getTopMostActivity(); 592 activity2.setVisible(true); 593 activity2.setVisibleRequested(false); 594 595 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 596 opening.add(activity1); 597 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 598 closing.add(activity2); 599 600 // Promote animation targets up to TaskFragment level, not beyond. 601 assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}), 602 AppTransitionController.getAnimationTargets( 603 opening, closing, true /* visible */)); 604 assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}), 605 AppTransitionController.getAnimationTargets( 606 opening, closing, false /* visible */)); 607 } 608 609 @Test testGetAnimationTargets_openingTheOnlyTaskFragmentInTask()610 public void testGetAnimationTargets_openingTheOnlyTaskFragmentInTask() { 611 // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (opening, invisible) 612 // +- [Task2] - [ActivityRecord2] (closing, visible) 613 final Task task1 = createTask(mDisplayContent); 614 final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task1); 615 final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); 616 activity1.setVisible(false); 617 activity1.setVisibleRequested(true); 618 619 final ActivityRecord activity2 = createActivityRecord(mDisplayContent); 620 activity2.setVisible(true); 621 activity2.setVisibleRequested(false); 622 623 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 624 opening.add(activity1); 625 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 626 closing.add(activity2); 627 628 // Promote animation targets up to leaf Task level because there's only one TaskFragment in 629 // the Task. 630 assertEquals(new ArraySet<>(new WindowContainer[]{task1}), 631 AppTransitionController.getAnimationTargets( 632 opening, closing, true /* visible */)); 633 assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}), 634 AppTransitionController.getAnimationTargets( 635 opening, closing, false /* visible */)); 636 } 637 638 @Test testGetAnimationTargets_closingTheOnlyTaskFragmentInTask()639 public void testGetAnimationTargets_closingTheOnlyTaskFragmentInTask() { 640 // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (closing, visible) 641 // +- [Task2] - [ActivityRecord2] (opening, invisible) 642 final Task task1 = createTask(mDisplayContent); 643 final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task1); 644 final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); 645 activity1.setVisible(true); 646 activity1.setVisibleRequested(false); 647 648 final ActivityRecord activity2 = createActivityRecord(mDisplayContent); 649 activity2.setVisible(false); 650 activity2.setVisibleRequested(true); 651 652 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 653 opening.add(activity2); 654 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 655 closing.add(activity1); 656 657 // Promote animation targets up to leaf Task level because there's only one TaskFragment in 658 // the Task. 659 assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}), 660 AppTransitionController.getAnimationTargets( 661 opening, closing, true /* visible */)); 662 assertEquals(new ArraySet<>(new WindowContainer[]{task1}), 663 AppTransitionController.getAnimationTargets( 664 opening, closing, false /* visible */)); 665 } 666 667 @Test testGetAnimationTargets_embeddedTask()668 public void testGetAnimationTargets_embeddedTask() { 669 // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, invisible) 670 // +- [Task2] (embedded) - [ActivityRecord2] (opening, invisible) 671 final ActivityRecord activity1 = createActivityRecord(mDisplayContent); 672 activity1.setVisible(false); 673 activity1.setVisibleRequested(true); 674 675 final Task task2 = createTask(mDisplayContent); 676 task2.mRemoveWithTaskOrganizer = true; 677 final ActivityRecord activity2 = createActivityRecord(task2); 678 activity2.setVisible(false); 679 activity2.setVisibleRequested(true); 680 681 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 682 opening.add(activity1); 683 opening.add(activity2); 684 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 685 686 // No animation on the embedded task. 687 assertEquals( 688 new ArraySet<>(new WindowContainer[]{activity1.getTask()}), 689 AppTransitionController.getAnimationTargets( 690 opening, closing, true /* visible */)); 691 assertEquals( 692 new ArraySet<>(), 693 AppTransitionController.getAnimationTargets( 694 opening, closing, false /* visible */)); 695 } 696 697 698 @Test testGetAnimationTargets_activityInEmbeddedTask()699 public void testGetAnimationTargets_activityInEmbeddedTask() { 700 // [DisplayContent] - [Task] (embedded)-+- [ActivityRecord1] (opening, invisible) 701 // +- [ActivityRecord2] (closing, visible) 702 final Task task = createTask(mDisplayContent); 703 task.mRemoveWithTaskOrganizer = true; 704 705 final ActivityRecord activity1 = createActivityRecord(task); 706 activity1.setVisible(false); 707 activity1.setVisibleRequested(true); 708 final ActivityRecord activity2 = createActivityRecord(task); 709 710 final ArraySet<ActivityRecord> opening = new ArraySet<>(); 711 opening.add(activity1); 712 final ArraySet<ActivityRecord> closing = new ArraySet<>(); 713 closing.add(activity2); 714 715 // Even though embedded task itself doesn't animate, activities in an embedded task 716 // animate. 717 assertEquals( 718 new ArraySet<>(new WindowContainer[]{activity1}), 719 AppTransitionController.getAnimationTargets( 720 opening, closing, true /* visible */)); 721 assertEquals( 722 new ArraySet<>(new WindowContainer[]{activity2}), 723 AppTransitionController.getAnimationTargets( 724 opening, closing, false /* visible */)); 725 } 726 727 static class TestRemoteAnimationRunner implements IRemoteAnimationRunner { 728 private IRemoteAnimationFinishedCallback mFinishedCallback; 729 730 @Override onAnimationStart(int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback)731 public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, 732 RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, 733 IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { 734 mFinishedCallback = finishedCallback; 735 } 736 737 @Override onAnimationCancelled()738 public void onAnimationCancelled() throws RemoteException { 739 mFinishedCallback = null; 740 } 741 742 @Override asBinder()743 public IBinder asBinder() { 744 return new Binder(); 745 } 746 isAnimationStarted()747 boolean isAnimationStarted() { 748 return mFinishedCallback != null; 749 } 750 finishAnimation()751 void finishAnimation() { 752 try { 753 mFinishedCallback.onAnimationFinished(); 754 } catch (RemoteException e) { 755 fail(); 756 } 757 } 758 } 759 760 @Test testGetRemoteAnimationOverrideEmpty()761 public void testGetRemoteAnimationOverrideEmpty() { 762 final ActivityRecord activity = createActivityRecord(mDisplayContent); 763 assertNull(mAppTransitionController.getRemoteAnimationOverride(activity, 764 TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); 765 } 766 767 @Test testGetRemoteAnimationOverrideWindowContainer()768 public void testGetRemoteAnimationOverrideWindowContainer() { 769 final ActivityRecord activity = createActivityRecord(mDisplayContent); 770 final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); 771 final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( 772 new TestRemoteAnimationRunner(), 10, 1); 773 definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); 774 activity.registerRemoteAnimations(definition); 775 776 assertEquals(adapter, 777 mAppTransitionController.getRemoteAnimationOverride( 778 activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); 779 assertNull(mAppTransitionController.getRemoteAnimationOverride( 780 null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); 781 } 782 783 @Test testGetRemoteAnimationOverrideTransitionController()784 public void testGetRemoteAnimationOverrideTransitionController() { 785 final ActivityRecord activity = createActivityRecord(mDisplayContent); 786 final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); 787 final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( 788 new TestRemoteAnimationRunner(), 10, 1); 789 definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); 790 mAppTransitionController.registerRemoteAnimations(definition); 791 792 assertEquals(adapter, 793 mAppTransitionController.getRemoteAnimationOverride( 794 activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); 795 assertEquals(adapter, 796 mAppTransitionController.getRemoteAnimationOverride( 797 null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); 798 } 799 800 @Test testGetRemoteAnimationOverrideBoth()801 public void testGetRemoteAnimationOverrideBoth() { 802 final ActivityRecord activity = createActivityRecord(mDisplayContent); 803 final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition(); 804 final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter( 805 new TestRemoteAnimationRunner(), 10, 1); 806 definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1); 807 activity.registerRemoteAnimations(definition1); 808 809 final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition(); 810 final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter( 811 new TestRemoteAnimationRunner(), 10, 1); 812 definition2.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, adapter2); 813 mAppTransitionController.registerRemoteAnimations(definition2); 814 815 assertEquals(adapter2, 816 mAppTransitionController.getRemoteAnimationOverride( 817 activity, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>())); 818 assertEquals(adapter2, 819 mAppTransitionController.getRemoteAnimationOverride( 820 null, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>())); 821 } 822 823 @Test testGetRemoteAnimationOverrideWindowContainerHasPriority()824 public void testGetRemoteAnimationOverrideWindowContainerHasPriority() { 825 final ActivityRecord activity = createActivityRecord(mDisplayContent); 826 final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition(); 827 final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter( 828 new TestRemoteAnimationRunner(), 10, 1); 829 definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1); 830 activity.registerRemoteAnimations(definition1); 831 832 final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition(); 833 final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter( 834 new TestRemoteAnimationRunner(), 10, 1); 835 definition2.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter2); 836 mAppTransitionController.registerRemoteAnimations(definition2); 837 838 assertEquals(adapter1, 839 mAppTransitionController.getRemoteAnimationOverride( 840 activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>())); 841 } 842 843 @Test testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity()844 public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() { 845 final Task task = createTask(mDisplayContent); 846 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 847 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 848 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 849 850 // Create a TaskFragment with embedded activity. 851 final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); 852 final ActivityRecord activity = taskFragment.getTopMostActivity(); 853 prepareActivityForAppTransition(activity); 854 spyOn(mDisplayContent.mAppTransition); 855 856 // Prepare and start transition. 857 prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); 858 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 859 860 // Animation run by the remote handler. 861 assertTrue(remoteAnimationRunner.isAnimationStarted()); 862 } 863 864 @Test testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask()865 public void testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask() { 866 final Task task = createTask(mDisplayContent); 867 final ActivityRecord closingActivity = createActivityRecord(task); 868 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 869 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 870 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 871 872 // Create a TaskFragment with embedded activity. 873 final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); 874 875 // Make sure the TaskFragment is not embedded. 876 assertFalse(taskFragment.isEmbeddedWithBoundsOverride()); 877 final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); 878 prepareActivityForAppTransition(closingActivity); 879 prepareActivityForAppTransition(openingActivity); 880 final int uid = 12345; 881 closingActivity.info.applicationInfo.uid = uid; 882 openingActivity.info.applicationInfo.uid = uid; 883 task.effectiveUid = uid; 884 spyOn(mDisplayContent.mAppTransition); 885 886 // Prepare and start transition. 887 prepareAndTriggerAppTransition(openingActivity, closingActivity, 888 null /* changingTaskFragment */); 889 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 890 891 // Animation is not run by the remote handler because the activity is filling the Task. 892 assertFalse(remoteAnimationRunner.isAnimationStarted()); 893 } 894 895 @Test testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask()896 public void testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask() { 897 final Task task = createTask(mDisplayContent); 898 final ActivityRecord closingActivity = createActivityRecord(task); 899 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 900 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 901 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 902 903 // Create a TaskFragment with embedded activity. 904 final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); 905 906 // Make sure the TaskFragment is embedded. 907 taskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 908 final Rect embeddedBounds = new Rect(task.getBounds()); 909 embeddedBounds.right = embeddedBounds.left + embeddedBounds.width() / 2; 910 taskFragment.setBounds(embeddedBounds); 911 assertTrue(taskFragment.isEmbeddedWithBoundsOverride()); 912 final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); 913 prepareActivityForAppTransition(closingActivity); 914 prepareActivityForAppTransition(openingActivity); 915 final int uid = 12345; 916 closingActivity.info.applicationInfo.uid = uid; 917 openingActivity.info.applicationInfo.uid = uid; 918 task.effectiveUid = uid; 919 spyOn(mDisplayContent.mAppTransition); 920 921 // Prepare and start transition. 922 prepareAndTriggerAppTransition(openingActivity, closingActivity, 923 null /* changingTaskFragment */); 924 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 925 926 // Animation run by the remote handler. 927 assertTrue(remoteAnimationRunner.isAnimationStarted()); 928 } 929 930 @Test testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity()931 public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() { 932 final Task task = createTask(mDisplayContent); 933 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 934 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 935 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 936 937 // Closing non-embedded activity. 938 final ActivityRecord closingActivity = createActivityRecord(task); 939 prepareActivityForAppTransition(closingActivity); 940 // Opening TaskFragment with embedded activity. 941 final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); 942 final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); 943 prepareActivityForAppTransition(openingActivity); 944 task.effectiveUid = openingActivity.getUid(); 945 spyOn(mDisplayContent.mAppTransition); 946 947 // Prepare and start transition. 948 prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); 949 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 950 951 // Animation run by the remote handler. 952 assertTrue(remoteAnimationRunner.isAnimationStarted()); 953 } 954 955 @Test testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid()956 public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() { 957 final Task task = createTask(mDisplayContent); 958 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 959 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 960 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 961 962 // Closing TaskFragment with embedded activity. 963 final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer); 964 final ActivityRecord closingActivity = taskFragment1.getTopMostActivity(); 965 prepareActivityForAppTransition(closingActivity); 966 closingActivity.info.applicationInfo.uid = 12345; 967 // Opening TaskFragment with embedded activity with different UID. 968 final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer); 969 final ActivityRecord openingActivity = taskFragment2.getTopMostActivity(); 970 prepareActivityForAppTransition(openingActivity); 971 openingActivity.info.applicationInfo.uid = 54321; 972 spyOn(mDisplayContent.mAppTransition); 973 974 // Prepare and start transition. 975 prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1); 976 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 977 978 // Animation run by the remote handler. 979 assertTrue(remoteAnimationRunner.isAnimationStarted()); 980 } 981 982 @Test testOverrideTaskFragmentAdapter_noOverrideWithTwoApps()983 public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() { 984 final Task task = createTask(mDisplayContent); 985 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 986 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 987 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 988 989 // Closing activity in Task1. 990 final ActivityRecord closingActivity = createActivityRecord(mDisplayContent); 991 prepareActivityForAppTransition(closingActivity); 992 // Opening TaskFragment with embedded activity in Task2. 993 final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); 994 final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); 995 prepareActivityForAppTransition(openingActivity); 996 spyOn(mDisplayContent.mAppTransition); 997 998 // Prepare and start transition. 999 prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); 1000 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 1001 1002 // Animation not run by the remote handler. 1003 assertFalse(remoteAnimationRunner.isAnimationStarted()); 1004 } 1005 1006 @Test testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid()1007 public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() { 1008 final Task task = createTask(mDisplayContent); 1009 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 1010 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 1011 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 1012 1013 // Closing TaskFragment with embedded activity. 1014 final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); 1015 final ActivityRecord closingActivity = taskFragment.getTopMostActivity(); 1016 prepareActivityForAppTransition(closingActivity); 1017 closingActivity.info.applicationInfo.uid = 12345; 1018 task.effectiveUid = closingActivity.getUid(); 1019 // Opening non-embedded activity with different UID. 1020 final ActivityRecord openingActivity = createActivityRecord(task); 1021 prepareActivityForAppTransition(openingActivity); 1022 openingActivity.info.applicationInfo.uid = 54321; 1023 spyOn(mDisplayContent.mAppTransition); 1024 1025 // Prepare and start transition. 1026 prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); 1027 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 1028 1029 // Animation should not run by the remote handler when there are non-embedded activities of 1030 // different UID. 1031 assertFalse(remoteAnimationRunner.isAnimationStarted()); 1032 } 1033 1034 @Test testOverrideTaskFragmentAdapter_noOverrideWithWallpaper()1035 public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() { 1036 final Task task = createTask(mDisplayContent); 1037 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 1038 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 1039 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 1040 1041 // Create a TaskFragment with embedded activity. 1042 final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); 1043 final ActivityRecord activity = taskFragment.getTopMostActivity(); 1044 prepareActivityForAppTransition(activity); 1045 // Set wallpaper as visible. 1046 final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, 1047 mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */); 1048 spyOn(mDisplayContent.mWallpaperController); 1049 doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible(); 1050 spyOn(mDisplayContent.mAppTransition); 1051 1052 // Prepare and start transition. 1053 prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); 1054 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 1055 1056 // Animation should not run by the remote handler when there is wallpaper in the transition. 1057 assertFalse(remoteAnimationRunner.isAnimationStarted()); 1058 } 1059 1060 @Test testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation()1061 public void testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation() { 1062 final Task task = createTask(mDisplayContent); 1063 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 1064 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 1065 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 1066 1067 // Create a TaskFragment with embedded activities, one is trusted embedded, and the other 1068 // one is untrusted embedded. 1069 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 1070 .setParentTask(task) 1071 .createActivityCount(2) 1072 .setOrganizer(organizer) 1073 .build(); 1074 final ActivityRecord activity0 = taskFragment.getChildAt(0).asActivityRecord(); 1075 final ActivityRecord activity1 = taskFragment.getChildAt(1).asActivityRecord(); 1076 // Also create a non-embedded activity in the Task. 1077 final ActivityRecord activity2 = new ActivityBuilder(mAtm).build(); 1078 task.addChild(activity2, POSITION_BOTTOM); 1079 prepareActivityForAppTransition(activity0); 1080 prepareActivityForAppTransition(activity1); 1081 prepareActivityForAppTransition(activity2); 1082 doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0); 1083 doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1); 1084 spyOn(mDisplayContent.mAppTransition); 1085 1086 // Prepare and start transition. 1087 prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment); 1088 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 1089 1090 // The animation will be animated remotely by client and all activities are input disabled 1091 // for untrusted animation. 1092 assertTrue(remoteAnimationRunner.isAnimationStarted()); 1093 verify(activity0).setDropInputForAnimation(true); 1094 verify(activity1).setDropInputForAnimation(true); 1095 verify(activity2).setDropInputForAnimation(true); 1096 verify(activity0).setDropInputMode(DropInputMode.ALL); 1097 verify(activity1).setDropInputMode(DropInputMode.ALL); 1098 verify(activity2).setDropInputMode(DropInputMode.ALL); 1099 1100 // Reset input after animation is finished. 1101 clearInvocations(activity0); 1102 clearInvocations(activity1); 1103 clearInvocations(activity2); 1104 remoteAnimationRunner.finishAnimation(); 1105 1106 verify(activity0).setDropInputForAnimation(false); 1107 verify(activity1).setDropInputForAnimation(false); 1108 verify(activity2).setDropInputForAnimation(false); 1109 verify(activity0).setDropInputMode(DropInputMode.OBSCURED); 1110 verify(activity1).setDropInputMode(DropInputMode.NONE); 1111 verify(activity2).setDropInputMode(DropInputMode.NONE); 1112 } 1113 1114 /** 1115 * Since we don't have any use case to rely on handling input during animation, disable it even 1116 * if it is trusted embedding so that it could cover some edge-cases when a previously trusted 1117 * host starts doing something bad. 1118 */ 1119 @Test testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation()1120 public void testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation() { 1121 final Task task = createTask(mDisplayContent); 1122 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 1123 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 1124 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 1125 1126 // Create a TaskFragment with only trusted embedded activity 1127 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 1128 .setParentTask(task) 1129 .createActivityCount(1) 1130 .setOrganizer(organizer) 1131 .build(); 1132 final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord(); 1133 prepareActivityForAppTransition(activity); 1134 doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity); 1135 spyOn(mDisplayContent.mAppTransition); 1136 1137 // Prepare and start transition. 1138 prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); 1139 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 1140 1141 // The animation will be animated remotely by client and all activities are input disabled 1142 // for untrusted animation. 1143 assertTrue(remoteAnimationRunner.isAnimationStarted()); 1144 verify(activity).setDropInputForAnimation(true); 1145 verify(activity).setDropInputMode(DropInputMode.ALL); 1146 1147 // Reset input after animation is finished. 1148 clearInvocations(activity); 1149 remoteAnimationRunner.finishAnimation(); 1150 1151 verify(activity).setDropInputForAnimation(false); 1152 verify(activity).setDropInputMode(DropInputMode.NONE); 1153 } 1154 1155 /** 1156 * We don't need to drop input for fully trusted embedding (system app, and embedding in the 1157 * same app). This will allow users to do fast tapping. 1158 */ 1159 @Test testOverrideTaskFragmentAdapter_noInputProtectedForFullyTrustedAnimation()1160 public void testOverrideTaskFragmentAdapter_noInputProtectedForFullyTrustedAnimation() { 1161 final Task task = createTask(mDisplayContent); 1162 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 1163 final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); 1164 setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); 1165 1166 // Create a TaskFragment with only trusted embedded activity 1167 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 1168 .setParentTask(task) 1169 .createActivityCount(1) 1170 .setOrganizer(organizer) 1171 .build(); 1172 final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord(); 1173 prepareActivityForAppTransition(activity); 1174 final int uid = mAtm.mTaskFragmentOrganizerController.getTaskFragmentOrganizerUid( 1175 getITaskFragmentOrganizer(organizer)); 1176 doReturn(true).when(task).isFullyTrustedEmbedding(uid); 1177 spyOn(mDisplayContent.mAppTransition); 1178 1179 // Prepare and start transition. 1180 prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); 1181 mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); 1182 1183 // The animation will be animated remotely by client, but input should not be dropped for 1184 // fully trusted. 1185 assertTrue(remoteAnimationRunner.isAnimationStarted()); 1186 verify(activity, never()).setDropInputForAnimation(true); 1187 verify(activity, never()).setDropInputMode(DropInputMode.ALL); 1188 } 1189 1190 @Test testTransitionGoodToGoForTaskFragments()1191 public void testTransitionGoodToGoForTaskFragments() { 1192 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 1193 final Task task = createTask(mDisplayContent); 1194 final TaskFragment changeTaskFragment = 1195 createTaskFragmentWithEmbeddedActivity(task, organizer); 1196 final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm) 1197 .setParentTask(task) 1198 .setOrganizer(organizer) 1199 .build(); 1200 prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity()); 1201 spyOn(mDisplayContent.mAppTransition); 1202 spyOn(emptyTaskFragment); 1203 1204 prepareAndTriggerAppTransition( 1205 null /* openingActivity */, null /* closingActivity*/, changeTaskFragment); 1206 1207 // Transition not ready because there is an empty non-finishing TaskFragment. 1208 verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any()); 1209 1210 doReturn(true).when(emptyTaskFragment).hasChild(); 1211 emptyTaskFragment.remove(false /* withTransition */, "test"); 1212 1213 mDisplayContent.mAppTransitionController.handleAppTransitionReady(); 1214 1215 // Transition ready because the empty (no running activity) TaskFragment is requested to be 1216 // removed. 1217 verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any()); 1218 } 1219 1220 @Test testTransitionGoodToGoForTaskFragments_detachedApp()1221 public void testTransitionGoodToGoForTaskFragments_detachedApp() { 1222 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 1223 final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer); 1224 mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); 1225 final Task task = createTask(mDisplayContent); 1226 final TaskFragment changeTaskFragment = 1227 createTaskFragmentWithEmbeddedActivity(task, organizer); 1228 final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm) 1229 .setParentTask(task) 1230 .setOrganizer(organizer) 1231 .build(); 1232 prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity()); 1233 // To make sure that having a detached activity won't cause any issue. 1234 final ActivityRecord detachedActivity = createActivityRecord(task); 1235 detachedActivity.removeImmediately(); 1236 assertNull(detachedActivity.getRootTask()); 1237 spyOn(mDisplayContent.mAppTransition); 1238 spyOn(emptyTaskFragment); 1239 1240 prepareAndTriggerAppTransition( 1241 null /* openingActivity */, detachedActivity, changeTaskFragment); 1242 1243 // Transition not ready because there is an empty non-finishing TaskFragment. 1244 verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any()); 1245 1246 doReturn(true).when(emptyTaskFragment).hasChild(); 1247 emptyTaskFragment.remove(false /* withTransition */, "test"); 1248 1249 mDisplayContent.mAppTransitionController.handleAppTransitionReady(); 1250 1251 // Transition ready because the empty (no running activity) TaskFragment is requested to be 1252 // removed. 1253 verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any()); 1254 } 1255 1256 /** Registers remote animation for the organizer. */ setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, TestRemoteAnimationRunner remoteAnimationRunner)1257 private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, 1258 TestRemoteAnimationRunner remoteAnimationRunner) { 1259 final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( 1260 remoteAnimationRunner, 10, 1); 1261 final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer); 1262 final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); 1263 definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); 1264 definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter); 1265 definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter); 1266 definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); 1267 definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter); 1268 mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); 1269 mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); 1270 } 1271 getITaskFragmentOrganizer( TaskFragmentOrganizer organizer)1272 private static ITaskFragmentOrganizer getITaskFragmentOrganizer( 1273 TaskFragmentOrganizer organizer) { 1274 return ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); 1275 } 1276 prepareAndTriggerAppTransition(@ullable ActivityRecord openingActivity, @Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment)1277 private void prepareAndTriggerAppTransition(@Nullable ActivityRecord openingActivity, 1278 @Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment) { 1279 if (openingActivity != null) { 1280 mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); 1281 mDisplayContent.mOpeningApps.add(openingActivity); 1282 } 1283 if (closingActivity != null) { 1284 mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CLOSE, 0); 1285 mDisplayContent.mClosingApps.add(closingActivity); 1286 } 1287 if (changingTaskFragment != null) { 1288 mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); 1289 mDisplayContent.mChangingContainers.add(changingTaskFragment); 1290 } 1291 mDisplayContent.mAppTransitionController.handleAppTransitionReady(); 1292 } 1293 prepareActivityForAppTransition(ActivityRecord activity)1294 private static void prepareActivityForAppTransition(ActivityRecord activity) { 1295 // Transition will wait until all participated activities to be drawn. 1296 activity.allDrawn = true; 1297 // Skip manipulate the SurfaceControl. 1298 doNothing().when(activity).setDropInputMode(anyInt()); 1299 // Assume the activity contains a window. 1300 doReturn(true).when(activity).hasChild(); 1301 // Make sure activity can create remote animation target. 1302 doReturn(mock(RemoteAnimationTarget.class)).when(activity).createRemoteAnimationTarget( 1303 any()); 1304 } 1305 }