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