• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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