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.app.ActivityManager.START_CANCELED; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 27 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 29 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 30 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 31 import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; 32 import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; 33 import static android.view.InsetsState.ITYPE_TOP_GENERIC_OVERLAY; 34 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 35 36 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 37 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 38 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; 40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; 42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; 44 import static com.android.server.wm.ActivityRecord.State.RESUMED; 45 import static com.android.server.wm.BLASTSyncEngine.METHOD_BLAST; 46 import static com.android.server.wm.WindowContainer.POSITION_TOP; 47 import static com.android.server.wm.WindowContainer.SYNC_STATE_READY; 48 import static com.android.server.wm.WindowState.BLAST_TIMEOUT_DURATION; 49 50 import static com.google.common.truth.Truth.assertThat; 51 52 import static org.junit.Assert.assertEquals; 53 import static org.junit.Assert.assertFalse; 54 import static org.junit.Assert.assertNotNull; 55 import static org.junit.Assert.assertTrue; 56 import static org.mockito.ArgumentMatchers.any; 57 import static org.mockito.ArgumentMatchers.anyBoolean; 58 import static org.mockito.ArgumentMatchers.anyInt; 59 import static org.mockito.ArgumentMatchers.eq; 60 import static org.mockito.Mockito.atLeastOnce; 61 import static org.mockito.Mockito.clearInvocations; 62 63 import android.app.ActivityManager; 64 import android.app.ActivityManager.RunningTaskInfo; 65 import android.app.ActivityOptions; 66 import android.app.ActivityTaskManager.RootTaskInfo; 67 import android.app.IRequestFinishCallback; 68 import android.app.PictureInPictureParams; 69 import android.content.pm.ActivityInfo; 70 import android.content.pm.ParceledListSlice; 71 import android.content.res.Configuration; 72 import android.graphics.Rect; 73 import android.os.Binder; 74 import android.os.IBinder; 75 import android.os.RemoteException; 76 import android.platform.test.annotations.Presubmit; 77 import android.util.ArrayMap; 78 import android.util.Rational; 79 import android.view.Display; 80 import android.view.SurfaceControl; 81 import android.window.ITaskOrganizer; 82 import android.window.IWindowContainerTransactionCallback; 83 import android.window.StartingWindowInfo; 84 import android.window.StartingWindowRemovalInfo; 85 import android.window.TaskAppearedInfo; 86 import android.window.WindowContainerToken; 87 import android.window.WindowContainerTransaction; 88 89 import androidx.test.filters.SmallTest; 90 91 import com.android.server.wm.TaskOrganizerController.PendingTaskEvent; 92 93 import org.junit.Before; 94 import org.junit.Test; 95 import org.junit.runner.RunWith; 96 import org.mockito.ArgumentCaptor; 97 98 import java.util.ArrayList; 99 import java.util.HashSet; 100 import java.util.List; 101 102 /** 103 * Test class for {@link ITaskOrganizer} and {@link android.window.ITaskOrganizerController}. 104 * 105 * Build/Install/Run: 106 * atest WmTests:WindowOrganizerTests 107 */ 108 @SmallTest 109 @Presubmit 110 @RunWith(WindowTestRunner.class) 111 public class WindowOrganizerTests extends WindowTestsBase { 112 createMockOrganizer()113 private ITaskOrganizer createMockOrganizer() { 114 final ITaskOrganizer organizer = mock(ITaskOrganizer.class); 115 when(organizer.asBinder()).thenReturn(new Binder()); 116 return organizer; 117 } 118 registerMockOrganizer(ArrayList<TaskAppearedInfo> existingTasks)119 private ITaskOrganizer registerMockOrganizer(ArrayList<TaskAppearedInfo> existingTasks) { 120 final ITaskOrganizer organizer = createMockOrganizer(); 121 ParceledListSlice<TaskAppearedInfo> tasks = 122 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(organizer); 123 if (existingTasks != null) { 124 existingTasks.addAll(tasks.getList()); 125 } 126 return organizer; 127 } 128 registerMockOrganizer()129 private ITaskOrganizer registerMockOrganizer() { 130 return registerMockOrganizer(null); 131 } 132 createTask(Task rootTask, boolean fakeDraw)133 Task createTask(Task rootTask, boolean fakeDraw) { 134 final Task task = createTaskInRootTask(rootTask, 0); 135 136 if (fakeDraw) { 137 task.setHasBeenVisible(true); 138 } 139 return task; 140 } 141 createTask(Task rootTask)142 Task createTask(Task rootTask) { 143 // Fake draw notifications for most of our tests. 144 return createTask(rootTask, true); 145 } 146 createRootTask()147 Task createRootTask() { 148 return createTask(mDisplayContent); 149 } 150 151 @Before setUp()152 public void setUp() { 153 // We defer callbacks since we need to adjust task surface visibility, but for these tests, 154 // just run the callbacks synchronously 155 mWm.mAtmService.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer((r) -> r.run()); 156 } 157 158 @Test testAppearVanish()159 public void testAppearVanish() throws RemoteException { 160 final ITaskOrganizer organizer = registerMockOrganizer(); 161 final Task rootTask = createRootTask(); 162 final Task task = createTask(rootTask); 163 // Ensure events dispatch to organizer. 164 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 165 166 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 167 168 rootTask.removeImmediately(); 169 // Ensure events dispatch to organizer. 170 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 171 verify(organizer).onTaskVanished(any()); 172 } 173 174 @Test testAppearWaitsForVisibility()175 public void testAppearWaitsForVisibility() throws RemoteException { 176 final ITaskOrganizer organizer = registerMockOrganizer(); 177 final Task rootTask = createRootTask(); 178 final Task task = createTask(rootTask, false); 179 // Ensure events dispatch to organizer. 180 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 181 182 verify(organizer, never()) 183 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 184 rootTask.setHasBeenVisible(true); 185 // Ensure events dispatch to organizer. 186 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 187 assertTrue(rootTask.getHasBeenVisible()); 188 189 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 190 191 rootTask.removeImmediately(); 192 // Ensure events dispatch to organizer. 193 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 194 verify(organizer).onTaskVanished(any()); 195 } 196 197 @Test testNoVanishedIfNoAppear()198 public void testNoVanishedIfNoAppear() throws RemoteException { 199 final ITaskOrganizer organizer = registerMockOrganizer(); 200 final Task rootTask = createRootTask(); 201 final Task task = createTask(rootTask, false /* hasBeenVisible */); 202 203 // In this test we skip making the Task visible, and verify 204 // that even though a TaskOrganizer is set remove doesn't emit 205 // a vanish callback, because we never emitted appear. 206 rootTask.setTaskOrganizer(organizer); 207 verify(organizer, never()) 208 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 209 rootTask.removeImmediately(); 210 verify(organizer, never()).onTaskVanished(any()); 211 } 212 213 @Test testTaskNoDraw()214 public void testTaskNoDraw() throws RemoteException { 215 final ITaskOrganizer organizer = registerMockOrganizer(); 216 final Task rootTask = createRootTask(); 217 final Task task = createTask(rootTask, false /* fakeDraw */); 218 // Ensure events dispatch to organizer. 219 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 220 221 verify(organizer, never()) 222 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 223 assertTrue(rootTask.isOrganized()); 224 225 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer); 226 // Ensure events dispatch to organizer. 227 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 228 verify(organizer, times(0)).onTaskVanished(any()); 229 assertFalse(rootTask.isOrganized()); 230 } 231 232 @Test testClearOrganizer()233 public void testClearOrganizer() throws RemoteException { 234 final ITaskOrganizer organizer = registerMockOrganizer(); 235 final Task rootTask = createRootTask(); 236 final Task task = createTask(rootTask); 237 // Ensure events dispatch to organizer. 238 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 239 240 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 241 assertTrue(rootTask.isOrganized()); 242 243 rootTask.setTaskOrganizer(null); 244 // Ensure events dispatch to organizer. 245 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 246 247 verify(organizer).onTaskVanished(any()); 248 assertFalse(rootTask.isOrganized()); 249 } 250 251 @Test testRemoveWithOrganizerRemovesTask()252 public void testRemoveWithOrganizerRemovesTask() throws RemoteException { 253 final ITaskOrganizer organizer = registerMockOrganizer(); 254 final Task rootTask = createRootTask(); 255 final Task task = createTask(rootTask); 256 rootTask.mRemoveWithTaskOrganizer = true; 257 258 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 259 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 260 assertTrue(rootTask.isOrganized()); 261 262 spyOn(mWm.mAtmService); 263 rootTask.setTaskOrganizer(null); 264 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 265 266 verify(mWm.mAtmService).removeTask(eq(rootTask.mTaskId)); 267 } 268 269 @Test testNoRemoveWithOrganizerNoRemoveTask()270 public void testNoRemoveWithOrganizerNoRemoveTask() throws RemoteException { 271 final ITaskOrganizer organizer = registerMockOrganizer(); 272 final Task rootTask = createRootTask(); 273 final Task task = createTask(rootTask); 274 rootTask.mRemoveWithTaskOrganizer = false; 275 276 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 277 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 278 assertTrue(rootTask.isOrganized()); 279 280 spyOn(mWm.mAtmService); 281 rootTask.setTaskOrganizer(null); 282 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 283 284 verify(mWm.mAtmService, never()).removeTask(eq(rootTask.mTaskId)); 285 } 286 287 @Test testUnregisterOrganizer()288 public void testUnregisterOrganizer() throws RemoteException { 289 final ITaskOrganizer organizer = registerMockOrganizer(); 290 final Task rootTask = createRootTask(); 291 final Task task = createTask(rootTask); 292 // Ensure events dispatch to organizer. 293 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 294 295 verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 296 assertTrue(rootTask.isOrganized()); 297 298 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer); 299 // Ensure events dispatch to organizer. 300 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 301 302 verify(organizer, times(0)).onTaskVanished(any()); 303 assertFalse(rootTask.isOrganized()); 304 } 305 306 @Test testUnregisterOrganizerReturnsRegistrationToPrevious()307 public void testUnregisterOrganizerReturnsRegistrationToPrevious() throws RemoteException { 308 final Task rootTask = createRootTask(); 309 final Task task = createTask(rootTask); 310 final Task rootTask2 = createRootTask(); 311 final Task task2 = createTask(rootTask2); 312 final Task rootTask3 = createRootTask(); 313 final Task task3 = createTask(rootTask3); 314 final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 315 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 316 // Ensure events dispatch to organizer. 317 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 318 319 // verify that tasks are returned and taskAppeared is not called 320 assertContainsTasks(existingTasks, rootTask, rootTask2, rootTask3); 321 verify(organizer, times(0)).onTaskAppeared(any(RunningTaskInfo.class), 322 any(SurfaceControl.class)); 323 verify(organizer, times(0)).onTaskVanished(any()); 324 assertTrue(rootTask.isOrganized()); 325 326 // Now we replace the registration and verify the new organizer receives existing tasks 327 final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>(); 328 final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2); 329 // Ensure events dispatch to organizer. 330 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 331 assertContainsTasks(existingTasks2, rootTask, rootTask2, rootTask3); 332 verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class), 333 any(SurfaceControl.class)); 334 verify(organizer2, times(0)).onTaskVanished(any()); 335 // Removed tasks from the original organizer 336 assertTaskVanished(organizer, true /* expectVanished */, rootTask, rootTask2, rootTask3); 337 assertTrue(rootTask2.isOrganized()); 338 339 // Now we unregister the second one, the first one should automatically be reregistered 340 // so we verify that it's now seeing changes. 341 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2); 342 // Ensure events dispatch to organizer. 343 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 344 verify(organizer, times(3)) 345 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 346 verify(organizer2, times(0)).onTaskVanished(any()); 347 } 348 349 @Test testUnregisterOrganizer_removesTasksCreatedByIt()350 public void testUnregisterOrganizer_removesTasksCreatedByIt() throws RemoteException { 351 final Task rootTask = createRootTask(); 352 final Task task = createTask(rootTask); 353 final Task rootTask2 = createRootTask(); 354 rootTask2.mCreatedByOrganizer = true; 355 final Task task2 = createTask(rootTask2); 356 final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 357 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 358 // Ensure events dispatch to organizer. 359 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 360 361 // verify that tasks are returned and taskAppeared is called only for rootTask2 since it 362 // is the one created by this organizer. 363 assertContainsTasks(existingTasks, rootTask); 364 verify(organizer, times(1)).onTaskAppeared(any(RunningTaskInfo.class), 365 any(SurfaceControl.class)); 366 verify(organizer, times(0)).onTaskVanished(any()); 367 assertTrue(rootTask.isOrganized()); 368 369 // Now we replace the registration and verify the new organizer receives existing tasks 370 final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>(); 371 final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2); 372 // Ensure events dispatch to organizer. 373 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 374 assertContainsTasks(existingTasks2, rootTask); 375 verify(organizer2, never()).onTaskAppeared(any(RunningTaskInfo.class), 376 any(SurfaceControl.class)); 377 verify(organizer2, times(0)).onTaskVanished(any()); 378 // The non-CreatedByOrganizer task is removed from the original organizer. 379 assertTaskVanished(organizer, true /* expectVanished */, rootTask); 380 assertEquals(organizer2, rootTask.mTaskOrganizer); 381 // The CreatedByOrganizer task should be still organized by the original organizer. 382 assertEquals(organizer, rootTask2.mTaskOrganizer); 383 384 clearInvocations(organizer); 385 // Now we unregister the second one, the first one should automatically be reregistered 386 // so we verify that it's now seeing changes. 387 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2); 388 // Ensure events dispatch to organizer. 389 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 390 391 verify(organizer, times(2)) 392 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 393 394 // Unregister the first one. The CreatedByOrganizer task created by it must be removed. 395 mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer); 396 assertFalse(rootTask2.isAttached()); 397 assertFalse(task2.isAttached()); 398 // Normal task should keep. 399 assertTrue(task.isAttached()); 400 verify(organizer2, times(0)).onTaskVanished(any()); 401 } 402 403 @Test testOrganizerDeathReturnsRegistrationToPrevious()404 public void testOrganizerDeathReturnsRegistrationToPrevious() throws RemoteException { 405 final Task rootTask = createRootTask(); 406 final Task task = createTask(rootTask); 407 final Task rootTask2 = createRootTask(); 408 final Task task2 = createTask(rootTask2); 409 final Task rootTask3 = createRootTask(); 410 final Task task3 = createTask(rootTask3); 411 final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 412 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 413 // Ensure events dispatch to organizer. 414 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 415 416 // verify that tasks are returned and taskAppeared is not called 417 assertContainsTasks(existingTasks, rootTask, rootTask2, rootTask3); 418 verify(organizer, times(0)).onTaskAppeared(any(RunningTaskInfo.class), 419 any(SurfaceControl.class)); 420 verify(organizer, times(0)).onTaskVanished(any()); 421 assertTrue(rootTask.isOrganized()); 422 423 // Now we replace the registration and verify the new organizer receives existing tasks 424 final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>(); 425 final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2); 426 // Ensure events dispatch to organizer. 427 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 428 assertContainsTasks(existingTasks2, rootTask, rootTask2, rootTask3); 429 verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class), 430 any(SurfaceControl.class)); 431 verify(organizer2, times(0)).onTaskVanished(any()); 432 // Removed tasks from the original organizer 433 assertTaskVanished(organizer, true /* expectVanished */, rootTask, rootTask2, rootTask3); 434 assertTrue(rootTask2.isOrganized()); 435 436 // Trigger binderDied for second one, the first one should automatically be reregistered 437 // so we verify that it's now seeing changes. 438 mWm.mAtmService.mTaskOrganizerController.getTaskOrganizerState(organizer2.asBinder()) 439 .getDeathRecipient().binderDied(); 440 441 // Ensure events dispatch to organizer. 442 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 443 verify(organizer, times(3)) 444 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 445 verify(organizer2, times(0)).onTaskVanished(any()); 446 } 447 448 @Test testRegisterTaskOrganizerWithExistingTasks()449 public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException { 450 final Task rootTask = createRootTask(); 451 final Task task = createTask(rootTask); 452 final Task rootTask2 = createRootTask(); 453 final Task task2 = createTask(rootTask2); 454 ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 455 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 456 assertContainsTasks(existingTasks, rootTask, rootTask2); 457 458 // Verify we don't get onTaskAppeared if we are returned the tasks 459 verify(organizer, never()) 460 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 461 } 462 463 @Test testRegisterTaskOrganizerWithExistingTasks_noSurfaceControl()464 public void testRegisterTaskOrganizerWithExistingTasks_noSurfaceControl() 465 throws RemoteException { 466 final Task rootTask = createRootTask(); 467 final Task task = createTask(rootTask); 468 final Task rootTask2 = createRootTask(); 469 final Task task2 = createTask(rootTask2); 470 rootTask2.setSurfaceControl(null); 471 ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>(); 472 final ITaskOrganizer organizer = registerMockOrganizer(existingTasks); 473 assertContainsTasks(existingTasks, rootTask); 474 475 // Verify we don't get onTaskAppeared if we are returned the tasks 476 verify(organizer, never()) 477 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 478 } 479 480 @Test testTaskTransaction()481 public void testTaskTransaction() { 482 removeGlobalMinSizeRestriction(); 483 final Task rootTask = new TaskBuilder(mSupervisor) 484 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 485 final Task task = rootTask.getTopMostTask(); 486 testTransaction(task); 487 } 488 489 @Test testRootTaskTransaction()490 public void testRootTaskTransaction() { 491 removeGlobalMinSizeRestriction(); 492 final Task rootTask = new TaskBuilder(mSupervisor) 493 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 494 RootTaskInfo info = 495 mWm.mAtmService.getRootTaskInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD); 496 assertEquals(rootTask.mRemoteToken.toWindowContainerToken(), info.token); 497 testTransaction(rootTask); 498 } 499 500 @Test testDisplayAreaTransaction()501 public void testDisplayAreaTransaction() { 502 removeGlobalMinSizeRestriction(); 503 final DisplayArea displayArea = mDisplayContent.getDefaultTaskDisplayArea(); 504 testTransaction(displayArea); 505 } 506 testTransaction(WindowContainer wc)507 private void testTransaction(WindowContainer wc) { 508 WindowContainerTransaction t = new WindowContainerTransaction(); 509 Rect newBounds = new Rect(10, 10, 100, 100); 510 t.setBounds(wc.mRemoteToken.toWindowContainerToken(), new Rect(10, 10, 100, 100)); 511 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 512 assertEquals(newBounds, wc.getBounds()); 513 } 514 515 @Test testSetWindowingMode()516 public void testSetWindowingMode() { 517 final Task rootTask = new TaskBuilder(mSupervisor) 518 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 519 testSetWindowingMode(rootTask); 520 521 final DisplayArea displayArea = mDisplayContent.getDefaultTaskDisplayArea(); 522 displayArea.setWindowingMode(WINDOWING_MODE_FREEFORM); 523 testSetWindowingMode(displayArea); 524 } 525 testSetWindowingMode(WindowContainer wc)526 private void testSetWindowingMode(WindowContainer wc) { 527 final WindowContainerTransaction t = new WindowContainerTransaction(); 528 t.setWindowingMode(wc.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_FULLSCREEN); 529 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 530 assertEquals(WINDOWING_MODE_FULLSCREEN, wc.getWindowingMode()); 531 } 532 533 @Test testSetActivityWindowingMode()534 public void testSetActivityWindowingMode() { 535 final ActivityRecord record = makePipableActivity(); 536 final Task rootTask = record.getRootTask(); 537 final WindowContainerTransaction t = new WindowContainerTransaction(); 538 539 t.setWindowingMode(rootTask.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_PINNED); 540 t.setActivityWindowingMode( 541 rootTask.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_FULLSCREEN); 542 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 543 544 assertEquals(WINDOWING_MODE_FULLSCREEN, record.getWindowingMode()); 545 // Get the root task from the PIP activity record again, since the PIP root task may have 546 // changed when the activity entered PIP mode. 547 final Task pipRootTask = record.getRootTask(); 548 assertEquals(WINDOWING_MODE_PINNED, pipRootTask.getWindowingMode()); 549 } 550 551 @Test testContainerFocusableChanges()552 public void testContainerFocusableChanges() { 553 removeGlobalMinSizeRestriction(); 554 final Task rootTask = new TaskBuilder(mSupervisor) 555 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 556 final Task task = rootTask.getTopMostTask(); 557 WindowContainerTransaction t = new WindowContainerTransaction(); 558 assertTrue(task.isFocusable()); 559 t.setFocusable(rootTask.mRemoteToken.toWindowContainerToken(), false); 560 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 561 assertFalse(task.isFocusable()); 562 t.setFocusable(rootTask.mRemoteToken.toWindowContainerToken(), true); 563 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 564 assertTrue(task.isFocusable()); 565 } 566 567 @Test testContainerHiddenChanges()568 public void testContainerHiddenChanges() { 569 removeGlobalMinSizeRestriction(); 570 final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) 571 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 572 WindowContainerTransaction t = new WindowContainerTransaction(); 573 assertTrue(rootTask.shouldBeVisible(null)); 574 t.setHidden(rootTask.mRemoteToken.toWindowContainerToken(), true); 575 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 576 assertFalse(rootTask.shouldBeVisible(null)); 577 t.setHidden(rootTask.mRemoteToken.toWindowContainerToken(), false); 578 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 579 assertTrue(rootTask.shouldBeVisible(null)); 580 } 581 582 @Test testContainerTranslucentChanges()583 public void testContainerTranslucentChanges() { 584 removeGlobalMinSizeRestriction(); 585 final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true) 586 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build(); 587 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 588 WindowContainerTransaction t = new WindowContainerTransaction(); 589 assertFalse(rootTask.isTranslucent(activity)); 590 t.setForceTranslucent(rootTask.mRemoteToken.toWindowContainerToken(), true); 591 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 592 assertTrue(rootTask.isTranslucent(activity)); 593 t.setForceTranslucent(rootTask.mRemoteToken.toWindowContainerToken(), false); 594 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 595 assertFalse(rootTask.isTranslucent(activity)); 596 } 597 598 @Test testSetIgnoreOrientationRequest_taskDisplayArea()599 public void testSetIgnoreOrientationRequest_taskDisplayArea() { 600 removeGlobalMinSizeRestriction(); 601 final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); 602 final Task rootTask = taskDisplayArea.createRootTask( 603 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 604 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 605 taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 606 mDisplayContent.setFocusedApp(activity); 607 activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); 608 609 // TDA returns UNSET when ignoreOrientationRequest == true 610 // DC is UNSPECIFIED when child returns UNSET 611 assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET); 612 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED); 613 614 WindowContainerTransaction t = new WindowContainerTransaction(); 615 t.setIgnoreOrientationRequest( 616 taskDisplayArea.mRemoteToken.toWindowContainerToken(), 617 false /* ignoreOrientationRequest */); 618 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 619 620 // TDA returns app request orientation when ignoreOrientationRequest == false 621 // DC uses the same as TDA returns when it is not UNSET. 622 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); 623 assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); 624 625 t.setIgnoreOrientationRequest( 626 taskDisplayArea.mRemoteToken.toWindowContainerToken(), 627 true /* ignoreOrientationRequest */); 628 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 629 630 // TDA returns UNSET when ignoreOrientationRequest == true 631 // DC is UNSPECIFIED when child returns UNSET 632 assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET); 633 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED); 634 } 635 636 @Test testSetIgnoreOrientationRequest_displayContent()637 public void testSetIgnoreOrientationRequest_displayContent() { 638 removeGlobalMinSizeRestriction(); 639 final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); 640 final Task rootTask = taskDisplayArea.createRootTask( 641 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); 642 final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build(); 643 mDisplayContent.setFocusedApp(activity); 644 activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); 645 646 // DC uses the orientation request from app 647 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); 648 649 WindowContainerTransaction t = new WindowContainerTransaction(); 650 t.setIgnoreOrientationRequest( 651 mDisplayContent.mRemoteToken.toWindowContainerToken(), 652 true /* ignoreOrientationRequest */); 653 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 654 655 // DC returns UNSPECIFIED when ignoreOrientationRequest == true 656 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED); 657 658 t.setIgnoreOrientationRequest( 659 mDisplayContent.mRemoteToken.toWindowContainerToken(), 660 false /* ignoreOrientationRequest */); 661 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 662 663 // DC uses the orientation request from app after mIgnoreOrientationRequest is set to false 664 assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); 665 } 666 667 @Test testOverrideConfigSize()668 public void testOverrideConfigSize() { 669 removeGlobalMinSizeRestriction(); 670 final Task rootTask = new TaskBuilder(mSupervisor) 671 .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); 672 final Task task = rootTask.getTopMostTask(); 673 WindowContainerTransaction t = new WindowContainerTransaction(); 674 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 675 final int origScreenWDp = task.getConfiguration().screenHeightDp; 676 final int origScreenHDp = task.getConfiguration().screenHeightDp; 677 t = new WindowContainerTransaction(); 678 // verify that setting config overrides on parent restricts children. 679 t.setScreenSizeDp(rootTask.mRemoteToken 680 .toWindowContainerToken(), origScreenWDp, origScreenHDp / 2); 681 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 682 assertEquals(origScreenHDp / 2, task.getConfiguration().screenHeightDp); 683 t = new WindowContainerTransaction(); 684 t.setScreenSizeDp(rootTask.mRemoteToken.toWindowContainerToken(), SCREEN_WIDTH_DP_UNDEFINED, 685 SCREEN_HEIGHT_DP_UNDEFINED); 686 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 687 assertEquals(origScreenHDp, task.getConfiguration().screenHeightDp); 688 } 689 690 @Test testCreateDeleteRootTasks()691 public void testCreateDeleteRootTasks() { 692 DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY); 693 694 Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 695 dc, WINDOWING_MODE_FULLSCREEN, null); 696 RunningTaskInfo info1 = task1.getTaskInfo(); 697 assertEquals(WINDOWING_MODE_FULLSCREEN, 698 info1.configuration.windowConfiguration.getWindowingMode()); 699 assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType); 700 701 Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 702 dc, WINDOWING_MODE_MULTI_WINDOW, null); 703 RunningTaskInfo info2 = task2.getTaskInfo(); 704 assertEquals(WINDOWING_MODE_MULTI_WINDOW, 705 info2.configuration.windowConfiguration.getWindowingMode()); 706 assertEquals(ACTIVITY_TYPE_UNDEFINED, info2.topActivityType); 707 708 List<Task> infos = getTasksCreatedByOrganizer(dc); 709 assertEquals(2, infos.size()); 710 711 assertTrue(mWm.mAtmService.mTaskOrganizerController.deleteRootTask(info1.token)); 712 infos = getTasksCreatedByOrganizer(dc); 713 assertEquals(1, infos.size()); 714 assertEquals(WINDOWING_MODE_MULTI_WINDOW, infos.get(0).getWindowingMode()); 715 } 716 717 @Test testSetAdjacentLaunchRoot()718 public void testSetAdjacentLaunchRoot() { 719 DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY); 720 721 final Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 722 dc, WINDOWING_MODE_MULTI_WINDOW, null); 723 final RunningTaskInfo info1 = task1.getTaskInfo(); 724 final Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 725 dc, WINDOWING_MODE_MULTI_WINDOW, null); 726 final RunningTaskInfo info2 = task2.getTaskInfo(); 727 728 WindowContainerTransaction wct = new WindowContainerTransaction(); 729 wct.setAdjacentRoots(info1.token, info2.token); 730 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 731 assertEquals(task1.getAdjacentTaskFragment(), task2); 732 assertEquals(task2.getAdjacentTaskFragment(), task1); 733 734 wct = new WindowContainerTransaction(); 735 wct.setLaunchAdjacentFlagRoot(info1.token); 736 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 737 assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, task1); 738 739 task1.setAdjacentTaskFragment(null); 740 task2.setAdjacentTaskFragment(null); 741 wct = new WindowContainerTransaction(); 742 wct.clearLaunchAdjacentFlagRoot(info1.token); 743 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 744 assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, null); 745 } 746 747 @Test testTileAddRemoveChild()748 public void testTileAddRemoveChild() { 749 final StubOrganizer listener = new StubOrganizer(); 750 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); 751 Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask( 752 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 753 RunningTaskInfo info1 = task.getTaskInfo(); 754 755 final Task rootTask = createTask( 756 mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD); 757 assertEquals(mDisplayContent.getWindowingMode(), rootTask.getWindowingMode()); 758 WindowContainerTransaction wct = new WindowContainerTransaction(); 759 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */); 760 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 761 assertEquals(info1.configuration.windowConfiguration.getWindowingMode(), 762 rootTask.getWindowingMode()); 763 764 // Info should reflect new membership 765 List<Task> infos = getTasksCreatedByOrganizer(mDisplayContent); 766 info1 = infos.get(0).getTaskInfo(); 767 assertEquals(ACTIVITY_TYPE_STANDARD, info1.topActivityType); 768 769 // Children inherit configuration 770 Rect newSize = new Rect(10, 10, 300, 300); 771 Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask(); 772 Configuration c = new Configuration(task1.getRequestedOverrideConfiguration()); 773 c.windowConfiguration.setBounds(newSize); 774 doNothing().when(rootTask).adjustForMinimalTaskDimensions(any(), any(), any()); 775 task1.onRequestedOverrideConfigurationChanged(c); 776 assertEquals(newSize, rootTask.getBounds()); 777 778 wct = new WindowContainerTransaction(); 779 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), null, true /* onTop */); 780 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 781 assertEquals(mDisplayContent.getWindowingMode(), rootTask.getWindowingMode()); 782 infos = getTasksCreatedByOrganizer(mDisplayContent); 783 info1 = infos.get(0).getTaskInfo(); 784 assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType); 785 } 786 787 @Test testAddRectInsetsProvider()788 public void testAddRectInsetsProvider() { 789 final Task rootTask = createTask(mDisplayContent); 790 791 final Task navigationBarInsetsReceiverTask = createTaskInRootTask(rootTask, 0); 792 navigationBarInsetsReceiverTask.getConfiguration().windowConfiguration.setBounds(new Rect( 793 0, 200, 1080, 700)); 794 795 final Rect navigationBarInsetsProviderRect = new Rect(0, 0, 1080, 200); 796 797 final WindowContainerTransaction wct = new WindowContainerTransaction(); 798 wct.addRectInsetsProvider(navigationBarInsetsReceiverTask.mRemoteToken 799 .toWindowContainerToken(), navigationBarInsetsProviderRect, 800 new int[]{ITYPE_TOP_GENERIC_OVERLAY}); 801 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 802 803 assertThat(navigationBarInsetsReceiverTask.mLocalInsetsSourceProviders 804 .valueAt(0).getSource().getType()).isEqualTo(ITYPE_TOP_GENERIC_OVERLAY); 805 } 806 807 @Test testRemoveInsetsProvider()808 public void testRemoveInsetsProvider() { 809 final Task rootTask = createTask(mDisplayContent); 810 811 final Task navigationBarInsetsReceiverTask = createTaskInRootTask(rootTask, 0); 812 navigationBarInsetsReceiverTask.getConfiguration().windowConfiguration.setBounds(new Rect( 813 0, 200, 1080, 700)); 814 815 final Rect navigationBarInsetsProviderRect = new Rect(0, 0, 1080, 200); 816 817 final WindowContainerTransaction wct = new WindowContainerTransaction(); 818 wct.addRectInsetsProvider(navigationBarInsetsReceiverTask.mRemoteToken 819 .toWindowContainerToken(), navigationBarInsetsProviderRect, 820 new int[]{ITYPE_TOP_GENERIC_OVERLAY}); 821 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 822 823 final WindowContainerTransaction wct2 = new WindowContainerTransaction(); 824 wct2.removeInsetsProvider(navigationBarInsetsReceiverTask.mRemoteToken 825 .toWindowContainerToken(), new int[]{ITYPE_TOP_GENERIC_OVERLAY}); 826 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct2); 827 828 assertThat(navigationBarInsetsReceiverTask.mLocalInsetsSourceProviders.size()).isEqualTo(0); 829 } 830 831 @UseTestDisplay 832 @Test testTaskInfoCallback()833 public void testTaskInfoCallback() { 834 final ArrayList<RunningTaskInfo> lastReportedTiles = new ArrayList<>(); 835 final boolean[] called = {false}; 836 final StubOrganizer listener = new StubOrganizer() { 837 @Override 838 public void onTaskInfoChanged(RunningTaskInfo info) { 839 lastReportedTiles.add(info); 840 called[0] = true; 841 } 842 }; 843 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); 844 Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask( 845 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 846 RunningTaskInfo info1 = task.getTaskInfo(); 847 // Ensure events dispatch to organizer. 848 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 849 lastReportedTiles.clear(); 850 called[0] = false; 851 852 final Task rootTask = createTask( 853 mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD); 854 Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask(); 855 WindowContainerTransaction wct = new WindowContainerTransaction(); 856 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */); 857 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 858 assertTrue(called[0]); 859 assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType); 860 861 lastReportedTiles.clear(); 862 called[0] = false; 863 final Task rootTask2 = createTask( 864 mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME); 865 wct = new WindowContainerTransaction(); 866 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), 867 info1.token, true /* onTop */); 868 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 869 assertTrue(called[0]); 870 assertEquals(ACTIVITY_TYPE_HOME, lastReportedTiles.get(0).topActivityType); 871 872 lastReportedTiles.clear(); 873 called[0] = false; 874 task1.positionChildAt(POSITION_TOP, rootTask, false /* includingParents */); 875 assertTrue(called[0]); 876 assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType); 877 878 lastReportedTiles.clear(); 879 called[0] = false; 880 wct = new WindowContainerTransaction(); 881 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), 882 null, true /* onTop */); 883 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), 884 null, true /* onTop */); 885 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 886 assertTrue(called[0]); 887 assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType); 888 } 889 890 @UseTestDisplay 891 @Test testHierarchyTransaction()892 public void testHierarchyTransaction() { 893 final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>(); 894 final StubOrganizer listener = new StubOrganizer() { 895 @Override 896 public void onTaskInfoChanged(RunningTaskInfo info) { 897 lastReportedTiles.put(info.token.asBinder(), info); 898 } 899 }; 900 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener); 901 902 Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 903 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 904 RunningTaskInfo info1 = task1.getTaskInfo(); 905 Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( 906 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 907 RunningTaskInfo info2 = task2.getTaskInfo(); 908 // Ensure events dispatch to organizer. 909 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 910 911 final int initialRootTaskCount = mWm.mAtmService.mTaskOrganizerController.getRootTasks( 912 mDisplayContent.mDisplayId, null /* activityTypes */).size(); 913 914 final Task rootTask = createTask( 915 mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD); 916 final Task rootTask2 = createTask( 917 mDisplayContent, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME); 918 919 // Check getRootTasks works 920 List<RunningTaskInfo> roots = mWm.mAtmService.mTaskOrganizerController.getRootTasks( 921 mDisplayContent.mDisplayId, null /* activityTypes */); 922 assertEquals(initialRootTaskCount + 2, roots.size()); 923 924 lastReportedTiles.clear(); 925 WindowContainerTransaction wct = new WindowContainerTransaction(); 926 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), 927 info1.token, true /* onTop */); 928 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), 929 info2.token, true /* onTop */); 930 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 931 assertFalse(lastReportedTiles.isEmpty()); 932 assertEquals(ACTIVITY_TYPE_STANDARD, 933 lastReportedTiles.get(info1.token.asBinder()).topActivityType); 934 assertEquals(ACTIVITY_TYPE_HOME, 935 lastReportedTiles.get(info2.token.asBinder()).topActivityType); 936 937 lastReportedTiles.clear(); 938 wct = new WindowContainerTransaction(); 939 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), 940 info1.token, false /* onTop */); 941 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 942 assertFalse(lastReportedTiles.isEmpty()); 943 // Standard should still be on top of tile 1, so no change there 944 assertFalse(lastReportedTiles.containsKey(info1.token.asBinder())); 945 // But tile 2 has no children, so should become undefined 946 assertEquals(ACTIVITY_TYPE_UNDEFINED, 947 lastReportedTiles.get(info2.token.asBinder()).topActivityType); 948 949 // Check the getChildren call 950 List<RunningTaskInfo> children = 951 mWm.mAtmService.mTaskOrganizerController.getChildTasks(info1.token, 952 null /* activityTypes */); 953 assertEquals(2, children.size()); 954 children = mWm.mAtmService.mTaskOrganizerController.getChildTasks(info2.token, 955 null /* activityTypes */); 956 assertEquals(0, children.size()); 957 958 // Check that getRootTasks doesn't include children of tiles 959 roots = mWm.mAtmService.mTaskOrganizerController.getRootTasks(mDisplayContent.mDisplayId, 960 null /* activityTypes */); 961 assertEquals(initialRootTaskCount, roots.size()); 962 963 lastReportedTiles.clear(); 964 wct = new WindowContainerTransaction(); 965 wct.reorder(rootTask2.mRemoteToken.toWindowContainerToken(), true /* onTop */); 966 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 967 // Home should now be on top. No change occurs in second tile, so not reported 968 assertEquals(1, lastReportedTiles.size()); 969 assertEquals(ACTIVITY_TYPE_HOME, 970 lastReportedTiles.get(info1.token.asBinder()).topActivityType); 971 972 // This just needs to not crash (ie. it should be possible to reparent to display twice) 973 wct = new WindowContainerTransaction(); 974 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */); 975 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 976 wct = new WindowContainerTransaction(); 977 wct.reparent(rootTask2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */); 978 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 979 } 980 getTasksCreatedByOrganizer(DisplayContent dc)981 private List<Task> getTasksCreatedByOrganizer(DisplayContent dc) { 982 final ArrayList<Task> out = new ArrayList<>(); 983 dc.forAllRootTasks(task -> { 984 if (task.mCreatedByOrganizer) { 985 out.add(task); 986 } 987 }); 988 return out; 989 } 990 991 @Test testBLASTCallbackWithActivityChildren()992 public void testBLASTCallbackWithActivityChildren() { 993 final Task rootTaskController1 = createRootTask(); 994 final Task task = createTask(rootTaskController1); 995 final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window"); 996 997 w.mActivityRecord.setVisibleRequested(true); 998 w.mActivityRecord.setVisible(true); 999 1000 BLASTSyncEngine bse = new BLASTSyncEngine(mWm); 1001 1002 BLASTSyncEngine.TransactionReadyListener transactionListener = 1003 mock(BLASTSyncEngine.TransactionReadyListener.class); 1004 1005 int id = bse.startSyncSet(transactionListener, BLAST_TIMEOUT_DURATION, "", METHOD_BLAST); 1006 bse.addToSyncSet(id, task); 1007 bse.setReady(id); 1008 bse.onSurfacePlacement(); 1009 1010 // Even though w is invisible (and thus activity isn't waiting on it), activity will 1011 // continue to wait until it has at-least 1 visible window. 1012 // Since we have a child window we still shouldn't be done. 1013 verify(transactionListener, never()).onTransactionReady(anyInt(), any()); 1014 1015 makeWindowVisible(w); 1016 bse.onSurfacePlacement(); 1017 w.immediatelyNotifyBlastSync(); 1018 bse.onSurfacePlacement(); 1019 1020 verify(transactionListener).onTransactionReady(anyInt(), any()); 1021 } 1022 1023 static class StubOrganizer extends ITaskOrganizer.Stub { 1024 RunningTaskInfo mInfo; 1025 1026 @Override addStartingWindow(StartingWindowInfo info, IBinder appToken)1027 public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { } 1028 @Override removeStartingWindow(StartingWindowRemovalInfo removalInfo)1029 public void removeStartingWindow(StartingWindowRemovalInfo removalInfo) { } 1030 @Override copySplashScreenView(int taskId)1031 public void copySplashScreenView(int taskId) { } 1032 @Override onTaskAppeared(RunningTaskInfo info, SurfaceControl leash)1033 public void onTaskAppeared(RunningTaskInfo info, SurfaceControl leash) { 1034 mInfo = info; 1035 } 1036 @Override onTaskVanished(RunningTaskInfo info)1037 public void onTaskVanished(RunningTaskInfo info) { 1038 } 1039 @Override onTaskInfoChanged(RunningTaskInfo info)1040 public void onTaskInfoChanged(RunningTaskInfo info) { 1041 } 1042 @Override onBackPressedOnTaskRoot(RunningTaskInfo taskInfo)1043 public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { 1044 } 1045 @Override onImeDrawnOnTask(int taskId)1046 public void onImeDrawnOnTask(int taskId) throws RemoteException { 1047 } 1048 @Override onAppSplashScreenViewRemoved(int taskId)1049 public void onAppSplashScreenViewRemoved(int taskId) { 1050 } 1051 }; 1052 makePipableActivity()1053 private ActivityRecord makePipableActivity() { 1054 final ActivityRecord record = createActivityRecordWithParentTask(mDisplayContent, 1055 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); 1056 record.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; 1057 record.setPictureInPictureParams(new PictureInPictureParams.Builder() 1058 .setAutoEnterEnabled(true).build()); 1059 spyOn(record); 1060 doReturn(true).when(record).checkEnterPictureInPictureState(any(), anyBoolean()); 1061 1062 record.getTask().setHasBeenVisible(true); 1063 return record; 1064 } 1065 1066 @Test testEnterPipParams()1067 public void testEnterPipParams() { 1068 final StubOrganizer o = new StubOrganizer(); 1069 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o); 1070 final ActivityRecord record = makePipableActivity(); 1071 1072 final PictureInPictureParams p = new PictureInPictureParams.Builder() 1073 .setAspectRatio(new Rational(1, 2)).build(); 1074 assertTrue(mWm.mAtmService.mActivityClientController.enterPictureInPictureMode( 1075 record.token, p)); 1076 waitUntilHandlersIdle(); 1077 assertNotNull(o.mInfo); 1078 assertNotNull(o.mInfo.pictureInPictureParams); 1079 } 1080 1081 @Test testChangePipParams()1082 public void testChangePipParams() { 1083 class ChangeSavingOrganizer extends StubOrganizer { 1084 RunningTaskInfo mChangedInfo; 1085 @Override 1086 public void onTaskInfoChanged(RunningTaskInfo info) { 1087 mChangedInfo = info; 1088 } 1089 } 1090 ChangeSavingOrganizer o = new ChangeSavingOrganizer(); 1091 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o); 1092 1093 final ActivityRecord record = makePipableActivity(); 1094 final PictureInPictureParams p = new PictureInPictureParams.Builder() 1095 .setAspectRatio(new Rational(1, 2)).build(); 1096 assertTrue(mWm.mAtmService.mActivityClientController.enterPictureInPictureMode( 1097 record.token, p)); 1098 waitUntilHandlersIdle(); 1099 assertNotNull(o.mInfo); 1100 assertNotNull(o.mInfo.pictureInPictureParams); 1101 1102 final PictureInPictureParams p2 = new PictureInPictureParams.Builder() 1103 .setAspectRatio(new Rational(3, 4)).build(); 1104 mWm.mAtmService.mActivityClientController.setPictureInPictureParams(record.token, p2); 1105 waitUntilHandlersIdle(); 1106 // Ensure events dispatch to organizer. 1107 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1108 assertNotNull(o.mChangedInfo); 1109 assertNotNull(o.mChangedInfo.pictureInPictureParams); 1110 final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatio(); 1111 assertEquals(3, ratio.getNumerator()); 1112 assertEquals(4, ratio.getDenominator()); 1113 } 1114 1115 @Test testChangeTaskDescription()1116 public void testChangeTaskDescription() { 1117 class ChangeSavingOrganizer extends StubOrganizer { 1118 RunningTaskInfo mChangedInfo; 1119 @Override 1120 public void onTaskInfoChanged(RunningTaskInfo info) { 1121 mChangedInfo = info; 1122 } 1123 } 1124 ChangeSavingOrganizer o = new ChangeSavingOrganizer(); 1125 mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o); 1126 1127 final Task rootTask = createRootTask(); 1128 final Task task = createTask(rootTask); 1129 final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task); 1130 1131 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1132 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); 1133 waitUntilHandlersIdle(); 1134 assertEquals("TestDescription", o.mChangedInfo.taskDescription.getLabel()); 1135 } 1136 1137 @Test testPreventDuplicateAppear()1138 public void testPreventDuplicateAppear() throws RemoteException { 1139 final ITaskOrganizer organizer = registerMockOrganizer(); 1140 final Task rootTask = createRootTask(); 1141 final Task task = createTask(rootTask, false /* fakeDraw */); 1142 1143 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1144 rootTask.setTaskOrganizer(organizer); 1145 // setHasBeenVisible was already called once by the set-up code. 1146 rootTask.setHasBeenVisible(true); 1147 // Ensure events dispatch to organizer. 1148 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1149 verify(organizer, times(1)) 1150 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 1151 1152 rootTask.setTaskOrganizer(null); 1153 // Ensure events dispatch to organizer. 1154 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1155 verify(organizer, times(1)).onTaskVanished(any()); 1156 rootTask.setTaskOrganizer(organizer); 1157 // Ensure events dispatch to organizer. 1158 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1159 verify(organizer, times(2)) 1160 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class)); 1161 1162 rootTask.removeImmediately(); 1163 // Ensure events dispatch to organizer. 1164 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1165 verify(organizer, times(2)).onTaskVanished(any()); 1166 } 1167 1168 @Test testInterceptBackPressedOnTaskRoot()1169 public void testInterceptBackPressedOnTaskRoot() throws RemoteException { 1170 final ITaskOrganizer organizer = registerMockOrganizer(); 1171 final Task rootTask = createRootTask(); 1172 final Task task = createTask(rootTask); 1173 final ActivityRecord activity = createActivityRecord(rootTask.mDisplayContent, task); 1174 final Task rootTask2 = createRootTask(); 1175 final Task task2 = createTask(rootTask2); 1176 final ActivityRecord activity2 = createActivityRecord(rootTask.mDisplayContent, task2); 1177 1178 assertTrue(rootTask.isOrganized()); 1179 assertTrue(rootTask2.isOrganized()); 1180 1181 // Verify a back pressed does not call the organizer 1182 mWm.mAtmService.mActivityClientController.onBackPressed(activity.token, 1183 new IRequestFinishCallback.Default()); 1184 // Ensure events dispatch to organizer. 1185 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1186 verify(organizer, never()).onBackPressedOnTaskRoot(any()); 1187 1188 // Enable intercepting back 1189 mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot( 1190 rootTask.mRemoteToken.toWindowContainerToken(), true); 1191 1192 // Verify now that the back press does call the organizer 1193 mWm.mAtmService.mActivityClientController.onBackPressed(activity.token, 1194 new IRequestFinishCallback.Default()); 1195 // Ensure events dispatch to organizer. 1196 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1197 verify(organizer, times(1)).onBackPressedOnTaskRoot(any()); 1198 1199 // Disable intercepting back 1200 mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot( 1201 rootTask.mRemoteToken.toWindowContainerToken(), false); 1202 1203 // Verify now that the back press no longer calls the organizer 1204 mWm.mAtmService.mActivityClientController.onBackPressed(activity.token, 1205 new IRequestFinishCallback.Default()); 1206 // Ensure events dispatch to organizer. 1207 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1208 verify(organizer, times(1)).onBackPressedOnTaskRoot(any()); 1209 } 1210 1211 @Test testBLASTCallbackWithWindows()1212 public void testBLASTCallbackWithWindows() throws Exception { 1213 final Task rootTaskController = createRootTask(); 1214 final Task task = createTask(rootTaskController); 1215 final WindowState w1 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 1"); 1216 final WindowState w2 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 2"); 1217 makeWindowVisible(w1); 1218 makeWindowVisible(w2); 1219 1220 IWindowContainerTransactionCallback mockCallback = 1221 mock(IWindowContainerTransactionCallback.class); 1222 int id = mWm.mAtmService.mWindowOrganizerController.startSyncWithOrganizer(mockCallback); 1223 1224 mWm.mAtmService.mWindowOrganizerController.addToSyncSet(id, task); 1225 mWm.mAtmService.mWindowOrganizerController.setSyncReady(id); 1226 1227 // Since we have a window we have to wait for it to draw to finish sync. 1228 verify(mockCallback, never()).onTransactionReady(anyInt(), any()); 1229 assertTrue(w1.useBLASTSync()); 1230 assertTrue(w2.useBLASTSync()); 1231 1232 // Make second (bottom) ready. If we started with the top, since activities fillsParent 1233 // by default, the sync would be considered finished. 1234 w2.immediatelyNotifyBlastSync(); 1235 mWm.mSyncEngine.onSurfacePlacement(); 1236 verify(mockCallback, never()).onTransactionReady(anyInt(), any()); 1237 1238 assertEquals(SYNC_STATE_READY, w2.mSyncState); 1239 // Even though one Window finished drawing, both windows should still be using blast sync 1240 assertTrue(w1.useBLASTSync()); 1241 assertTrue(w2.useBLASTSync()); 1242 1243 // A drawn window can complete the sync state automatically. 1244 w1.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; 1245 mWm.mSyncEngine.onSurfacePlacement(); 1246 verify(mockCallback).onTransactionReady(anyInt(), any()); 1247 assertFalse(w1.useBLASTSync()); 1248 assertFalse(w2.useBLASTSync()); 1249 } 1250 1251 @Test testDisplayAreaHiddenTransaction()1252 public void testDisplayAreaHiddenTransaction() { 1253 removeGlobalMinSizeRestriction(); 1254 1255 WindowContainerTransaction trx = new WindowContainerTransaction(); 1256 1257 TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); 1258 1259 trx.setHidden(taskDisplayArea.mRemoteToken.toWindowContainerToken(), true); 1260 mWm.mAtmService.mWindowOrganizerController.applyTransaction(trx); 1261 1262 taskDisplayArea.forAllTasks(daTask -> { 1263 assertTrue(daTask.isForceHidden()); 1264 }); 1265 1266 trx.setHidden(taskDisplayArea.mRemoteToken.toWindowContainerToken(), false); 1267 mWm.mAtmService.mWindowOrganizerController.applyTransaction(trx); 1268 1269 taskDisplayArea.forAllTasks(daTask -> { 1270 assertFalse(daTask.isForceHidden()); 1271 }); 1272 } 1273 1274 @Test testReparentToOrganizedTask()1275 public void testReparentToOrganizedTask() { 1276 final ITaskOrganizer organizer = registerMockOrganizer(); 1277 Task rootTask = mWm.mAtmService.mTaskOrganizerController.createRootTask( 1278 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 1279 final Task task1 = createRootTask(); 1280 final Task task2 = createTask(rootTask, false /* fakeDraw */); 1281 WindowContainerTransaction wct = new WindowContainerTransaction(); 1282 wct.reparent(task1.mRemoteToken.toWindowContainerToken(), 1283 rootTask.mRemoteToken.toWindowContainerToken(), true /* onTop */); 1284 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1285 assertTrue(task1.isOrganized()); 1286 assertTrue(task2.isOrganized()); 1287 } 1288 1289 @Test testAppearDeferThenInfoChange()1290 public void testAppearDeferThenInfoChange() { 1291 final ITaskOrganizer organizer = registerMockOrganizer(); 1292 final Task rootTask = createRootTask(); 1293 1294 // Assume layout defer 1295 mWm.mWindowPlacerLocked.deferLayout(); 1296 1297 final Task task = createTask(rootTask); 1298 final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task); 1299 1300 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1301 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); 1302 waitUntilHandlersIdle(); 1303 1304 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1305 assertEquals(1, pendingEvents.size()); 1306 assertEquals(PendingTaskEvent.EVENT_APPEARED, pendingEvents.get(0).mEventType); 1307 assertEquals("TestDescription", 1308 pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel()); 1309 } 1310 1311 @Test testAppearDeferThenVanish()1312 public void testAppearDeferThenVanish() { 1313 final ITaskOrganizer organizer = registerMockOrganizer(); 1314 final Task rootTask = createRootTask(); 1315 1316 // Assume layout defer 1317 mWm.mWindowPlacerLocked.deferLayout(); 1318 1319 final Task task = createTask(rootTask); 1320 1321 rootTask.removeImmediately(); 1322 waitUntilHandlersIdle(); 1323 1324 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1325 assertEquals(0, pendingEvents.size()); 1326 } 1327 1328 @Test testInfoChangeDeferMultiple()1329 public void testInfoChangeDeferMultiple() { 1330 final ITaskOrganizer organizer = registerMockOrganizer(); 1331 final Task rootTask = createRootTask(); 1332 final Task task = createTask(rootTask); 1333 final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task); 1334 1335 // Assume layout defer 1336 mWm.mWindowPlacerLocked.deferLayout(); 1337 1338 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1339 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); 1340 waitUntilHandlersIdle(); 1341 1342 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1343 assertEquals(1, pendingEvents.size()); 1344 assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType); 1345 assertEquals("TestDescription", 1346 pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel()); 1347 1348 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription2")); 1349 waitUntilHandlersIdle(); 1350 1351 pendingEvents = getTaskPendingEvent(organizer, rootTask); 1352 assertEquals(1, pendingEvents.size()); 1353 assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType); 1354 assertEquals("TestDescription2", 1355 pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel()); 1356 } 1357 1358 @Test testInfoChangDeferThenVanish()1359 public void testInfoChangDeferThenVanish() { 1360 final ITaskOrganizer organizer = registerMockOrganizer(); 1361 final Task rootTask = createRootTask(); 1362 final Task task = createTask(rootTask); 1363 final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task); 1364 1365 // Assume layout defer 1366 mWm.mWindowPlacerLocked.deferLayout(); 1367 1368 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1369 record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); 1370 1371 rootTask.removeImmediately(); 1372 waitUntilHandlersIdle(); 1373 1374 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1375 assertEquals(1, pendingEvents.size()); 1376 assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType); 1377 assertEquals("TestDescription", 1378 pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel()); 1379 } 1380 1381 @Test testVanishDeferThenInfoChange()1382 public void testVanishDeferThenInfoChange() { 1383 final ITaskOrganizer organizer = registerMockOrganizer(); 1384 final Task rootTask = createRootTask(); 1385 final Task task = createTask(rootTask); 1386 final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task); 1387 1388 // Assume layout defer 1389 mWm.mWindowPlacerLocked.deferLayout(); 1390 1391 rootTask.removeImmediately(); 1392 rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 1393 waitUntilHandlersIdle(); 1394 1395 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1396 assertEquals(1, pendingEvents.size()); 1397 assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType); 1398 } 1399 1400 @Test testVanishDeferThenBackOnRoot()1401 public void testVanishDeferThenBackOnRoot() { 1402 final ITaskOrganizer organizer = registerMockOrganizer(); 1403 final Task rootTask = createRootTask(); 1404 final Task task = createTask(rootTask); 1405 final ActivityRecord record = createActivityRecord(rootTask.mDisplayContent, task); 1406 1407 // Assume layout defer 1408 mWm.mWindowPlacerLocked.deferLayout(); 1409 1410 rootTask.removeImmediately(); 1411 mWm.mAtmService.mActivityClientController.onBackPressed(record.token, 1412 new IRequestFinishCallback.Default()); 1413 waitUntilHandlersIdle(); 1414 1415 ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(organizer, rootTask); 1416 assertEquals(1, pendingEvents.size()); 1417 assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType); 1418 } 1419 getTaskPendingEvent(ITaskOrganizer organizer, Task task)1420 private ArrayList<PendingTaskEvent> getTaskPendingEvent(ITaskOrganizer organizer, Task task) { 1421 ArrayList<PendingTaskEvent> total = 1422 mWm.mAtmService.mTaskOrganizerController 1423 .getTaskOrganizerPendingEvents(organizer.asBinder()) 1424 .getPendingEventList(); 1425 ArrayList<PendingTaskEvent> result = new ArrayList(); 1426 1427 for (int i = 0; i < total.size(); i++) { 1428 PendingTaskEvent entry = total.get(i); 1429 if (entry.mTask.mTaskId == task.mTaskId) { 1430 result.add(entry); 1431 } 1432 } 1433 1434 return result; 1435 } 1436 1437 @Test testReparentNonResizableTaskToSplitScreen()1438 public void testReparentNonResizableTaskToSplitScreen() { 1439 final ActivityRecord activity = new ActivityBuilder(mAtm) 1440 .setCreateTask(true) 1441 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 1442 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 1443 .build(); 1444 final Task rootTask = activity.getRootTask(); 1445 rootTask.setResizeMode(activity.info.resizeMode); 1446 final Task splitPrimaryRootTask = mWm.mAtmService.mTaskOrganizerController.createRootTask( 1447 mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, null); 1448 final WindowContainerTransaction wct = new WindowContainerTransaction(); 1449 wct.reparent(rootTask.mRemoteToken.toWindowContainerToken(), 1450 splitPrimaryRootTask.mRemoteToken.toWindowContainerToken(), true /* onTop */); 1451 1452 // Can't reparent non-resizable to split screen 1453 mAtm.mSupportsNonResizableMultiWindow = -1; 1454 mAtm.mWindowOrganizerController.applyTransaction(wct); 1455 1456 assertEquals(rootTask, activity.getRootTask()); 1457 1458 // Allow reparent non-resizable to split screen 1459 mAtm.mSupportsNonResizableMultiWindow = 1; 1460 mAtm.mWindowOrganizerController.applyTransaction(wct); 1461 1462 assertEquals(splitPrimaryRootTask, activity.getRootTask()); 1463 } 1464 1465 @Test testSizeCompatModeChangedOnFirstOrganizedTask()1466 public void testSizeCompatModeChangedOnFirstOrganizedTask() throws RemoteException { 1467 final ITaskOrganizer organizer = registerMockOrganizer(); 1468 final Task rootTask = createRootTask(); 1469 final Task task = createTask(rootTask); 1470 final ActivityRecord activity = createActivityRecord(rootTask.mDisplayContent, task); 1471 final ArgumentCaptor<RunningTaskInfo> infoCaptor = 1472 ArgumentCaptor.forClass(RunningTaskInfo.class); 1473 1474 assertTrue(rootTask.isOrganized()); 1475 1476 spyOn(activity); 1477 doReturn(true).when(activity).inSizeCompatMode(); 1478 doReturn(true).when(activity).isState(RESUMED); 1479 1480 // Ensure task info show top activity in size compat. 1481 rootTask.onSizeCompatActivityChanged(); 1482 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1483 verify(organizer).onTaskInfoChanged(infoCaptor.capture()); 1484 RunningTaskInfo info = infoCaptor.getValue(); 1485 assertEquals(rootTask.mTaskId, info.taskId); 1486 assertTrue(info.topActivityInSizeCompat); 1487 1488 // Ensure task info show top activity that is not visible as not in size compat. 1489 clearInvocations(organizer); 1490 doReturn(false).when(activity).isVisible(); 1491 rootTask.onSizeCompatActivityChanged(); 1492 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1493 verify(organizer).onTaskInfoChanged(infoCaptor.capture()); 1494 info = infoCaptor.getValue(); 1495 assertEquals(rootTask.mTaskId, info.taskId); 1496 assertFalse(info.topActivityInSizeCompat); 1497 1498 // Ensure task info show non size compat top activity as not in size compat. 1499 clearInvocations(organizer); 1500 doReturn(true).when(activity).isVisible(); 1501 doReturn(false).when(activity).inSizeCompatMode(); 1502 rootTask.onSizeCompatActivityChanged(); 1503 mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); 1504 verify(organizer).onTaskInfoChanged(infoCaptor.capture()); 1505 info = infoCaptor.getValue(); 1506 assertEquals(rootTask.mTaskId, info.taskId); 1507 assertFalse(info.topActivityInSizeCompat); 1508 } 1509 1510 @Test testStartTasksInTransaction()1511 public void testStartTasksInTransaction() { 1512 WindowContainerTransaction wct = new WindowContainerTransaction(); 1513 ActivityOptions testOptions = ActivityOptions.makeBasic(); 1514 testOptions.setTransientLaunch(); 1515 wct.startTask(1, null /* options */); 1516 wct.startTask(2, testOptions.toBundle()); 1517 spyOn(mWm.mAtmService.mTaskSupervisor); 1518 doReturn(START_CANCELED).when(mWm.mAtmService.mTaskSupervisor).startActivityFromRecents( 1519 anyInt(), anyInt(), anyInt(), any()); 1520 clearInvocations(mWm.mAtmService); 1521 mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); 1522 1523 verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents( 1524 anyInt(), anyInt(), eq(1), any()); 1525 1526 final ArgumentCaptor<SafeActivityOptions> optionsCaptor = 1527 ArgumentCaptor.forClass(SafeActivityOptions.class); 1528 verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents( 1529 anyInt(), anyInt(), eq(2), optionsCaptor.capture()); 1530 assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch()); 1531 } 1532 1533 @Test testResumeTopsWhenLeavingPinned()1534 public void testResumeTopsWhenLeavingPinned() { 1535 final ActivityRecord record = makePipableActivity(); 1536 final Task rootTask = record.getRootTask(); 1537 1538 clearInvocations(mWm.mAtmService.mRootWindowContainer); 1539 final WindowContainerTransaction t = new WindowContainerTransaction(); 1540 WindowContainerToken wct = rootTask.mRemoteToken.toWindowContainerToken(); 1541 t.setWindowingMode(wct, WINDOWING_MODE_PINNED); 1542 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 1543 verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities(); 1544 1545 clearInvocations(mWm.mAtmService.mRootWindowContainer); 1546 // The token for the PIP root task may have changed when the task entered PIP mode, so do 1547 // not reuse the one from above. 1548 final WindowContainerToken newToken = 1549 record.getRootTask().mRemoteToken.toWindowContainerToken(); 1550 t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN); 1551 mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); 1552 verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities(); 1553 } 1554 1555 /** 1556 * Verifies that task vanished is called for a specific task. 1557 */ assertTaskVanished(ITaskOrganizer organizer, boolean expectVanished, Task... tasks)1558 private void assertTaskVanished(ITaskOrganizer organizer, boolean expectVanished, Task... tasks) 1559 throws RemoteException { 1560 ArgumentCaptor<RunningTaskInfo> arg = ArgumentCaptor.forClass(RunningTaskInfo.class); 1561 verify(organizer, atLeastOnce()).onTaskVanished(arg.capture()); 1562 List<RunningTaskInfo> taskInfos = arg.getAllValues(); 1563 1564 HashSet<Integer> vanishedTaskIds = new HashSet<>(); 1565 for (int i = 0; i < taskInfos.size(); i++) { 1566 vanishedTaskIds.add(taskInfos.get(i).taskId); 1567 } 1568 HashSet<Integer> taskIds = new HashSet<>(); 1569 for (int i = 0; i < tasks.length; i++) { 1570 taskIds.add(tasks[i].mTaskId); 1571 } 1572 1573 assertTrue(expectVanished 1574 ? vanishedTaskIds.containsAll(taskIds) 1575 : !vanishedTaskIds.removeAll(taskIds)); 1576 } 1577 assertContainsTasks(List<TaskAppearedInfo> taskInfos, Task... expectedTasks)1578 private void assertContainsTasks(List<TaskAppearedInfo> taskInfos, Task... expectedTasks) { 1579 HashSet<Integer> taskIds = new HashSet<>(); 1580 for (int i = 0; i < taskInfos.size(); i++) { 1581 taskIds.add(taskInfos.get(i).getTaskInfo().taskId); 1582 } 1583 for (int i = 0; i < expectedTasks.length; i++) { 1584 assertTrue(taskIds.contains(expectedTasks[i].mTaskId)); 1585 } 1586 } 1587 } 1588