1 /* 2 * Copyright (C) 2020 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.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; 20 import static android.app.ActivityManager.START_CANCELED; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 26 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 27 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 28 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 29 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 30 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 31 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 32 import static android.content.pm.PackageManager.PERMISSION_DENIED; 33 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 34 import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; 35 import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; 36 import static android.view.InsetsSource.FLAG_FORCE_CONSUMING; 37 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 38 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; 39 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.mock; 43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; 45 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 46 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; 47 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 48 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; 49 import static com.android.server.wm.ActivityRecord.State.RESUMED; 50 import static com.android.server.wm.WindowContainer.POSITION_TOP; 51 import static com.android.server.wm.WindowContainer.SYNC_STATE_READY; 52 import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; 53 import static com.android.server.wm.testing.Assert.assertThrows; 54 55 import static com.google.common.truth.Truth.assertThat; 56 57 import static org.junit.Assert.assertArrayEquals; 58 import static org.junit.Assert.assertEquals; 59 import static org.junit.Assert.assertFalse; 60 import static org.junit.Assert.assertNotNull; 61 import static org.junit.Assert.assertTrue; 62 import static org.mockito.ArgumentMatchers.any; 63 import static org.mockito.ArgumentMatchers.anyBoolean; 64 import static org.mockito.ArgumentMatchers.anyInt; 65 import static org.mockito.ArgumentMatchers.eq; 66 import static org.mockito.Mockito.atLeastOnce; 67 import static org.mockito.Mockito.clearInvocations; 68 import static org.mockito.quality.Strictness.LENIENT; 69 70 import android.annotation.NonNull; 71 import android.app.ActivityManager; 72 import android.app.ActivityManager.RunningTaskInfo; 73 import android.app.ActivityOptions; 74 import android.app.ActivityTaskManager.RootTaskInfo; 75 import android.app.IRequestFinishCallback; 76 import android.app.PictureInPictureParams; 77 import android.content.Intent; 78 import android.content.pm.ActivityInfo; 79 import android.content.pm.ParceledListSlice; 80 import android.content.res.Configuration; 81 import android.graphics.Rect; 82 import android.os.Binder; 83 import android.os.IBinder; 84 import android.os.RemoteException; 85 import android.platform.test.annotations.EnableFlags; 86 import android.platform.test.annotations.Presubmit; 87 import android.platform.test.annotations.RequiresFlagsDisabled; 88 import android.util.ArrayMap; 89 import android.util.Rational; 90 import android.view.Display; 91 import android.view.InsetsSource; 92 import android.view.SurfaceControl; 93 import android.view.WindowInsets; 94 import android.window.ITaskFragmentOrganizer; 95 import android.window.ITaskOrganizer; 96 import android.window.IWindowContainerTransactionCallback; 97 import android.window.RemoteTransition; 98 import android.window.StartingWindowInfo; 99 import android.window.StartingWindowRemovalInfo; 100 import android.window.TaskAppearedInfo; 101 import android.window.TaskFragmentOrganizer; 102 import android.window.WindowContainerToken; 103 import android.window.WindowContainerTransaction; 104 105 import androidx.test.filters.SmallTest; 106 107 import com.android.server.wm.TaskOrganizerController.PendingTaskEvent; 108 import com.android.window.flags.Flags; 109 110 import org.junit.Test; 111 import org.junit.runner.RunWith; 112 import org.mockito.ArgumentCaptor; 113 import org.mockito.MockitoSession; 114 115 import java.util.ArrayList; 116 import java.util.HashSet; 117 import java.util.List; 118 import java.util.function.BiConsumer; 119 120 /** 121 * Test class for {@link ITaskOrganizer} and {@link android.window.ITaskOrganizerController}. 122 * 123 * Build/Install/Run: 124 * atest WmTests:WindowOrganizerTests 125 */ 126 127 // TODO revert parts of this set to set the flag to test the behavior 128 @SmallTest 129 @Presubmit 130 @RunWith(WindowTestRunner.class) 131 public class WindowOrganizerTests extends WindowTestsBase { 132 createMockOrganizer()133 private ITaskOrganizer createMockOrganizer() { 134 final ITaskOrganizer organizer = mock(ITaskOrganizer.class); 135 when(organizer.asBinder()).thenReturn(new Binder()); 136 return organizer; 137 } 138 registerMockOrganizer(ArrayList<TaskAppearedInfo> existingTasks)139 private ITaskOrganizer registerMockOrganizer(ArrayList<TaskAppearedInfo> existingTasks) { 140 final ITaskOrganizer organizer = createMockOrganizer(); 141 ParceledListSlice<TaskAppearedInfo> tasks = 142 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(organizer); 143 if (existingTasks != null) { 144 existingTasks.addAll(tasks.getList()); 145 } 146 return organizer; 147 } 148 registerMockOrganizer()149 private ITaskOrganizer registerMockOrganizer() { 150 return registerMockOrganizer(null); 151 } 152 createTask(Task rootTask, boolean fakeDraw)153 Task createTask(Task rootTask, boolean fakeDraw) { 154 final Task task = createTaskInRootTask(rootTask, 0); 155 156 if (fakeDraw) { 157 task.setHasBeenVisible(true); 158 } 159 return task; 160 } 161 createTask(Task rootTask)162 Task createTask(Task rootTask) { 163 // Fake draw notifications for most of our tests. 164 return createTask(rootTask, true); 165 } 166 createRootTask()167 Task createRootTask() { 168 return createTask(mDisplayContent); 169 } 170 171 @Test testAppearVanish()172 public void testAppearVanish() throws RemoteException { 173 final ITaskOrganizer organizer = registerMockOrganizer(); 174 final Task rootTask = createRootTask(); 175 final Task task = createTask(rootTask); 176 // Ensure events dispatch to organizer. 177 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 178 179 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 180 181 rootTask.removeImmediately(); 182 // Ensure events dispatch to organizer. 183 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 184 verify(organizer).onTaskVanished(any()); 185 } 186 187 @Test testAppearWaitsForVisibility()188 public void testAppearWaitsForVisibility() throws RemoteException { 189 final ITaskOrganizer organizer = registerMockOrganizer(); 190 final Task rootTask = createRootTask(); 191 final Task task = createTask(rootTask, false); 192 // Ensure events dispatch to organizer. 193 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 194 195 verify(organizer, never()) 196 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 197 rootTask.setHasBeenVisible(true); 198 // Ensure events dispatch to organizer. 199 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 200 assertTrue(rootTask.getHasBeenVisible()); 201 202 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 203 204 rootTask.removeImmediately(); 205 // Ensure events dispatch to organizer. 206 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 207 verify(organizer).onTaskVanished(any()); 208 } 209 210 @Test testNoVanishedIfNoAppear()211 public void testNoVanishedIfNoAppear() throws RemoteException { 212 final ITaskOrganizer organizer = registerMockOrganizer(); 213 final Task rootTask = createRootTask(); 214 final Task task = createTask(rootTask, false /* hasBeenVisible */); 215 216 // In this test we skip making the Task visible, and verify 217 // that even though a TaskOrganizer is set remove doesn't emit 218 // a vanish callback, because we never emitted appear. 219 rootTask.setTaskOrganizer(organizer); 220 verify(organizer, never()) 221 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 222 rootTask.removeImmediately(); 223 verify(organizer, never()).onTaskVanished(any()); 224 } 225 226 @Test testTaskNoDraw()227 public void testTaskNoDraw() throws RemoteException { 228 final ITaskOrganizer organizer = registerMockOrganizer(); 229 final Task rootTask = createRootTask(); 230 final Task task = createTask(rootTask, false /* fakeDraw */); 231 // Ensure events dispatch to organizer. 232 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 233 234 verify(organizer, never()) 235 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 236 assertTrue(rootTask.isOrganized()); 237 238 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer); 239 // Ensure events dispatch to organizer. 240 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 241 verify(organizer, times(0)).onTaskVanished(any()); 242 assertFalse(rootTask.isOrganized()); 243 } 244 245 @Test testClearOrganizer()246 public void testClearOrganizer() throws RemoteException { 247 final ITaskOrganizer organizer = registerMockOrganizer(); 248 final Task rootTask = createRootTask(); 249 final Task task = createTask(rootTask); 250 // Ensure events dispatch to organizer. 251 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 252 253 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 254 assertTrue(rootTask.isOrganized()); 255 256 rootTask.setTaskOrganizer(null); 257 // Ensure events dispatch to organizer. 258 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 259 260 verify(organizer).onTaskVanished(any()); 261 assertFalse(rootTask.isOrganized()); 262 } 263 264 @Test testRemoveWithOrganizerRemovesTask()265 public void testRemoveWithOrganizerRemovesTask() throws RemoteException { 266 final ITaskOrganizer organizer = registerMockOrganizer(); 267 final Task rootTask = createRootTask(); 268 final Task task = createTask(rootTask); 269 rootTask.mRemoveWithTaskOrganizer = true; 270 271 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 272 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 273 assertTrue(rootTask.isOrganized()); 274 275 spyOn(mWm.mAtmService); 276 rootTask.setTaskOrganizer(null); 277 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 278 279 verify(mWm.mAtmService).removeTask(eq(rootTask)); 280 } 281 282 @Test testNoRemoveWithOrganizerNoRemoveTask()283 public void testNoRemoveWithOrganizerNoRemoveTask() throws RemoteException { 284 final ITaskOrganizer organizer = registerMockOrganizer(); 285 final Task rootTask = createRootTask(); 286 final Task task = createTask(rootTask); 287 rootTask.mRemoveWithTaskOrganizer = false; 288 289 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 290 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 291 assertTrue(rootTask.isOrganized()); 292 293 spyOn(mWm.mAtmService); 294 rootTask.setTaskOrganizer(null); 295 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 296 297 verify(mWm.mAtmService, never()).removeTask(eq(rootTask)); 298 } 299 300 @Test testUnregisterOrganizer()301 public void testUnregisterOrganizer() throws RemoteException { 302 final ITaskOrganizer organizer = registerMockOrganizer(); 303 final Task rootTask = createRootTask(); 304 final Task task = createTask(rootTask); 305 // Ensure events dispatch to organizer. 306 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 307 308 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 309 assertTrue(rootTask.isOrganized()); 310 311 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer); 312 // Ensure events dispatch to organizer. 313 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 314 315 verify(organizer, times(0)).onTaskVanished(any()); 316 assertFalse(rootTask.isOrganized()); 317 } 318 319 @Test testUnregisterOrganizerReturnsRegistrationToPrevious()320 public void testUnregisterOrganizerReturnsRegistrationToPrevious() throws RemoteException { 321 final Task rootTask = createRootTask(); 322 final Task task = createTask(rootTask); 323 final Task rootTask2 = createRootTask(); 324 final Task task2 = createTask(rootTask2); 325 final Task rootTask3 = createRootTask(); 326 final Task task3 = createTask(rootTask3); 327 final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 328 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 329 // Ensure events dispatch to organizer. 330 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 331 332 // verify that tasks are returned and taskAppeared is not called 333 assertContainsTasks(existingTasks, rootTask, rootTask2, rootTask3); 334 verify(organizer, times(0)).onTaskAppeared(any(RunningTaskInfo.class), 335 any(SurfaceControl.class)); 336 verify(organizer, times(0)).onTaskVanished(any()); 337 assertTrue(rootTask.isOrganized()); 338 339 // Now we replace the registration and verify the new organizer receives existing tasks 340 final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>(); 341 final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2); 342 // Ensure events dispatch to organizer. 343 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 344 assertContainsTasks(existingTasks2, rootTask, rootTask2, rootTask3); 345 verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class), 346 any(SurfaceControl.class)); 347 verify(organizer2, times(0)).onTaskVanished(any()); 348 // Removed tasks from the original organizer 349 assertTaskVanished(organizer, true /* expectVanished */, rootTask, rootTask2, rootTask3); 350 assertTrue(rootTask2.isOrganized()); 351 352 // Now we unregister the second one, the first one should automatically be reregistered 353 // so we verify that it's now seeing changes. 354 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2); 355 // Ensure events dispatch to organizer. 356 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 357 verify(organizer, times(3)) 358 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 359 verify(organizer2, times(0)).onTaskVanished(any()); 360 } 361 362 @Test testUnregisterOrganizer_removesTasksCreatedByIt()363 public void testUnregisterOrganizer_removesTasksCreatedByIt() throws RemoteException { 364 final Task rootTask = createRootTask(); 365 final Task task = createTask(rootTask); 366 final Task rootTask2 = createRootTask(); 367 rootTask2.mCreatedByOrganizer = true; 368 final Task task2 = createTask(rootTask2); 369 final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 370 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 371 // Ensure events dispatch to organizer. 372 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 373 374 // verify that tasks are returned and taskAppeared is called only for rootTask2 since it 375 // is the one created by this organizer. 376 assertContainsTasks(existingTasks, rootTask); 377 verify(organizer, times(1)).onTaskAppeared(any(RunningTaskInfo.class), 378 any(SurfaceControl.class)); 379 verify(organizer, times(0)).onTaskVanished(any()); 380 assertTrue(rootTask.isOrganized()); 381 382 // Now we replace the registration and verify the new organizer receives existing tasks 383 final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>(); 384 final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2); 385 // Ensure events dispatch to organizer. 386 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 387 assertContainsTasks(existingTasks2, rootTask); 388 verify(organizer2, never()).onTaskAppeared(any(RunningTaskInfo.class), 389 any(SurfaceControl.class)); 390 verify(organizer2, times(0)).onTaskVanished(any()); 391 // The non-CreatedByOrganizer task is removed from the original organizer. 392 assertTaskVanished(organizer, true /* expectVanished */, rootTask); 393 assertEquals(organizer2, rootTask.mTaskOrganizer); 394 // The CreatedByOrganizer task should be still organized by the original organizer. 395 assertEquals(organizer, rootTask2.mTaskOrganizer); 396 397 clearInvocations(organizer); 398 // Now we unregister the second one, the first one should automatically be reregistered 399 // so we verify that it's now seeing changes. 400 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2); 401 // Ensure events dispatch to organizer. 402 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 403 404 verify(organizer, times(2)) 405 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 406 407 // Unregister the first one. The CreatedByOrganizer task created by it must be removed. 408 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer); 409 assertFalse(rootTask2.isAttached()); 410 assertFalse(task2.isAttached()); 411 // Normal task should keep. 412 assertTrue(task.isAttached()); 413 verify(organizer2, times(0)).onTaskVanished(any()); 414 } 415 416 @Test testOrganizerDeathReturnsRegistrationToPrevious()417 public void testOrganizerDeathReturnsRegistrationToPrevious() throws RemoteException { 418 final Task rootTask = createRootTask(); 419 final Task task = createTask(rootTask); 420 final Task rootTask2 = createRootTask(); 421 final Task task2 = createTask(rootTask2); 422 final Task rootTask3 = createRootTask(); 423 final Task task3 = createTask(rootTask3); 424 final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 425 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 426 // Ensure events dispatch to organizer. 427 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 428 429 // verify that tasks are returned and taskAppeared is not called 430 assertContainsTasks(existingTasks, rootTask, rootTask2, rootTask3); 431 verify(organizer, times(0)).onTaskAppeared(any(RunningTaskInfo.class), 432 any(SurfaceControl.class)); 433 verify(organizer, times(0)).onTaskVanished(any()); 434 assertTrue(rootTask.isOrganized()); 435 436 // Now we replace the registration and verify the new organizer receives existing tasks 437 final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>(); 438 final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2); 439 // Ensure events dispatch to organizer. 440 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 441 assertContainsTasks(existingTasks2, rootTask, rootTask2, rootTask3); 442 verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class), 443 any(SurfaceControl.class)); 444 verify(organizer2, times(0)).onTaskVanished(any()); 445 // Removed tasks from the original organizer 446 assertTaskVanished(organizer, true /* expectVanished */, rootTask, rootTask2, rootTask3); 447 assertTrue(rootTask2.isOrganized()); 448 449 // Trigger binderDied for second one, the first one should automatically be reregistered 450 // so we verify that it's now seeing changes. 451 mWm.mAtmService.mTaskOrganizerController.getTaskOrganizerState(organizer2.asBinder()) 452 .getDeathRecipient().binderDied(); 453 454 // Ensure events dispatch to organizer. 455 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 456 verify(organizer, times(3)) 457 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 458 verify(organizer2, times(0)).onTaskVanished(any()); 459 } 460 461 @Test testRegisterTaskOrganizerWithExistingTasks()462 public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException { 463 final Task rootTask = createRootTask(); 464 final Task task = createTask(rootTask); 465 final Task rootTask2 = createRootTask(); 466 final Task task2 = createTask(rootTask2); 467 ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 468 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 469 assertContainsTasks(existingTasks, rootTask, rootTask2); 470 471 // Verify we don't get onTaskAppeared if we are returned the tasks 472 verify(organizer, never()) 473 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 474 } 475 476 @Test testRegisterTaskOrganizerWithExistingTasks_noSurfaceControl()477 public void testRegisterTaskOrganizerWithExistingTasks_noSurfaceControl() 478 throws RemoteException { 479 final Task rootTask = createRootTask(); 480 final Task task = createTask(rootTask); 481 final Task rootTask2 = createRootTask(); 482 final Task task2 = createTask(rootTask2); 483 rootTask2.setSurfaceControl(null); 484 ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 485 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 486 assertContainsTasks(existingTasks, rootTask); 487 488 // Verify we don't get onTaskAppeared if we are returned the tasks 489 verify(organizer, never()) 490 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 491 } 492 493 @Test testTaskTransaction()494 public void testTaskTransaction() { 495 removeGlobalMinSizeRestriction(); 496 final Task rootTask = new TaskBuilder(mSupervisor) 497 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 498 final Task task = rootTask.getTopMostTask(); 499 testTransaction(task); 500 } 501 502 @Test testRootTaskTransaction()503 public void testRootTaskTransaction() { 504 removeGlobalMinSizeRestriction(); 505 final Task rootTask = new TaskBuilder(mSupervisor) 506 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 507 RootTaskInfo info = 508 mWm.mAtmService.getRootTaskInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); 509 assertEquals(rootTask.mRemoteToken.toWindowContainerToken(), info.token); 510 testTransaction(rootTask); 511 } 512 513 @Test testDisplayAreaTransaction()514 public void testDisplayAreaTransaction() { 515 removeGlobalMinSizeRestriction(); 516 final DisplayArea displayArea = mDisplayContent.getDefaultTaskDisplayArea(); 517 testTransaction(displayArea); 518 } 519 testTransaction(WindowContainer wc)520 private void testTransaction(WindowContainer wc) { 521 WindowContainerTransaction t = new WindowContainerTransaction(); 522 Rect newBounds = new Rect(10, 10, 100, 100); 523 t.setBounds(wc.mRemoteToken.toWindowContainerToken(), new Rect(10, 10, 100, 100)); 524 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 525 assertEquals(newBounds, wc.getBounds()); 526 } 527 528 @Test testSetWindowingMode()529 public void testSetWindowingMode() { 530 final Task rootTask = new TaskBuilder(mSupervisor) 531 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 532 testSetWindowingMode(rootTask); 533 534 final DisplayArea displayArea = mDisplayContent.getDefaultTaskDisplayArea(); 535 displayArea.setWindowingMode(WINDOWING_MODE_FREEFORM); 536 testSetWindowingMode(displayArea); 537 } 538 testSetWindowingMode(WindowContainer wc)539 private void testSetWindowingMode(WindowContainer wc) { 540 final WindowContainerTransaction t = new WindowContainerTransaction(); 541 t.setWindowingMode(wc.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_FULLSCREEN); 542 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 543 assertEquals(WINDOWING_MODE_FULLSCREEN, wc.getWindowingMode()); 544 } 545 546 @Test 547 @RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2) testSetActivityWindowingMode()548 public void testSetActivityWindowingMode() { 549 final ActivityRecord record = makePipableActivity(); 550 final Task rootTask = record.getRootTask(); 551 final WindowContainerTransaction t = new WindowContainerTransaction(); 552 553 t.setWindowingMode(rootTask.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_PINNED); 554 t.setActivityWindowingMode( 555 rootTask.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_FULLSCREEN); 556 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 557 558 assertEquals(WINDOWING_MODE_FULLSCREEN, record.getWindowingMode()); 559 // Get the root task from the PIP activity record again, since the PIP root task may have 560 // changed when the activity entered PIP mode. 561 final Task pipRootTask = record.getRootTask(); 562 assertEquals(WINDOWING_MODE_PINNED, pipRootTask.getWindowingMode()); 563 } 564 565 @Test testContainerFocusableChanges()566 public void testContainerFocusableChanges() { 567 removeGlobalMinSizeRestriction(); 568 final Task rootTask = new TaskBuilder(mSupervisor) 569 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 570 final Task task = rootTask.getTopMostTask(); 571 WindowContainerTransaction t = new WindowContainerTransaction(); 572 assertTrue(task.isFocusable()); 573 t.setFocusable(rootTask.mRemoteToken.toWindowContainerToken(), false); 574 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 575 assertFalse(task.isFocusable()); 576 t.setFocusable(rootTask.mRemoteToken.toWindowContainerToken(), true); 577 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 578 assertTrue(task.isFocusable()); 579 } 580 581 @Test testContainerHiddenChanges()582 public void testContainerHiddenChanges() { 583 removeGlobalMinSizeRestriction(); 584 final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) 585 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 586 WindowContainerTransaction t = new WindowContainerTransaction(); 587 assertTrue(rootTask.shouldBeVisible(null)); 588 t.setHidden(rootTask.mRemoteToken.toWindowContainerToken(), true); 589 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 590 assertFalse(rootTask.shouldBeVisible(null)); 591 t.setHidden(rootTask.mRemoteToken.toWindowContainerToken(), false); 592 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 593 assertTrue(rootTask.shouldBeVisible(null)); 594 } 595 596 @Test testTaskFragmentHiddenFocusableTranslucentChanges()597 public void testTaskFragmentHiddenFocusableTranslucentChanges() { 598 mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); 599 600 removeGlobalMinSizeRestriction(); 601 final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) 602 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build(); 603 604 final WindowContainerTransaction t = new WindowContainerTransaction(); 605 final TaskFragmentOrganizer organizer = 606 createTaskFragmentOrganizer(t, true /* isSystemOrganizer */); 607 608 final IBinder token = new Binder(); 609 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 610 .setParentTask(rootTask) 611 .setFragmentToken(token) 612 .setOrganizer(organizer) 613 .createActivityCount(1) 614 .build(); 615 616 // Should be visible and focusable initially. 617 assertTrue(rootTask.shouldBeVisible(null)); 618 assertTrue(taskFragment.shouldBeVisible(null)); 619 assertTrue(taskFragment.isFocusable()); 620 assertTrue(taskFragment.isTopActivityFocusable()); 621 assertFalse(taskFragment.isForceTranslucent()); 622 623 // Apply transaction to the TaskFragment hidden and not focusable. 624 t.setHidden(taskFragment.mRemoteToken.toWindowContainerToken(), true); 625 t.setFocusable(taskFragment.mRemoteToken.toWindowContainerToken(), false); 626 t.setForceTranslucent(taskFragment.mRemoteToken.toWindowContainerToken(), true); 627 mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked( 628 t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE, 629 false /* shouldApplyIndependently */, null /* remoteTransition */); 630 631 // Should be not visible and not focusable after the transaction. 632 assertFalse(taskFragment.shouldBeVisible(null)); 633 assertFalse(taskFragment.isFocusable()); 634 assertFalse(taskFragment.isTopActivityFocusable()); 635 assertTrue(taskFragment.isForceTranslucent()); 636 637 // Apply transaction to the TaskFragment not hidden and focusable. 638 t.setHidden(taskFragment.mRemoteToken.toWindowContainerToken(), false); 639 t.setFocusable(taskFragment.mRemoteToken.toWindowContainerToken(), true); 640 t.setForceTranslucent(taskFragment.mRemoteToken.toWindowContainerToken(), false); 641 mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked( 642 t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE, 643 false /* shouldApplyIndependently */, null /* remoteTransition */); 644 645 // Should be visible and focusable after the transaction. 646 assertTrue(taskFragment.shouldBeVisible(null)); 647 assertTrue(taskFragment.isFocusable()); 648 assertTrue(taskFragment.isTopActivityFocusable()); 649 assertFalse(taskFragment.isForceTranslucent()); 650 } 651 652 @Test testStartActivityInTaskFragment_checkCallerPermission()653 public void testStartActivityInTaskFragment_checkCallerPermission() { 654 final ActivityStartController activityStartController = 655 mWm.mAtmService.getActivityStartController(); 656 spyOn(activityStartController); 657 final ArgumentCaptor<SafeActivityOptions> activityOptionsCaptor = 658 ArgumentCaptor.forClass(SafeActivityOptions.class); 659 660 final int uid = Binder.getCallingUid(); 661 final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) 662 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build(); 663 final WindowContainerTransaction t = new WindowContainerTransaction(); 664 final TaskFragmentOrganizer organizer = 665 createTaskFragmentOrganizer(t, true /* isSystemOrganizer */); 666 final IBinder token = new Binder(); 667 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 668 .setParentTask(rootTask) 669 .setFragmentToken(token) 670 .setOrganizer(organizer) 671 .createActivityCount(1) 672 .build(); 673 mWm.mAtmService.mWindowOrganizerController.mLaunchTaskFragments.put(token, taskFragment); 674 final ActivityRecord ownerActivity = taskFragment.getTopMostActivity(); 675 676 // Start Activity in TaskFragment with remote transition. 677 final RemoteTransition transition = mock(RemoteTransition.class); 678 final ActivityOptions options = ActivityOptions.makeRemoteTransition(transition); 679 final Intent intent = new Intent(); 680 t.startActivityInTaskFragment(token, ownerActivity.token, intent, options.toBundle()); 681 mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked( 682 t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_OPEN, 683 false /* shouldApplyIndependently */, null /* remoteTransition */); 684 685 // Get the ActivityOptions. 686 verify(activityStartController).startActivityInTaskFragment( 687 eq(taskFragment), eq(intent), activityOptionsCaptor.capture(), 688 eq(ownerActivity.token), eq(uid), anyInt(), any()); 689 final SafeActivityOptions safeActivityOptions = activityOptionsCaptor.getValue(); 690 691 final MockitoSession session = 692 mockitoSession().strictness(LENIENT).spyStatic(ActivityTaskManagerService.class) 693 .startMocking(); 694 try { 695 // Without the CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS permission, start activity with 696 // remote transition is not allowed. 697 doReturn(PERMISSION_DENIED).when(() -> ActivityTaskManagerService.checkPermission( 698 eq(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS), anyInt(), eq(uid))); 699 assertThrows(SecurityException.class, 700 () -> safeActivityOptions.getOptions(mWm.mAtmService.mTaskSupervisor)); 701 702 // With the CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS permission, start activity with 703 // remote transition is allowed. 704 doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission( 705 eq(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS), anyInt(), eq(uid))); 706 safeActivityOptions.getOptions(mWm.mAtmService.mTaskSupervisor); 707 } finally { 708 session.finishMocking(); 709 } 710 } 711 712 @Test testTaskFragmentChangeHidden_throwsWhenNotSystemOrganizer()713 public void testTaskFragmentChangeHidden_throwsWhenNotSystemOrganizer() { 714 // Non-system organizers are not allow to update the hidden state. 715 testTaskFragmentChangesWithoutSystemOrganizerThrowException( 716 (t, windowContainerToken) -> t.setHidden(windowContainerToken, true)); 717 } 718 719 @Test testTaskFragmentChangeFocusable_throwsWhenNotSystemOrganizer()720 public void testTaskFragmentChangeFocusable_throwsWhenNotSystemOrganizer() { 721 // Non-system organizers are not allow to update the focusable state. 722 testTaskFragmentChangesWithoutSystemOrganizerThrowException( 723 (t, windowContainerToken) -> t.setFocusable(windowContainerToken, false)); 724 } 725 726 @Test testTaskFragmentChangeTranslucent_throwsWhenNotSystemOrganizer()727 public void testTaskFragmentChangeTranslucent_throwsWhenNotSystemOrganizer() { 728 // Non-system organizers are not allow to update the translucent state. 729 testTaskFragmentChangesWithoutSystemOrganizerThrowException( 730 (t, windowContainerToken) -> t.setForceTranslucent(windowContainerToken, true)); 731 } 732 testTaskFragmentChangesWithoutSystemOrganizerThrowException( BiConsumer<WindowContainerTransaction, WindowContainerToken> addOp)733 private void testTaskFragmentChangesWithoutSystemOrganizerThrowException( 734 BiConsumer<WindowContainerTransaction, WindowContainerToken> addOp) { 735 mSetFlagsRule.enableFlags(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG); 736 737 removeGlobalMinSizeRestriction(); 738 final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) 739 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build(); 740 741 final WindowContainerTransaction t = new WindowContainerTransaction(); 742 final TaskFragmentOrganizer organizer = 743 createTaskFragmentOrganizer(t, false /* isSystemOrganizer */); 744 745 final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) 746 .setParentTask(rootTask) 747 .setFragmentToken(new Binder()) 748 .setOrganizer(organizer) 749 .createActivityCount(1) 750 .build(); 751 752 addOp.accept(t, taskFragment.mRemoteToken.toWindowContainerToken()); 753 754 assertThrows(SecurityException.class, () -> 755 mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked( 756 t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE, 757 false /* shouldApplyIndependently */, null /* remoteTransition */) 758 ); 759 } 760 761 @Test testContainerTranslucentChanges()762 public void testContainerTranslucentChanges() { 763 removeGlobalMinSizeRestriction(); 764 final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) 765 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build(); 766 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 767 WindowContainerTransaction t = new WindowContainerTransaction(); 768 assertFalse(rootTask.isTranslucent(activity)); 769 t.setForceTranslucent(rootTask.mRemoteToken.toWindowContainerToken(), true); 770 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 771 assertTrue(rootTask.isTranslucent(activity)); 772 t.setForceTranslucent(rootTask.mRemoteToken.toWindowContainerToken(), false); 773 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 774 assertFalse(rootTask.isTranslucent(activity)); 775 } 776 777 @Test testSetIgnoreOrientationRequest_taskDisplayArea()778 public void testSetIgnoreOrientationRequest_taskDisplayArea() { 779 removeGlobalMinSizeRestriction(); 780 final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); 781 final Task rootTask = taskDisplayArea.createRootTask( 782 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 783 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 784 taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 785 mDisplayContent.setFocusedApp(activity); 786 activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); 787 788 // TDA returns UNSET when ignoreOrientationRequest == true 789 // DC is UNSPECIFIED when child returns UNSET 790 assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET); 791 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED); 792 793 WindowContainerTransaction t = new WindowContainerTransaction(); 794 t.setIgnoreOrientationRequest( 795 taskDisplayArea.mRemoteToken.toWindowContainerToken(), 796 false /* ignoreOrientationRequest */); 797 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 798 799 // TDA returns app request orientation when ignoreOrientationRequest == false 800 // DC uses the same as TDA returns when it is not UNSET. 801 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); 802 assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); 803 804 t.setIgnoreOrientationRequest( 805 taskDisplayArea.mRemoteToken.toWindowContainerToken(), 806 true /* ignoreOrientationRequest */); 807 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 808 809 // TDA returns UNSET when ignoreOrientationRequest == true 810 // DC is UNSPECIFIED when child returns UNSET 811 assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET); 812 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED); 813 } 814 815 @Test testSetIgnoreOrientationRequest_displayContent()816 public void testSetIgnoreOrientationRequest_displayContent() { 817 removeGlobalMinSizeRestriction(); 818 final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); 819 final Task rootTask = taskDisplayArea.createRootTask( 820 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 821 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 822 mDisplayContent.setFocusedApp(activity); 823 activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); 824 825 // DC uses the orientation request from app 826 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); 827 828 WindowContainerTransaction t = new WindowContainerTransaction(); 829 t.setIgnoreOrientationRequest( 830 mDisplayContent.mRemoteToken.toWindowContainerToken(), 831 true /* ignoreOrientationRequest */); 832 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 833 834 // DC returns UNSPECIFIED when ignoreOrientationRequest == true 835 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED); 836 837 t.setIgnoreOrientationRequest( 838 mDisplayContent.mRemoteToken.toWindowContainerToken(), 839 false /* ignoreOrientationRequest */); 840 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 841 842 // DC uses the orientation request from app after mIgnoreOrientationRequest is set to false 843 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); 844 } 845 846 @Test testOverrideConfigSize()847 public void testOverrideConfigSize() { 848 removeGlobalMinSizeRestriction(); 849 final Task rootTask = new TaskBuilder(mSupervisor) 850 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 851 final Task task = rootTask.getTopMostTask(); 852 WindowContainerTransaction t = new WindowContainerTransaction(); 853 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 854 final int origScreenWDp = task.getConfiguration().screenHeightDp; 855 final int origScreenHDp = task.getConfiguration().screenHeightDp; 856 t = new WindowContainerTransaction(); 857 // verify that setting config overrides on parent restricts children. 858 t.setScreenSizeDp(rootTask.mRemoteToken 859 .toWindowContainerToken(), origScreenWDp, origScreenHDp / 2); 860 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 861 assertEquals(origScreenHDp / 2, task.getConfiguration().screenHeightDp); 862 t = new WindowContainerTransaction(); 863 t.setScreenSizeDp(rootTask.mRemoteToken.toWindowContainerToken(), SCREEN_WIDTH_DP_UNDEFINED, 864 SCREEN_HEIGHT_DP_UNDEFINED); 865 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 866 assertEquals(origScreenHDp, task.getConfiguration().screenHeightDp); 867 } 868 869 @Test testCreateDeleteRootTasks()870 public void testCreateDeleteRootTasks() { 871 DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY); 872 873 Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 874 dc, WINDOWING_MODE_FULLSCREEN, null); 875 RunningTaskInfo info1 = task1.getTaskInfo(); 876 assertEquals(WINDOWING_MODE_FULLSCREEN, 877 info1.configuration.windowConfiguration.getWindowingMode()); 878 assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType); 879 880 Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 881 dc, WINDOWING_MODE_MULTI_WINDOW, null); 882 RunningTaskInfo info2 = task2.getTaskInfo(); 883 assertEquals(WINDOWING_MODE_MULTI_WINDOW, 884 info2.configuration.windowConfiguration.getWindowingMode()); 885 assertEquals(ACTIVITY_TYPE_UNDEFINED, info2.topActivityType); 886 887 List<Task> infos = getTasksCreatedByOrganizer(dc); 888 assertEquals(2, infos.size()); 889 890 assertTrue(mWm.mAtmService.mTaskOrganizerController.deleteRootTask(info1.token)); 891 infos = getTasksCreatedByOrganizer(dc); 892 assertEquals(1, infos.size()); 893 assertEquals(WINDOWING_MODE_MULTI_WINDOW, infos.get(0).getWindowingMode()); 894 } 895 896 @Test testSetAdjacentLaunchRoot()897 public void testSetAdjacentLaunchRoot() { 898 DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY); 899 900 final Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 901 dc, WINDOWING_MODE_MULTI_WINDOW, null); 902 final RunningTaskInfo info1 = task1.getTaskInfo(); 903 final Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 904 dc, WINDOWING_MODE_MULTI_WINDOW, null); 905 final RunningTaskInfo info2 = task2.getTaskInfo(); 906 907 WindowContainerTransaction wct = new WindowContainerTransaction(); 908 wct.setAdjacentRoots(info1.token, info2.token); 909 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 910 assertEquals(task1.getAdjacentTaskFragment(), task2); 911 assertEquals(task2.getAdjacentTaskFragment(), task1); 912 913 wct = new WindowContainerTransaction(); 914 wct.setLaunchAdjacentFlagRoot(info1.token); 915 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 916 assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, task1); 917 918 wct = new WindowContainerTransaction(); 919 wct.clearAdjacentRoots(info1.token); 920 wct.clearLaunchAdjacentFlagRoot(info1.token); 921 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 922 assertEquals(task1.getAdjacentTaskFragment(), null); 923 assertEquals(task2.getAdjacentTaskFragment(), null); 924 assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, null); 925 } 926 927 @Test testTileAddRemoveChild()928 public void testTileAddRemoveChild() { 929 final StubOrganizer listener = new StubOrganizer(); 930 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); 931 Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask( 932 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 933 RunningTaskInfo info1 = task.getTaskInfo(); 934 935 final Task rootTask = createTask( 936 mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD); 937 assertEquals(mDisplayContent.getWindowingMode(), rootTask.getWindowingMode()); 938 WindowContainerTransaction wct = new WindowContainerTransaction(); 939 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */); 940 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 941 assertEquals(info1.configuration.windowConfiguration.getWindowingMode(), 942 rootTask.getWindowingMode()); 943 944 // Info should reflect new membership 945 List<Task> infos = getTasksCreatedByOrganizer(mDisplayContent); 946 info1 = infos.get(0).getTaskInfo(); 947 assertEquals(ACTIVITY_TYPE_STANDARD, info1.topActivityType); 948 949 // Children inherit configuration 950 Rect newSize = new Rect(10, 10, 300, 300); 951 Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask(); 952 Configuration c = new Configuration(task1.getRequestedOverrideConfiguration()); 953 c.windowConfiguration.setBounds(newSize); 954 doNothing().when(rootTask).adjustForMinimalTaskDimensions(any(), any(), any()); 955 task1.onRequestedOverrideConfigurationChanged(c); 956 assertEquals(newSize, rootTask.getBounds()); 957 958 wct = new WindowContainerTransaction(); 959 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), null, true /* onTop */); 960 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 961 assertEquals(mDisplayContent.getWindowingMode(), rootTask.getWindowingMode()); 962 infos = getTasksCreatedByOrganizer(mDisplayContent); 963 info1 = infos.get(0).getTaskInfo(); 964 assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType); 965 } 966 967 @Test testAddInsetsSource()968 public void testAddInsetsSource() { 969 final Task rootTask = createTask(mDisplayContent); 970 971 final Task navigationBarInsetsReceiverTask = createTaskInRootTask(rootTask, 0); 972 navigationBarInsetsReceiverTask.getConfiguration().windowConfiguration.setBounds(new Rect( 973 0, 200, 1080, 700)); 974 975 final WindowContainerTransaction wct = new WindowContainerTransaction(); 976 wct.addInsetsSource( 977 navigationBarInsetsReceiverTask.mRemoteToken.toWindowContainerToken(), 978 new Binder(), 979 0 /* index */, 980 WindowInsets.Type.systemOverlays(), 981 new Rect(0, 0, 1080, 200), 982 null /* boundingRects */, 983 0 /* flags */); 984 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 985 986 assertThat(navigationBarInsetsReceiverTask.mLocalInsetsSources 987 .valueAt(0).getType()).isEqualTo( 988 WindowInsets.Type.systemOverlays()); 989 } 990 991 @Test testAddInsetsSource_withBoundingRects()992 public void testAddInsetsSource_withBoundingRects() { 993 final Task rootTask = createTask(mDisplayContent); 994 995 final Task navigationBarInsetsReceiverTask = createTaskInRootTask(rootTask, 0); 996 navigationBarInsetsReceiverTask.getConfiguration().windowConfiguration.setBounds(new Rect( 997 0, 200, 1080, 700)); 998 999 final Rect[] boundingRects = new Rect[]{ 1000 new Rect(0, 0, 10, 10), new Rect(100, 100, 200, 100) 1001 }; 1002 final WindowContainerTransaction wct = new WindowContainerTransaction(); 1003 wct.addInsetsSource( 1004 navigationBarInsetsReceiverTask.mRemoteToken.toWindowContainerToken(), 1005 new Binder(), 1006 0 /* index */, 1007 WindowInsets.Type.systemOverlays(), 1008 new Rect(0, 0, 1080, 200), 1009 boundingRects, 1010 0 /* flags */); 1011 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1012 1013 assertArrayEquals(boundingRects, navigationBarInsetsReceiverTask.mLocalInsetsSources 1014 .valueAt(0).getBoundingRects()); 1015 } 1016 1017 @Test 1018 @EnableFlags(Flags.FLAG_ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION) testAddInsetsSource_withFlags()1019 public void testAddInsetsSource_withFlags() { 1020 final Task rootTask = createTask(mDisplayContent); 1021 1022 final Task insetsReceiverTask = createTaskInRootTask(rootTask, 0); 1023 insetsReceiverTask.getConfiguration().windowConfiguration 1024 .setBounds(new Rect(0, 200, 1080, 700)); 1025 1026 final @InsetsSource.Flags int flags = FLAG_FORCE_CONSUMING; 1027 final WindowContainerTransaction wct = new WindowContainerTransaction(); 1028 wct.addInsetsSource( 1029 insetsReceiverTask.mRemoteToken.toWindowContainerToken(), 1030 new Binder(), 1031 0 /* index */, 1032 WindowInsets.Type.systemOverlays(), 1033 new Rect(0, 0, 1080, 200), 1034 null /* boundingRects */, 1035 flags); 1036 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1037 1038 assertEquals(flags, insetsReceiverTask.mLocalInsetsSources.valueAt(0).getFlags()); 1039 } 1040 1041 @Test testRemoveInsetsSource()1042 public void testRemoveInsetsSource() { 1043 final Task rootTask = createTask(mDisplayContent); 1044 1045 final Task navigationBarInsetsReceiverTask = createTaskInRootTask(rootTask, 0); 1046 navigationBarInsetsReceiverTask.getConfiguration().windowConfiguration.setBounds(new Rect( 1047 0, 200, 1080, 700)); 1048 final Binder owner = new Binder(); 1049 final WindowContainerTransaction wct = new WindowContainerTransaction(); 1050 wct.addInsetsSource( 1051 navigationBarInsetsReceiverTask.mRemoteToken.toWindowContainerToken(), 1052 owner, 1053 0 /* index */, 1054 WindowInsets.Type.systemOverlays(), 1055 new Rect(0, 0, 1080, 200), 1056 null /* boundingRects */, 1057 0 /* flags */); 1058 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1059 1060 final WindowContainerTransaction wct2 = new WindowContainerTransaction(); 1061 wct2.removeInsetsSource( 1062 navigationBarInsetsReceiverTask.mRemoteToken.toWindowContainerToken(), 1063 owner, 1064 0 /* index */, 1065 WindowInsets.Type.systemOverlays()); 1066 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct2); 1067 1068 assertThat(navigationBarInsetsReceiverTask.mLocalInsetsSources.size()).isEqualTo(0); 1069 } 1070 1071 @Test testTaskInfoCallback()1072 public void testTaskInfoCallback() { 1073 final ArrayList<RunningTaskInfo> lastReportedTiles = new ArrayList<>(); 1074 final boolean[] called = {false}; 1075 final StubOrganizer listener = new StubOrganizer() { 1076 @Override 1077 public void onTaskInfoChanged(RunningTaskInfo info) { 1078 lastReportedTiles.add(info); 1079 called[0] = true; 1080 } 1081 }; 1082 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); 1083 Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask( 1084 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 1085 RunningTaskInfo info1 = task.getTaskInfo(); 1086 // Ensure events dispatch to organizer. 1087 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1088 lastReportedTiles.clear(); 1089 called[0] = false; 1090 1091 final Task rootTask = createTask( 1092 mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD); 1093 Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask(); 1094 WindowContainerTransaction wct = new WindowContainerTransaction(); 1095 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */); 1096 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1097 assertTrue(called[0]); 1098 assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType); 1099 1100 lastReportedTiles.clear(); 1101 called[0] = false; 1102 final Task rootTask2 = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask(); 1103 wct = new WindowContainerTransaction(); 1104 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), 1105 info1.token, true /* onTop */); 1106 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1107 assertTrue(called[0]); 1108 assertEquals(ACTIVITY_TYPE_HOME, lastReportedTiles.get(0).topActivityType); 1109 1110 lastReportedTiles.clear(); 1111 called[0] = false; 1112 task1.positionChildAt(POSITION_TOP, rootTask, false /* includingParents */); 1113 mAtm.mTaskOrganizerController.dispatchPendingEvents(); 1114 assertTrue(called[0]); 1115 assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType); 1116 1117 lastReportedTiles.clear(); 1118 called[0] = false; 1119 wct = new WindowContainerTransaction(); 1120 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), 1121 null, true /* onTop */); 1122 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), 1123 null, true /* onTop */); 1124 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1125 assertTrue(called[0]); 1126 assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType); 1127 } 1128 1129 @Test testHierarchyTransaction()1130 public void testHierarchyTransaction() { 1131 final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>(); 1132 final StubOrganizer listener = new StubOrganizer() { 1133 @Override 1134 public void onTaskInfoChanged(RunningTaskInfo info) { 1135 lastReportedTiles.put(info.token.asBinder(), info); 1136 } 1137 }; 1138 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); 1139 1140 Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 1141 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 1142 RunningTaskInfo info1 = task1.getTaskInfo(); 1143 Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 1144 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 1145 RunningTaskInfo info2 = task2.getTaskInfo(); 1146 // Ensure events dispatch to organizer. 1147 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1148 1149 // 2 + 1 (home) = 3 1150 final int initialRootTaskCount = mWm.mAtmService.mTaskOrganizerController.getRootTasks( 1151 mDisplayContent.mDisplayId, null /* activityTypes */).size(); 1152 final Task rootTask = createTask( 1153 mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD); 1154 1155 // Check getRootTasks works 1156 List<RunningTaskInfo> roots = mWm.mAtmService.mTaskOrganizerController.getRootTasks( 1157 mDisplayContent.mDisplayId, null /* activityTypes */); 1158 assertEquals(initialRootTaskCount + 1, roots.size()); 1159 1160 lastReportedTiles.clear(); 1161 WindowContainerTransaction wct = new WindowContainerTransaction(); 1162 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), 1163 info1.token, true /* onTop */); 1164 final Task rootTask2 = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask(); 1165 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), 1166 info2.token, true /* onTop */); 1167 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1168 assertFalse(lastReportedTiles.isEmpty()); 1169 assertEquals(ACTIVITY_TYPE_STANDARD, 1170 lastReportedTiles.get(info1.token.asBinder()).topActivityType); 1171 assertEquals(ACTIVITY_TYPE_HOME, 1172 lastReportedTiles.get(info2.token.asBinder()).topActivityType); 1173 1174 lastReportedTiles.clear(); 1175 wct = new WindowContainerTransaction(); 1176 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), 1177 info1.token, false /* onTop */); 1178 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1179 assertFalse(lastReportedTiles.isEmpty()); 1180 // Standard should still be on top of tile 1, so no change there 1181 assertFalse(lastReportedTiles.containsKey(info1.token.asBinder())); 1182 // But tile 2 has no children, so should become undefined 1183 assertEquals(ACTIVITY_TYPE_UNDEFINED, 1184 lastReportedTiles.get(info2.token.asBinder()).topActivityType); 1185 1186 // Check the getChildren call 1187 List<RunningTaskInfo> children = 1188 mWm.mAtmService.mTaskOrganizerController.getChildTasks(info1.token, 1189 null /* activityTypes */); 1190 assertEquals(2, children.size()); 1191 children = mWm.mAtmService.mTaskOrganizerController.getChildTasks(info2.token, 1192 null /* activityTypes */); 1193 assertEquals(0, children.size()); 1194 1195 // Check that getRootTasks doesn't include children of tiles 1196 roots = mWm.mAtmService.mTaskOrganizerController.getRootTasks(mDisplayContent.mDisplayId, 1197 null /* activityTypes */); 1198 // Home (rootTask2) was moved into task1, so only remain 2 roots: task1 and task2. 1199 assertEquals(initialRootTaskCount - 1, roots.size()); 1200 1201 lastReportedTiles.clear(); 1202 wct = new WindowContainerTransaction(); 1203 wct.reorder(rootTask2.mRemoteToken.toWindowContainerToken(), true /* onTop */); 1204 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1205 // Home should now be on top. No change occurs in second tile, so not reported 1206 assertEquals(1, lastReportedTiles.size()); 1207 assertEquals(ACTIVITY_TYPE_HOME, 1208 lastReportedTiles.get(info1.token.asBinder()).topActivityType); 1209 1210 // This just needs to not crash (ie. it should be possible to reparent to display twice) 1211 wct = new WindowContainerTransaction(); 1212 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */); 1213 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1214 wct = new WindowContainerTransaction(); 1215 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */); 1216 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1217 } 1218 getTasksCreatedByOrganizer(DisplayContent dc)1219 private List<Task> getTasksCreatedByOrganizer(DisplayContent dc) { 1220 final ArrayList<Task> out = new ArrayList<>(); 1221 dc.forAllRootTasks(task -> { 1222 if (task.mCreatedByOrganizer) { 1223 out.add(task); 1224 } 1225 }); 1226 return out; 1227 } 1228 1229 @Test testBLASTCallbackWithActivityChildren()1230 public void testBLASTCallbackWithActivityChildren() { 1231 final Task rootTaskController1 = createRootTask(); 1232 final Task task = createTask(rootTaskController1); 1233 final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window"); 1234 1235 w.mActivityRecord.setVisibleRequested(true); 1236 w.mActivityRecord.setVisible(true); 1237 1238 BLASTSyncEngine bse = new BLASTSyncEngine(mWm); 1239 1240 BLASTSyncEngine.TransactionReadyListener transactionListener = 1241 mock(BLASTSyncEngine.TransactionReadyListener.class); 1242 1243 final int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "Test", 1244 false /* parallel */); 1245 bse.addToSyncSet(id, task); 1246 bse.setReady(id); 1247 bse.onSurfacePlacement(); 1248 1249 // Even though w is invisible (and thus activity isn't waiting on it), activity will 1250 // continue to wait until it has at-least 1 visible window. 1251 // Since we have a child window we still shouldn't be done. 1252 verify(transactionListener, never()).onTransactionReady(anyInt(), any()); 1253 1254 makeWindowVisible(w); 1255 bse.onSurfacePlacement(); 1256 w.immediatelyNotifyBlastSync(); 1257 bse.onSurfacePlacement(); 1258 1259 verify(transactionListener).onTransactionReady(anyInt(), any()); 1260 } 1261 1262 static class StubOrganizer extends ITaskOrganizer.Stub { 1263 RunningTaskInfo mInfo; 1264 1265 @Override addStartingWindow(StartingWindowInfo info)1266 public void addStartingWindow(StartingWindowInfo info) { } 1267 @Override removeStartingWindow(StartingWindowRemovalInfo removalInfo)1268 public void removeStartingWindow(StartingWindowRemovalInfo removalInfo) { } 1269 @Override copySplashScreenView(int taskId)1270 public void copySplashScreenView(int taskId) { } 1271 @Override onTaskAppeared(RunningTaskInfo info, SurfaceControl leash)1272 public void onTaskAppeared(RunningTaskInfo info, SurfaceControl leash) { 1273 mInfo = info; 1274 } 1275 @Override onTaskVanished(RunningTaskInfo info)1276 public void onTaskVanished(RunningTaskInfo info) { 1277 } 1278 @Override onTaskInfoChanged(RunningTaskInfo info)1279 public void onTaskInfoChanged(RunningTaskInfo info) { 1280 } 1281 @Override onBackPressedOnTaskRoot(RunningTaskInfo taskInfo)1282 public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { 1283 } 1284 @Override onImeDrawnOnTask(int taskId)1285 public void onImeDrawnOnTask(int taskId) throws RemoteException { 1286 } 1287 @Override onAppSplashScreenViewRemoved(int taskId)1288 public void onAppSplashScreenViewRemoved(int taskId) { 1289 } 1290 }; 1291 makePipableActivity()1292 private ActivityRecord makePipableActivity() { 1293 final ActivityRecord record = createActivityRecordWithParentTask(mDisplayContent, 1294 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 1295 record.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; 1296 record.setPictureInPictureParams(new PictureInPictureParams.Builder() 1297 .setAutoEnterEnabled(true).build()); 1298 spyOn(record); 1299 doReturn(true).when(record).checkEnterPictureInPictureState(any(), anyBoolean()); 1300 1301 record.getTask().setHasBeenVisible(true); 1302 return record; 1303 } 1304 1305 @Test 1306 @RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2) testEnterPipParams()1307 public void testEnterPipParams() { 1308 final StubOrganizer o = new StubOrganizer(); 1309 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o); 1310 final ActivityRecord record = makePipableActivity(); 1311 1312 final PictureInPictureParams p = new PictureInPictureParams.Builder() 1313 .setAspectRatio(new Rational(1, 2)).build(); 1314 assertTrue(mWm.mAtmService.mActivityClientController.enterPictureInPictureMode( 1315 record.token, p)); 1316 waitUntilHandlersIdle(); 1317 assertNotNull(o.mInfo); 1318 assertNotNull(o.mInfo.pictureInPictureParams); 1319 } 1320 1321 @Test 1322 @RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2) testChangePipParams()1323 public void testChangePipParams() { 1324 class ChangeSavingOrganizer extends StubOrganizer { 1325 RunningTaskInfo mChangedInfo; 1326 @Override 1327 public void onTaskInfoChanged(RunningTaskInfo info) { 1328 mChangedInfo = info; 1329 } 1330 } 1331 ChangeSavingOrganizer o = new ChangeSavingOrganizer(); 1332 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o); 1333 1334 final ActivityRecord record = makePipableActivity(); 1335 final PictureInPictureParams p = new PictureInPictureParams.Builder() 1336 .setAspectRatio(new Rational(1, 2)).build(); 1337 assertTrue(mWm.mAtmService.mActivityClientController.enterPictureInPictureMode( 1338 record.token, p)); 1339 waitUntilHandlersIdle(); 1340 assertNotNull(o.mInfo); 1341 assertNotNull(o.mInfo.pictureInPictureParams); 1342 1343 // Bypass the quota check, which causes NPE in current test setup. 1344 if (mWm.mAtmService.mActivityClientController.mSetPipAspectRatioQuotaTracker != null) { 1345 mWm.mAtmService.mActivityClientController.mSetPipAspectRatioQuotaTracker 1346 .setEnabled(false); 1347 } 1348 1349 final PictureInPictureParams p2 = new PictureInPictureParams.Builder() 1350 .setAspectRatio(new Rational(3, 4)).build(); 1351 mWm.mAtmService.mActivityClientController.setPictureInPictureParams(record.token, p2); 1352 waitUntilHandlersIdle(); 1353 // Ensure events dispatch to organizer. 1354 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1355 assertNotNull(o.mChangedInfo); 1356 assertNotNull(o.mChangedInfo.pictureInPictureParams); 1357 final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatio(); 1358 assertEquals(3, ratio.getNumerator()); 1359 assertEquals(4, ratio.getDenominator()); 1360 } 1361 1362 @Test testChangeTaskDescription()1363 public void testChangeTaskDescription() { 1364 class ChangeSavingOrganizer extends StubOrganizer { 1365 RunningTaskInfo mChangedInfo; 1366 @Override 1367 public void onTaskInfoChanged(RunningTaskInfo info) { 1368 mChangedInfo = info; 1369 } 1370 } 1371 ChangeSavingOrganizer o = new ChangeSavingOrganizer(); 1372 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o); 1373 1374 final Task rootTask = createRootTask(); 1375 final Task task = createTask(rootTask); 1376 final ActivityRecord record = createActivityRecordAndDispatchPendingEvents(task); 1377 1378 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1379 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); 1380 mAtm.mTaskOrganizerController.dispatchPendingEvents(); 1381 assertEquals("TestDescription", o.mChangedInfo.taskDescription.getLabel()); 1382 } 1383 1384 @Test testPreventDuplicateAppear()1385 public void testPreventDuplicateAppear() throws RemoteException { 1386 final ITaskOrganizer organizer = registerMockOrganizer(); 1387 final Task rootTask = createRootTask(); 1388 final Task task = createTask(rootTask, false /* fakeDraw */); 1389 1390 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1391 rootTask.setTaskOrganizer(organizer); 1392 // setHasBeenVisible was already called once by the set-up code. 1393 rootTask.setHasBeenVisible(true); 1394 // Ensure events dispatch to organizer. 1395 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1396 verify(organizer, times(1)) 1397 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 1398 1399 rootTask.setTaskOrganizer(null); 1400 // Ensure events dispatch to organizer. 1401 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1402 verify(organizer, times(1)).onTaskVanished(any()); 1403 rootTask.setTaskOrganizer(organizer); 1404 // Ensure events dispatch to organizer. 1405 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1406 verify(organizer, times(2)) 1407 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 1408 1409 rootTask.removeImmediately(); 1410 // Ensure events dispatch to organizer. 1411 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1412 verify(organizer, times(2)).onTaskVanished(any()); 1413 } 1414 1415 @Test testInterceptBackPressedOnTaskRoot()1416 public void testInterceptBackPressedOnTaskRoot() throws RemoteException { 1417 final ITaskOrganizer organizer = registerMockOrganizer(); 1418 final Task rootTask = createRootTask(); 1419 final Task task = createTask(rootTask); 1420 final ActivityRecord activity = createActivityRecord(rootTask.mDisplayContent, task); 1421 final Task rootTask2 = createRootTask(); 1422 final Task task2 = createTask(rootTask2); 1423 final ActivityRecord activity2 = createActivityRecord(rootTask.mDisplayContent, task2); 1424 1425 assertTrue(rootTask.isOrganized()); 1426 assertTrue(rootTask2.isOrganized()); 1427 1428 // Verify a back pressed does not call the organizer 1429 mWm.mAtmService.mActivityClientController.onBackPressed(activity.token, 1430 new IRequestFinishCallback.Default()); 1431 // Ensure events dispatch to organizer. 1432 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1433 verify(organizer, never()).onBackPressedOnTaskRoot(any()); 1434 1435 // Enable intercepting back 1436 mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot( 1437 rootTask.mRemoteToken.toWindowContainerToken(), true); 1438 1439 // Verify now that the back press does call the organizer 1440 mWm.mAtmService.mActivityClientController.onBackPressed(activity.token, 1441 new IRequestFinishCallback.Default()); 1442 // Ensure events dispatch to organizer. 1443 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1444 verify(organizer, times(1)).onBackPressedOnTaskRoot(any()); 1445 1446 // Disable intercepting back 1447 mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot( 1448 rootTask.mRemoteToken.toWindowContainerToken(), false); 1449 1450 // Verify now that the back press no longer calls the organizer 1451 mWm.mAtmService.mActivityClientController.onBackPressed(activity.token, 1452 new IRequestFinishCallback.Default()); 1453 // Ensure events dispatch to organizer. 1454 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1455 verify(organizer, times(1)).onBackPressedOnTaskRoot(any()); 1456 } 1457 1458 @Test testBLASTCallbackWithWindows()1459 public void testBLASTCallbackWithWindows() throws Exception { 1460 final Task rootTaskController = createRootTask(); 1461 final Task task = createTask(rootTaskController); 1462 final WindowState w1 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 1"); 1463 final WindowState w2 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 2"); 1464 makeWindowVisible(w1); 1465 makeWindowVisible(w2); 1466 1467 IWindowContainerTransactionCallback mockCallback = 1468 mock(IWindowContainerTransactionCallback.class); 1469 int id = mWm.mAtmService.mWindowOrganizerController.startSyncWithOrganizer(mockCallback); 1470 1471 mWm.mAtmService.mWindowOrganizerController.addToSyncSet(id, task); 1472 mWm.mAtmService.mWindowOrganizerController.setSyncReady(id); 1473 1474 // Since we have a window we have to wait for it to draw to finish sync. 1475 verify(mockCallback, never()).onTransactionReady(anyInt(), any()); 1476 assertTrue(w1.syncNextBuffer()); 1477 assertTrue(w2.syncNextBuffer()); 1478 1479 // Make second (bottom) ready. If we started with the top, since activities fillsParent 1480 // by default, the sync would be considered finished. 1481 w2.immediatelyNotifyBlastSync(); 1482 mWm.mSyncEngine.onSurfacePlacement(); 1483 verify(mockCallback, never()).onTransactionReady(anyInt(), any()); 1484 1485 assertEquals(SYNC_STATE_READY, w2.mSyncState); 1486 // Even though one Window finished drawing, both windows should still be using blast sync 1487 assertTrue(w1.syncNextBuffer()); 1488 assertTrue(w2.syncNextBuffer()); 1489 1490 // A drawn window in non-explicit sync can complete the sync state automatically. 1491 w1.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; 1492 w1.mPrepareSyncSeqId = 0; 1493 makeLastConfigReportedToClient(w1, true /* visible */); 1494 mWm.mSyncEngine.onSurfacePlacement(); 1495 verify(mockCallback).onTransactionReady(anyInt(), any()); 1496 assertFalse(w1.syncNextBuffer()); 1497 assertFalse(w2.syncNextBuffer()); 1498 } 1499 1500 @Test testDisplayAreaHiddenTransaction()1501 public void testDisplayAreaHiddenTransaction() { 1502 removeGlobalMinSizeRestriction(); 1503 1504 WindowContainerTransaction trx = new WindowContainerTransaction(); 1505 1506 TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); 1507 1508 trx.setHidden(taskDisplayArea.mRemoteToken.toWindowContainerToken(), true); 1509 mWm.mAtmService.mWindowOrganizerController.applyTransaction(trx); 1510 1511 taskDisplayArea.forAllTasks(daTask -> { 1512 assertTrue(daTask.isForceHidden()); 1513 }); 1514 1515 trx.setHidden(taskDisplayArea.mRemoteToken.toWindowContainerToken(), false); 1516 mWm.mAtmService.mWindowOrganizerController.applyTransaction(trx); 1517 1518 taskDisplayArea.forAllTasks(daTask -> { 1519 assertFalse(daTask.isForceHidden()); 1520 }); 1521 } 1522 1523 @Test testReparentToOrganizedTask()1524 public void testReparentToOrganizedTask() { 1525 final ITaskOrganizer organizer = registerMockOrganizer(); 1526 Task rootTask = mWm.mAtmService.mTaskOrganizerController.createRootTask( 1527 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 1528 final Task task1 = createRootTask(); 1529 final Task task2 = createTask(rootTask, false /* fakeDraw */); 1530 WindowContainerTransaction wct = new WindowContainerTransaction(); 1531 wct.reparent(task1.mRemoteToken.toWindowContainerToken(), 1532 rootTask.mRemoteToken.toWindowContainerToken(), true /* onTop */); 1533 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1534 assertTrue(task1.isOrganized()); 1535 assertTrue(task2.isOrganized()); 1536 } 1537 1538 @Test testAppearDeferThenInfoChange()1539 public void testAppearDeferThenInfoChange() { 1540 final ITaskOrganizer organizer = registerMockOrganizer(); 1541 final Task rootTask = createRootTask(); 1542 // Flush EVENT_APPEARED. 1543 mAtm.mTaskOrganizerController.dispatchPendingEvents(); 1544 1545 // Assume layout defer 1546 mWm.mWindowPlacerLocked.deferLayout(); 1547 1548 final Task task = createTask(rootTask); 1549 final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task); 1550 1551 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1552 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); 1553 waitUntilHandlersIdle(); 1554 1555 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1556 assertEquals(1, pendingEvents.size()); 1557 assertEquals(PendingTaskEvent.EVENT_APPEARED, pendingEvents.get(0).mEventType); 1558 assertEquals("TestDescription", 1559 pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel()); 1560 } 1561 1562 @Test testReorderWithParents()1563 public void testReorderWithParents() { 1564 /* 1565 default TDA 1566 ____|______ 1567 | | 1568 firstTda secondTda 1569 | | 1570 firstRootTask secondRootTask 1571 1572 */ 1573 final TaskDisplayArea firstTaskDisplayArea = createTaskDisplayArea( 1574 mDisplayContent, mRootWindowContainer.mWmService, "FirstTaskDisplayArea", 1575 FEATURE_VENDOR_FIRST); 1576 final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( 1577 mDisplayContent, mRootWindowContainer.mWmService, "SecondTaskDisplayArea", 1578 FEATURE_VENDOR_FIRST + 1); 1579 final Task firstRootTask = firstTaskDisplayArea.createRootTask( 1580 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 1581 final Task secondRootTask = secondTaskDisplayArea.createRootTask( 1582 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 1583 final ActivityRecord firstActivity = new ActivityBuilder(mAtm) 1584 .setTask(firstRootTask).build(); 1585 final ActivityRecord secondActivity = new ActivityBuilder(mAtm) 1586 .setTask(secondRootTask).build(); 1587 WindowContainerTransaction wct = new WindowContainerTransaction(); 1588 1589 // Reorder to top 1590 wct.reorder(firstRootTask.mRemoteToken.toWindowContainerToken(), true /* onTop */, 1591 true /* includingParents */); 1592 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1593 1594 // firstRootTask can only be on the top if its TDA was also reordered to the Top which 1595 // in-turn ensures that the reorder happened including the parents. 1596 assertThat(mDisplayContent.getTopRootTask()).isEqualTo(firstRootTask); 1597 1598 // Reorder to bottom 1599 wct.reorder(firstRootTask.mRemoteToken.toWindowContainerToken(), false /* onTop */, 1600 true /* includingParents */); 1601 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1602 1603 // firstRootTask can only be on the bottom if its TDA was also reordered to the bottom 1604 // which in-turn ensures that the reorder happened including the parents. 1605 assertThat(mDisplayContent.getBottomMostTask()).isEqualTo(firstRootTask); 1606 } 1607 1608 @Test testReorderDisplayArea()1609 public void testReorderDisplayArea() { 1610 /* 1611 defaultTda 1612 ____|______ 1613 | | 1614 firstTda secondTda 1615 | | 1616 firstRootTask secondRootTask 1617 1618 */ 1619 final TaskDisplayArea firstTaskDisplayArea = createTaskDisplayArea( 1620 mDisplayContent, mRootWindowContainer.mWmService, "FirstTaskDisplayArea", 1621 FEATURE_VENDOR_FIRST); 1622 final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( 1623 mDisplayContent, mRootWindowContainer.mWmService, "SecondTaskDisplayArea", 1624 FEATURE_VENDOR_FIRST + 1); 1625 final Task firstRootTask = firstTaskDisplayArea.createRootTask( 1626 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 1627 final Task secondRootTask = secondTaskDisplayArea.createRootTask( 1628 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 1629 final ActivityRecord firstActivity = new ActivityBuilder(mAtm) 1630 .setTask(firstRootTask).build(); 1631 final ActivityRecord secondActivity = new ActivityBuilder(mAtm) 1632 .setTask(secondRootTask).build(); 1633 1634 WindowContainerTransaction wct = new WindowContainerTransaction(); 1635 1636 // Reorder to top 1637 wct.reorder(firstTaskDisplayArea.mRemoteToken.toWindowContainerToken(), true /* onTop */, 1638 true /* includingParents */); 1639 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1640 assertThat(mDisplayContent.getTopRootTask()).isEqualTo(firstRootTask); 1641 1642 // Reorder to bottom 1643 wct.reorder(firstTaskDisplayArea.mRemoteToken.toWindowContainerToken(), false /* onTop */, 1644 true /* includingParents */); 1645 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1646 assertThat(mDisplayContent.getBottomMostTask()).isEqualTo(firstRootTask); 1647 } 1648 1649 @Test testReparentDisplayAreaUnsupported()1650 public void testReparentDisplayAreaUnsupported() { 1651 final TaskDisplayArea firstTaskDisplayArea = createTaskDisplayArea( 1652 mDisplayContent, mRootWindowContainer.mWmService, "FirstTaskDisplayArea", 1653 FEATURE_VENDOR_FIRST); 1654 final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( 1655 mDisplayContent, mRootWindowContainer.mWmService, "SecondTaskDisplayArea", 1656 FEATURE_VENDOR_FIRST + 1); 1657 1658 WindowContainerTransaction wct = new WindowContainerTransaction(); 1659 wct.reparent(firstTaskDisplayArea.mRemoteToken.toWindowContainerToken(), 1660 secondTaskDisplayArea.mRemoteToken.toWindowContainerToken(), 1661 true /* onTop */ 1662 ); 1663 1664 assertThrows(UnsupportedOperationException.class, () -> 1665 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct) 1666 ); 1667 } 1668 1669 @Test testAppearDeferThenVanish()1670 public void testAppearDeferThenVanish() { 1671 final ITaskOrganizer organizer = registerMockOrganizer(); 1672 final Task rootTask = createRootTask(); 1673 // Flush EVENT_APPEARED. 1674 mAtm.mTaskOrganizerController.dispatchPendingEvents(); 1675 1676 // Assume layout defer 1677 mWm.mWindowPlacerLocked.deferLayout(); 1678 1679 final Task task = createTask(rootTask); 1680 1681 rootTask.removeImmediately(); 1682 waitUntilHandlersIdle(); 1683 1684 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1685 assertEquals(0, pendingEvents.size()); 1686 } 1687 1688 @Test testInfoChangeDeferMultiple()1689 public void testInfoChangeDeferMultiple() { 1690 final ITaskOrganizer organizer = registerMockOrganizer(); 1691 final Task rootTask = createRootTask(); 1692 final Task task = createTask(rootTask); 1693 final ActivityRecord record = createActivityRecordAndDispatchPendingEvents(task); 1694 1695 // Assume layout defer 1696 mWm.mWindowPlacerLocked.deferLayout(); 1697 1698 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1699 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); 1700 waitUntilHandlersIdle(); 1701 1702 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1703 assertEquals(1, pendingEvents.size()); 1704 assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType); 1705 assertEquals("TestDescription", 1706 pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel()); 1707 1708 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription2")); 1709 waitUntilHandlersIdle(); 1710 1711 pendingEvents = getTaskPendingEvent(organizer, rootTask); 1712 assertEquals(1, pendingEvents.size()); 1713 assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType); 1714 assertEquals("TestDescription2", 1715 pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel()); 1716 } 1717 1718 @Test testInfoChangDeferThenVanish()1719 public void testInfoChangDeferThenVanish() { 1720 final ITaskOrganizer organizer = registerMockOrganizer(); 1721 final Task rootTask = createRootTask(); 1722 final Task task = createTask(rootTask); 1723 final ActivityRecord record = createActivityRecordAndDispatchPendingEvents(task); 1724 1725 // Assume layout defer 1726 mWm.mWindowPlacerLocked.deferLayout(); 1727 1728 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1729 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); 1730 1731 rootTask.removeImmediately(); 1732 waitUntilHandlersIdle(); 1733 1734 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1735 assertEquals(1, pendingEvents.size()); 1736 assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType); 1737 assertEquals("TestDescription", 1738 pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel()); 1739 } 1740 1741 @Test testVanishDeferThenInfoChange()1742 public void testVanishDeferThenInfoChange() { 1743 final ITaskOrganizer organizer = registerMockOrganizer(); 1744 final Task rootTask = createRootTask(); 1745 final Task task = createTask(rootTask); 1746 createActivityRecordAndDispatchPendingEvents(task); 1747 1748 // Assume layout defer 1749 mWm.mWindowPlacerLocked.deferLayout(); 1750 1751 rootTask.removeImmediately(); 1752 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1753 waitUntilHandlersIdle(); 1754 1755 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1756 assertEquals(1, pendingEvents.size()); 1757 assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType); 1758 } 1759 1760 @Test testVanishDeferThenBackOnRoot()1761 public void testVanishDeferThenBackOnRoot() { 1762 final ITaskOrganizer organizer = registerMockOrganizer(); 1763 final Task rootTask = createRootTask(); 1764 final Task task = createTask(rootTask); 1765 final ActivityRecord record = createActivityRecordAndDispatchPendingEvents(task); 1766 1767 // Assume layout defer 1768 mWm.mWindowPlacerLocked.deferLayout(); 1769 1770 rootTask.removeImmediately(); 1771 mWm.mAtmService.mActivityClientController.onBackPressed(record.token, 1772 new IRequestFinishCallback.Default()); 1773 waitUntilHandlersIdle(); 1774 1775 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1776 assertEquals(1, pendingEvents.size()); 1777 assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType); 1778 } 1779 getTaskPendingEvent(ITaskOrganizer organizer, Task task)1780 private ArrayList<PendingTaskEvent> getTaskPendingEvent(ITaskOrganizer organizer, Task task) { 1781 ArrayList<PendingTaskEvent> total = 1782 mWm.mAtmService.mTaskOrganizerController 1783 .getTaskOrganizerPendingEvents(organizer.asBinder()) 1784 .getPendingEventList(); 1785 ArrayList<PendingTaskEvent> result = new ArrayList(); 1786 1787 for (int i = 0; i < total.size(); i++) { 1788 PendingTaskEvent entry = total.get(i); 1789 if (entry.mTask.mTaskId == task.mTaskId) { 1790 result.add(entry); 1791 } 1792 } 1793 1794 return result; 1795 } 1796 1797 @Test testReparentNonResizableTaskToSplitScreen()1798 public void testReparentNonResizableTaskToSplitScreen() { 1799 final ActivityRecord activity = new ActivityBuilder(mAtm) 1800 .setCreateTask(true) 1801 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 1802 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 1803 .build(); 1804 final Task rootTask = activity.getRootTask(); 1805 rootTask.setResizeMode(activity.info.resizeMode); 1806 final Task splitPrimaryRootTask = mWm.mAtmService.mTaskOrganizerController.createRootTask( 1807 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 1808 final WindowContainerTransaction wct = new WindowContainerTransaction(); 1809 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), 1810 splitPrimaryRootTask.mRemoteToken.toWindowContainerToken(), true /* onTop */); 1811 1812 // Can't reparent non-resizable to split screen 1813 mAtm.mSupportsNonResizableMultiWindow = -1; 1814 mAtm.mWindowOrganizerController.applyTransaction(wct); 1815 1816 assertEquals(rootTask, activity.getRootTask()); 1817 1818 // Allow reparent non-resizable to split screen 1819 mAtm.mSupportsNonResizableMultiWindow = 1; 1820 mAtm.mWindowOrganizerController.applyTransaction(wct); 1821 1822 assertEquals(splitPrimaryRootTask, activity.getRootTask()); 1823 } 1824 1825 @Test testSizeCompatModeChangedOnFirstOrganizedTask()1826 public void testSizeCompatModeChangedOnFirstOrganizedTask() throws RemoteException { 1827 final ITaskOrganizer organizer = registerMockOrganizer(); 1828 final Task rootTask = createRootTask(); 1829 final Task task = createTask(rootTask); 1830 final ActivityRecord activity = createActivityRecordAndDispatchPendingEvents(task); 1831 final ArgumentCaptor<RunningTaskInfo> infoCaptor = 1832 ArgumentCaptor.forClass(RunningTaskInfo.class); 1833 1834 assertTrue(rootTask.isOrganized()); 1835 1836 doReturn(true).when(activity).inSizeCompatMode(); 1837 doReturn(true).when(activity).isState(RESUMED); 1838 1839 // Ensure task info show top activity in size compat. 1840 rootTask.onSizeCompatActivityChanged(); 1841 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1842 verify(organizer).onTaskInfoChanged(infoCaptor.capture()); 1843 RunningTaskInfo info = infoCaptor.getValue(); 1844 assertEquals(rootTask.mTaskId, info.taskId); 1845 assertTrue(info.appCompatTaskInfo.isTopActivityInSizeCompat()); 1846 1847 // Ensure task info show top activity that is not visible as not in size compat. 1848 clearInvocations(organizer); 1849 doReturn(false).when(activity).isVisible(); 1850 rootTask.onSizeCompatActivityChanged(); 1851 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1852 verify(organizer).onTaskInfoChanged(infoCaptor.capture()); 1853 info = infoCaptor.getValue(); 1854 assertEquals(rootTask.mTaskId, info.taskId); 1855 assertFalse(info.appCompatTaskInfo.isTopActivityInSizeCompat()); 1856 1857 // Ensure task info show non size compat top activity as not in size compat. 1858 clearInvocations(organizer); 1859 doReturn(true).when(activity).isVisible(); 1860 doReturn(false).when(activity).inSizeCompatMode(); 1861 rootTask.onSizeCompatActivityChanged(); 1862 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1863 verify(organizer).onTaskInfoChanged(infoCaptor.capture()); 1864 info = infoCaptor.getValue(); 1865 assertEquals(rootTask.mTaskId, info.taskId); 1866 assertFalse(info.appCompatTaskInfo.isTopActivityInSizeCompat()); 1867 } 1868 1869 @Test testStartTasksInTransaction()1870 public void testStartTasksInTransaction() { 1871 WindowContainerTransaction wct = new WindowContainerTransaction(); 1872 ActivityOptions testOptions = ActivityOptions.makeBasic(); 1873 testOptions.setTransientLaunch(); 1874 wct.startTask(1, null /* options */); 1875 wct.startTask(2, testOptions.toBundle()); 1876 spyOn(mWm.mAtmService.mTaskSupervisor); 1877 doReturn(START_CANCELED).when(mWm.mAtmService.mTaskSupervisor).startActivityFromRecents( 1878 anyInt(), anyInt(), anyInt(), any()); 1879 clearInvocations(mWm.mAtmService); 1880 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1881 1882 verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents( 1883 anyInt(), anyInt(), eq(1), any()); 1884 1885 final ArgumentCaptor<SafeActivityOptions> optionsCaptor = 1886 ArgumentCaptor.forClass(SafeActivityOptions.class); 1887 verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents( 1888 anyInt(), anyInt(), eq(2), optionsCaptor.capture()); 1889 assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch()); 1890 } 1891 1892 @SuppressWarnings("GuardedBy") 1893 @Test 1894 @RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2) testResumeTopsWhenLeavingPinned()1895 public void testResumeTopsWhenLeavingPinned() { 1896 final ActivityRecord home = new ActivityBuilder(mAtm).setTask( 1897 mRootWindowContainer.getDefaultTaskDisplayArea().getRootHomeTask()).build(); 1898 final Task homeTask = home.getTask(); 1899 final ActivityRecord pipActivity = makePipableActivity(); 1900 1901 final WindowContainerTransaction t = new WindowContainerTransaction(); 1902 t.setWindowingMode(pipActivity.getTask().mRemoteToken.toWindowContainerToken(), 1903 WINDOWING_MODE_PINNED); 1904 clearInvocations(homeTask); 1905 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 1906 if (WindowOrganizerController.shouldApplyLifecycleEffectOnPipChange()) { 1907 verify(homeTask).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); 1908 } else { 1909 verify(homeTask, never()).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); 1910 } 1911 1912 // Undo the effect of legacy logic in RootWindowContainer#moveActivityToPinnedRootTask. 1913 if (pipActivity.mWaitForEnteringPinnedMode) { 1914 pipActivity.mWaitForEnteringPinnedMode = false; 1915 pipActivity.setWindowingMode(WINDOWING_MODE_UNDEFINED); 1916 } 1917 assertFalse(pipActivity.isFocusable()); 1918 1919 // The token for the PIP root task may have changed when the task entered PIP mode, so do 1920 // not reuse the one from above. 1921 final Task pipTask = pipActivity.getTask(); 1922 final WindowContainerToken newToken = pipTask.mRemoteToken.toWindowContainerToken(); 1923 t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN); 1924 clearInvocations(pipTask); 1925 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 1926 assertTrue(pipActivity.isFocusable()); 1927 verify(pipTask).resumeTopActivityUncheckedLocked(any(), any(), anyBoolean()); 1928 } 1929 1930 @Test testSetAlwaysOnTop()1931 public void testSetAlwaysOnTop() { 1932 final Task rootTask = new TaskBuilder(mSupervisor) 1933 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 1934 testSetAlwaysOnTop(rootTask); 1935 1936 final DisplayArea displayArea = mDisplayContent.getDefaultTaskDisplayArea(); 1937 displayArea.setWindowingMode(WINDOWING_MODE_FREEFORM); 1938 testSetAlwaysOnTop(displayArea); 1939 } 1940 testSetAlwaysOnTop(WindowContainer wc)1941 private void testSetAlwaysOnTop(WindowContainer wc) { 1942 final WindowContainerTransaction t = new WindowContainerTransaction(); 1943 t.setAlwaysOnTop(wc.mRemoteToken.toWindowContainerToken(), true); 1944 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 1945 assertTrue(wc.isAlwaysOnTop()); 1946 1947 t.setAlwaysOnTop(wc.mRemoteToken.toWindowContainerToken(), false); 1948 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 1949 assertFalse(wc.isAlwaysOnTop()); 1950 } 1951 createActivityRecordAndDispatchPendingEvents(Task task)1952 private ActivityRecord createActivityRecordAndDispatchPendingEvents(Task task) { 1953 final ActivityRecord record = createActivityRecord(task); 1954 // Flush EVENT_APPEARED. 1955 mAtm.mTaskOrganizerController.dispatchPendingEvents(); 1956 return record; 1957 } 1958 1959 /** 1960 * Verifies that task vanished is called for a specific task. 1961 */ assertTaskVanished(ITaskOrganizer organizer, boolean expectVanished, Task... tasks)1962 private void assertTaskVanished(ITaskOrganizer organizer, boolean expectVanished, Task... tasks) 1963 throws RemoteException { 1964 ArgumentCaptor<RunningTaskInfo> arg = ArgumentCaptor.forClass(RunningTaskInfo.class); 1965 verify(organizer, atLeastOnce()).onTaskVanished(arg.capture()); 1966 List<RunningTaskInfo> taskInfos = arg.getAllValues(); 1967 1968 HashSet<Integer> vanishedTaskIds = new HashSet<>(); 1969 for (int i = 0; i < taskInfos.size(); i++) { 1970 vanishedTaskIds.add(taskInfos.get(i).taskId); 1971 } 1972 HashSet<Integer> taskIds = new HashSet<>(); 1973 for (int i = 0; i < tasks.length; i++) { 1974 taskIds.add(tasks[i].mTaskId); 1975 } 1976 1977 assertTrue(expectVanished 1978 ? vanishedTaskIds.containsAll(taskIds) 1979 : !vanishedTaskIds.removeAll(taskIds)); 1980 } 1981 assertContainsTasks(List<TaskAppearedInfo> taskInfos, Task... expectedTasks)1982 private void assertContainsTasks(List<TaskAppearedInfo> taskInfos, Task... expectedTasks) { 1983 HashSet<Integer> taskIds = new HashSet<>(); 1984 for (int i = 0; i < taskInfos.size(); i++) { 1985 taskIds.add(taskInfos.get(i).getTaskInfo().taskId); 1986 } 1987 for (int i = 0; i < expectedTasks.length; i++) { 1988 assertTrue(taskIds.contains(expectedTasks[i].mTaskId)); 1989 } 1990 } 1991 1992 @NonNull createTaskFragmentOrganizer( @onNull WindowContainerTransaction t, boolean isSystemOrganizer)1993 private TaskFragmentOrganizer createTaskFragmentOrganizer( 1994 @NonNull WindowContainerTransaction t, boolean isSystemOrganizer) { 1995 final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 1996 final ITaskFragmentOrganizer organizerInterface = 1997 ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); 1998 registerTaskFragmentOrganizer( 1999 ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()), 2000 isSystemOrganizer); 2001 t.setTaskFragmentOrganizer(organizerInterface); 2002 2003 return organizer; 2004 } 2005 } 2006