• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 android.server.wm;
18 
19 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
23 import static android.server.wm.TestTaskOrganizer.INVALID_TASK_ID;
24 import static android.server.wm.WindowManagerState.STATE_RESUMED;
25 import static android.server.wm.WindowManagerState.STATE_STOPPED;
26 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
27 import static android.server.wm.app.Components.NON_RESIZEABLE_ACTIVITY;
28 import static android.server.wm.app.Components.NO_RELAUNCH_ACTIVITY;
29 import static android.server.wm.app.Components.SINGLE_INSTANCE_ACTIVITY;
30 import static android.server.wm.app.Components.SINGLE_TASK_ACTIVITY;
31 import static android.server.wm.app.Components.TEST_ACTIVITY;
32 import static android.server.wm.app.Components.TEST_ACTIVITY_WITH_SAME_AFFINITY;
33 import static android.server.wm.app.Components.TRANSLUCENT_TEST_ACTIVITY;
34 import static android.server.wm.app.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF;
35 import static android.server.wm.app27.Components.SDK_27_LAUNCHING_ACTIVITY;
36 import static android.server.wm.app27.Components.SDK_27_SEPARATE_PROCESS_ACTIVITY;
37 import static android.server.wm.app27.Components.SDK_27_TEST_ACTIVITY;
38 
39 import static org.junit.Assert.assertEquals;
40 import static org.junit.Assert.assertNotEquals;
41 import static org.junit.Assert.assertTrue;
42 import static org.junit.Assert.fail;
43 import static org.junit.Assume.assumeTrue;
44 
45 import android.content.ComponentName;
46 import android.content.res.Resources;
47 import android.platform.test.annotations.Presubmit;
48 import android.server.wm.CommandSession.ActivityCallback;
49 import android.view.WindowManager;
50 import android.window.WindowContainerToken;
51 import android.window.WindowContainerTransaction;
52 
53 import org.junit.Before;
54 import org.junit.Test;
55 
56 /**
57  * Build/Install/Run:
58  *     atest CtsWindowManagerDeviceTestCases:MultiWindowTests
59  */
60 @Presubmit
61 @android.server.wm.annotation.Group2
62 public class MultiWindowTests extends ActivityManagerTestBase {
63 
64     private boolean mIsHomeRecentsComponent;
65 
66     @Before
67     @Override
setUp()68     public void setUp() throws Exception {
69         super.setUp();
70 
71         mIsHomeRecentsComponent = mWmState.isHomeRecentsComponent();
72 
73         assumeTrue("Skipping test: no split multi-window support",
74                 supportsSplitScreenMultiWindow());
75     }
76 
77     @Test
testMinimumDeviceSize()78     public void testMinimumDeviceSize() {
79         mWmState.assertDeviceDefaultDisplaySizeForMultiWindow(
80                 "Devices supporting multi-window must be larger than the default minimum"
81                         + " task size");
82         mWmState.assertDeviceDefaultDisplaySizeForSplitScreen(
83                 "Devices supporting split-screen multi-window must be larger than the"
84                         + " default minimum display size.");
85     }
86 
87     /** Resizeable activity should be able to enter multi-window mode.*/
88     @Test
testResizeableActivity()89     public void testResizeableActivity() {
90         assertActivitySupportedInSplitScreen(TEST_ACTIVITY);
91     }
92 
93     /**
94      * Depending on the value of
95      * {@link com.android.internal.R.integer.config_supportsNonResizableMultiWindow},
96      * non-resizeable activity may or may not be able to enter multi-window mode.
97      *
98      * Based on the flag value:
99      * -1: not support non-resizable in multi window.
100      *  0: check the screen smallest width, if it is a large screen, support non-resizable in multi
101      *     window. Otherwise, not support.
102      *  1: always support non-resizable in multi window.
103      */
104     @Test
testNonResizeableActivity()105     public void testNonResizeableActivity() {
106         createManagedDevEnableNonResizableMultiWindowSession().set(0);
107         final Resources resources = mContext.getResources();
108         final int configSupportsNonResizableMultiWindow;
109         try {
110             configSupportsNonResizableMultiWindow = resources.getInteger(resources.getIdentifier(
111                     "config_supportsNonResizableMultiWindow", "integer", "android"));
112         } catch (Resources.NotFoundException e) {
113             fail("Device must define config_supportsNonResizableMultiWindow");
114             return;
115         }
116         switch (configSupportsNonResizableMultiWindow) {
117             case -1:
118                 assertActivityNotSupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
119                 break;
120             case 1:
121                 assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
122                 break;
123             case 0:
124                 final int smallestScreenWidthDp = mWmState.getHomeTask()
125                         .mFullConfiguration.smallestScreenWidthDp;
126                 if (smallestScreenWidthDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP) {
127                     assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
128                 } else {
129                     assertActivityNotSupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
130                 }
131                 break;
132             default:
133                 fail("config_supportsNonResizableMultiWindow must be -1, 0, or 1.");
134         }
135     }
136 
137     /**
138      * Non-resizeable activity can enter split-screen if
139      * {@link android.provider.Settings.Global#DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW} is
140      * set.
141      */
142     @Test
testDevEnableNonResizeableMultiWindow_splitScreenPrimary()143     public void testDevEnableNonResizeableMultiWindow_splitScreenPrimary() {
144         createManagedDevEnableNonResizableMultiWindowSession().set(1);
145 
146         assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY);
147     }
148 
149     /**
150      * Non-resizeable activity can enter split-screen if
151      * {@link android.provider.Settings.Global#DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW} is
152      * set.
153      */
154     @Test
testDevEnableNonResizeableMultiWindow_splitScreenSecondary()155     public void testDevEnableNonResizeableMultiWindow_splitScreenSecondary() {
156         createManagedDevEnableNonResizableMultiWindowSession().set(1);
157 
158         launchActivitiesInSplitScreen(
159                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY),
160                 getLaunchActivityBuilder().setTargetActivity(NON_RESIZEABLE_ACTIVITY));
161 
162         mWmState.waitForActivityState(NON_RESIZEABLE_ACTIVITY, STATE_RESUMED);
163         mWmState.assertVisibility(NON_RESIZEABLE_ACTIVITY, true);
164         assertTrue(mWmState.containsActivityInWindowingMode(
165                 NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW));
166     }
167 
168     /** Asserts that the give activity can be shown in split screen. */
assertActivitySupportedInSplitScreen(ComponentName activity)169     private void assertActivitySupportedInSplitScreen(ComponentName activity) {
170         launchActivityInPrimarySplit(activity);
171         mWmState.waitForActivityState(activity, STATE_RESUMED);
172         mWmState.assertVisibility(activity, true);
173         assertTrue(mWmState.containsActivityInWindowingMode(activity, WINDOWING_MODE_MULTI_WINDOW));
174     }
175 
176     /** Asserts that the give activity can NOT be shown in split screen. */
assertActivityNotSupportedInSplitScreen(ComponentName activity)177     private void assertActivityNotSupportedInSplitScreen(ComponentName activity) {
178         boolean gotAssertionError = false;
179         try {
180             launchActivityInPrimarySplit(activity);
181         } catch (AssertionError e) {
182             gotAssertionError = true;
183         }
184         assertTrue("Trying to put non-resizeable activity in split should throw error.",
185                 gotAssertionError);
186         mWmState.waitForActivityState(activity, STATE_RESUMED);
187         mWmState.assertVisibility(activity, true);
188         assertTrue(mWmState.containsActivityInWindowingMode(activity, WINDOWING_MODE_FULLSCREEN));
189     }
190 
191     @Test
testLaunchToSideMultiWindowCallbacks()192     public void testLaunchToSideMultiWindowCallbacks() {
193         // Launch two activities in split-screen mode.
194         launchActivitiesInSplitScreen(
195                 getLaunchActivityBuilder().setTargetActivity(NO_RELAUNCH_ACTIVITY),
196                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
197 
198         int displayWindowingMode = mWmState.getDisplay(
199                 mWmState.getDisplayByActivity(TEST_ACTIVITY)).getWindowingMode();
200         separateTestJournal();
201         mTaskOrganizer.dismissSplitScreen(true /* primaryOnTop */);
202         if (displayWindowingMode == WINDOWING_MODE_FULLSCREEN) {
203             // Exit split-screen mode and ensure we only get 1 multi-window mode changed callback.
204             final ActivityLifecycleCounts lifecycleCounts = waitForOnMultiWindowModeChanged(
205                     NO_RELAUNCH_ACTIVITY);
206             assertEquals(1,
207                     lifecycleCounts.getCount(ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED));
208         } else {
209             // Display is not a fullscreen display, so there won't be a multi-window callback.
210             // Instead just verify that windows are not in split-screen anymore.
211             waitForIdle();
212             mWmState.computeState();
213             mWmState.assertDoesNotContainStack("Must have exited split-screen",
214                     WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
215         }
216     }
217 
218     @Test
testNoUserLeaveHintOnMultiWindowModeChanged()219     public void testNoUserLeaveHintOnMultiWindowModeChanged() {
220         launchActivity(NO_RELAUNCH_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
221 
222         // Move to primary split.
223         separateTestJournal();
224         putActivityInPrimarySplit(NO_RELAUNCH_ACTIVITY);
225 
226         ActivityLifecycleCounts lifecycleCounts =
227                 waitForOnMultiWindowModeChanged(NO_RELAUNCH_ACTIVITY);
228         assertEquals("mMultiWindowModeChangedCount",
229                 1, lifecycleCounts.getCount(ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED));
230         assertEquals("mUserLeaveHintCount",
231                 0, lifecycleCounts.getCount(ActivityCallback.ON_USER_LEAVE_HINT));
232 
233         // Make sure primary split is focused. This way when we dismiss it later fullscreen stack
234         // will come up.
235         launchActivity(LAUNCHING_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
236         putActivityInSecondarySplit(LAUNCHING_ACTIVITY);
237 
238         launchActivity(NO_RELAUNCH_ACTIVITY);
239 
240         separateTestJournal();
241 
242         // Move activities back to fullscreen screen.
243         // TestTaskOrganizer sets windowing modes of tasks to unspecific when putting them to split
244         // screens so we need to explicitly set their windowing modes back to fullscreen to avoid
245         // inheriting freeform windowing mode from the display on freeform first devices.
246         int noRelaunchTaskId = mWmState.getTaskByActivity(NO_RELAUNCH_ACTIVITY).mTaskId;
247         WindowContainerToken noRelaunchTaskToken =
248                 mTaskOrganizer.getTaskInfo(noRelaunchTaskId).getToken();
249         WindowContainerTransaction t = new WindowContainerTransaction()
250                 .setWindowingMode(noRelaunchTaskToken, WINDOWING_MODE_FULLSCREEN);
251         mTaskOrganizer.dismissSplitScreen(t, true /* primaryOnTop */);
252 
253         lifecycleCounts = waitForOnMultiWindowModeChanged(NO_RELAUNCH_ACTIVITY);
254         assertEquals("mMultiWindowModeChangedCount",
255                 1, lifecycleCounts.getCount(ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED));
256         assertEquals("mUserLeaveHintCount",
257                 0, lifecycleCounts.getCount(ActivityCallback.ON_USER_LEAVE_HINT));
258     }
259 
260     @Test
testLaunchToSideAndBringToFront()261     public void testLaunchToSideAndBringToFront() {
262         launchActivitiesInSplitScreen(
263                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
264                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
265 
266         mWmState.assertFocusedActivity("Launched to side activity must be in front.",
267                 TEST_ACTIVITY);
268 
269         // Set secondary split as launch root
270         mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
271 
272         // Launch another activity to side to cover first one.
273         launchActivityInSecondarySplit(NO_RELAUNCH_ACTIVITY);
274         mWmState.assertFocusedActivity("Launched to side covering activity must be in front.",
275                 NO_RELAUNCH_ACTIVITY);
276 
277         // Launch activity that was first launched to side. It should be brought to front.
278         launchActivity(TEST_ACTIVITY);
279         mWmState.assertFocusedActivity("Launched to side covering activity must be in front.",
280                 TEST_ACTIVITY);
281     }
282 
283     @Test
testLaunchToSideMultiple()284     public void testLaunchToSideMultiple() {
285         launchActivitiesInSplitScreen(
286                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
287                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
288 
289         final int taskNumberInitial = mTaskOrganizer.getSecondarySplitTaskCount();
290 
291         // Try to launch to side same activity again.
292         launchActivity(TEST_ACTIVITY);
293         mWmState.computeState(TEST_ACTIVITY, LAUNCHING_ACTIVITY);
294         final int taskNumberFinal = mTaskOrganizer.getSecondarySplitTaskCount();
295         assertEquals("Task number mustn't change.", taskNumberInitial, taskNumberFinal);
296         mWmState.assertFocusedActivity("Launched to side activity must remain in front.",
297                 TEST_ACTIVITY);
298     }
299 
300     @Test
testLaunchToSideSingleInstance()301     public void testLaunchToSideSingleInstance() {
302         launchTargetToSide(SINGLE_INSTANCE_ACTIVITY, false);
303     }
304 
305     @Test
testLaunchToSideSingleTask()306     public void testLaunchToSideSingleTask() {
307         launchTargetToSide(SINGLE_TASK_ACTIVITY, false);
308     }
309 
310     @Test
testLaunchToSideMultipleWithDifferentIntent()311     public void testLaunchToSideMultipleWithDifferentIntent() {
312         launchTargetToSide(TEST_ACTIVITY, true);
313     }
314 
launchTargetToSide(ComponentName targetActivityName, boolean taskCountMustIncrement)315     private void launchTargetToSide(ComponentName targetActivityName,
316             boolean taskCountMustIncrement) {
317         launchActivityInPrimarySplit(LAUNCHING_ACTIVITY);
318 
319         // Launch target to side
320         final LaunchActivityBuilder targetActivityLauncher = getLaunchActivityBuilder()
321                 .setTargetActivity(targetActivityName)
322                 .setToSide(true)
323                 .setRandomData(true)
324                 .setMultipleTask(false);
325         targetActivityLauncher.execute();
326         final int secondaryTaskId = mWmState.getTaskByActivity(targetActivityName).mTaskId;
327         mTaskOrganizer.putTaskInSplitSecondary(secondaryTaskId);
328 
329         mWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY);
330         final int taskNumberInitial = mTaskOrganizer.getSecondarySplitTaskCount();
331 
332         // Try to launch to side same activity again with different data.
333         targetActivityLauncher.execute();
334         mWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY);
335 
336         final int[] excludeTaskIds = new int[] { secondaryTaskId, INVALID_TASK_ID };
337         if (taskCountMustIncrement) {
338             mWmState.waitFor("Waiting for new activity to come up.",
339                     state -> state.getTaskByActivity(targetActivityName, excludeTaskIds) != null);
340         }
341         WindowManagerState.Task task = mWmState.getTaskByActivity(targetActivityName,
342                 excludeTaskIds);
343         final int secondaryTaskId2;
344         if (task != null) {
345             secondaryTaskId2 = task.mTaskId;
346             mTaskOrganizer.putTaskInSplitSecondary(secondaryTaskId2);
347         } else {
348             secondaryTaskId2 = INVALID_TASK_ID;
349         }
350         final int taskNumberSecondLaunch = mTaskOrganizer.getSecondarySplitTaskCount();
351 
352         if (taskCountMustIncrement) {
353             assertEquals("Task number must be incremented.", taskNumberInitial + 1,
354                     taskNumberSecondLaunch);
355         } else {
356             assertEquals("Task number must not change.", taskNumberInitial,
357                     taskNumberSecondLaunch);
358         }
359         mWmState.waitForFocusedActivity("Wait for launched to side activity to be in front.",
360                 targetActivityName);
361         mWmState.assertFocusedActivity("Launched to side activity must be in front.",
362                 targetActivityName);
363 
364         // Try to launch to side same activity again with different random data. Note that null
365         // cannot be used here, since the first instance of TestActivity is launched with no data
366         // in order to launch into split screen.
367         targetActivityLauncher.execute();
368         mWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY);
369 
370         excludeTaskIds[1] = secondaryTaskId2;
371         if (taskCountMustIncrement) {
372             mWmState.waitFor("Waiting for the second new activity to come up.",
373                     state -> state.getTaskByActivity(targetActivityName, excludeTaskIds) != null);
374         }
375         WindowManagerState.Task taskFinal =
376                 mWmState.getTaskByActivity(targetActivityName, excludeTaskIds);
377         if (taskFinal != null) {
378             int secondaryTaskId3 = taskFinal.mTaskId;
379             mTaskOrganizer.putTaskInSplitSecondary(secondaryTaskId3);
380         }
381         final int taskNumberFinal = mTaskOrganizer.getSecondarySplitTaskCount();
382 
383         if (taskCountMustIncrement) {
384             assertEquals("Task number must be incremented.", taskNumberSecondLaunch + 1,
385                     taskNumberFinal);
386         } else {
387             assertEquals("Task number must not change.", taskNumberSecondLaunch,
388                     taskNumberFinal);
389         }
390         mWmState.waitForFocusedActivity("Wait for launched to side activity to be in front.",
391                 targetActivityName);
392         mWmState.assertFocusedActivity("Launched to side activity must be in front.",
393                 targetActivityName);
394     }
395 
396     @Test
testLaunchToSideMultipleWithFlag()397     public void testLaunchToSideMultipleWithFlag() {
398         launchActivitiesInSplitScreen(
399                 getLaunchActivityBuilder()
400                         .setTargetActivity(TEST_ACTIVITY),
401                 getLaunchActivityBuilder()
402                         // Try to launch to side same activity again,
403                         // but with Intent#FLAG_ACTIVITY_MULTIPLE_TASK.
404                         .setMultipleTask(true)
405                         .setTargetActivity(TEST_ACTIVITY));
406         assertTrue("Primary split must contain TEST_ACTIVITY",
407                 mWmState.getRootTask(mTaskOrganizer.getPrimarySplitTaskId())
408                         .containsActivity(TEST_ACTIVITY)
409         );
410 
411         assertTrue("Secondary split must contain TEST_ACTIVITY",
412                 mWmState.getRootTask(mTaskOrganizer.getSecondarySplitTaskId())
413                         .containsActivity(TEST_ACTIVITY)
414                 );
415         mWmState.assertFocusedActivity("Launched to side activity must be in front.",
416                 TEST_ACTIVITY);
417     }
418 
419     @Test
testSameProcessActivityResumedPreQ()420     public void testSameProcessActivityResumedPreQ() {
421         launchActivitiesInSplitScreen(
422                 getLaunchActivityBuilder().setTargetActivity(SDK_27_TEST_ACTIVITY),
423                 getLaunchActivityBuilder().setTargetActivity(SDK_27_LAUNCHING_ACTIVITY));
424 
425         assertEquals("There must be only one resumed activity in the package.", 1,
426                 mWmState.getResumedActivitiesCountInPackage(
427                         SDK_27_TEST_ACTIVITY.getPackageName()));
428     }
429 
430     @Test
testDifferentProcessActivityResumedPreQ()431     public void testDifferentProcessActivityResumedPreQ() {
432         launchActivitiesInSplitScreen(
433                 getLaunchActivityBuilder().setTargetActivity(SDK_27_TEST_ACTIVITY),
434                 getLaunchActivityBuilder().setTargetActivity(SDK_27_SEPARATE_PROCESS_ACTIVITY));
435 
436         assertEquals("There must be only two resumed activities in the package.", 2,
437                 mWmState.getResumedActivitiesCountInPackage(
438                         SDK_27_TEST_ACTIVITY.getPackageName()));
439     }
440 
441     @Test
testDisallowUpdateWindowingModeWhenInLockedTask()442     public void testDisallowUpdateWindowingModeWhenInLockedTask() {
443         launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
444         final WindowManagerState.Task task =
445                 mWmState.getStandardRootTaskByWindowingMode(
446                         WINDOWING_MODE_FULLSCREEN).getTopTask();
447 
448         try {
449             // Lock the task
450             runWithShellPermission(() -> mAtm.startSystemLockTaskMode(task.mTaskId));
451             waitForOrFail("Fail to enter locked task mode", () ->
452                     mAm.getLockTaskModeState() != LOCK_TASK_MODE_NONE);
453 
454             // Verify specifying non-fullscreen windowing mode will fail.
455             runWithShellPermission(() -> {
456                 final WindowContainerTransaction wct = new WindowContainerTransaction()
457                         .setWindowingMode(
458                                 mTaskOrganizer.getTaskInfo(task.mTaskId).getToken(),
459                                 WINDOWING_MODE_MULTI_WINDOW);
460                 mTaskOrganizer.applyTransaction(wct);
461             });
462             mWmState.computeState(TEST_ACTIVITY);
463             assertEquals(WINDOWING_MODE_FULLSCREEN,
464                     mWmState.getWindowState(TEST_ACTIVITY).getWindowingMode());
465         } finally {
466             runWithShellPermission(() -> {
467                 mAtm.stopSystemLockTaskMode();
468             });
469         }
470     }
471 
472     @Test
testDisallowReparentOperationWhenInLockedTask()473     public void testDisallowReparentOperationWhenInLockedTask() {
474         launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
475         launchActivity(LAUNCHING_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW);
476         final WindowManagerState.Task task = mWmState
477                 .getStandardRootTaskByWindowingMode(WINDOWING_MODE_FULLSCREEN).getTopTask();
478         final WindowManagerState.Task root = mWmState
479                 .getStandardRootTaskByWindowingMode(WINDOWING_MODE_MULTI_WINDOW).getTopTask();
480 
481         try {
482             // Lock the task
483             runWithShellPermission(() -> {
484                 mAtm.startSystemLockTaskMode(task.mTaskId);
485             });
486             waitForOrFail("Fail to enter locked task mode", () ->
487                     mAm.getLockTaskModeState() != LOCK_TASK_MODE_NONE);
488 
489             boolean gotAssertionError = false;
490             try {
491                 runWithShellPermission(() -> {
492                     // Fetch tokens of testing task and multi-window root.
493                     final WindowContainerToken multiWindowRoot =
494                             mTaskOrganizer.getTaskInfo(root.mTaskId).getToken();
495                     final WindowContainerToken testChild =
496                             mTaskOrganizer.getTaskInfo(task.mTaskId).getToken();
497 
498                     // Verify performing reparent operation is no operation.
499                     final WindowContainerTransaction wct = new WindowContainerTransaction()
500                             .reparent(testChild, multiWindowRoot, true /* onTop */);
501                     mTaskOrganizer.applyTransaction(wct);
502                     waitForOrFail("Fail to reparent", () ->
503                             mTaskOrganizer.getTaskInfo(task.mTaskId).getParentTaskId()
504                                     == root.mTaskId);
505                 });
506             } catch (AssertionError e) {
507                 gotAssertionError = true;
508             }
509             assertTrue("Not allowed to perform hierarchy operation while in locked task mode.",
510                     gotAssertionError);
511         } finally {
512             runWithShellPermission(() -> {
513                 mAtm.stopSystemLockTaskMode();
514             });
515         }
516     }
517 
518     /**
519      * Asserts that the activity is visible when the top opaque activity finishes and with another
520      * translucent activity on top while in split-screen-secondary task.
521      */
522     @Test
testVisibilityWithTranslucentAndTopFinishingActivity()523     public void testVisibilityWithTranslucentAndTopFinishingActivity() {
524         // Launch two activities in split-screen mode.
525         launchActivitiesInSplitScreen(
526                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
527                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY_WITH_SAME_AFFINITY));
528 
529         mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
530 
531         // Launch two more activities on a different task on top of split-screen-secondary and
532         // only the top opaque activity should be visible.
533         // Explicitly launch them into fullscreen mode because the control windowing mode of the
534         // launch root doesn't include freeform mode. Freeform first devices launch apps in freeform
535         // mode by default, which won't trigger the launch root.
536         getLaunchActivityBuilder().setTargetActivity(TRANSLUCENT_TEST_ACTIVITY)
537                 .setUseInstrumentation()
538                 .setWaitForLaunched(true)
539                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
540                 .execute();
541         getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)
542                 .setUseInstrumentation()
543                 .setWaitForLaunched(true)
544                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
545                 .execute();
546         mWmState.assertVisibility(TEST_ACTIVITY, true);
547         mWmState.waitForActivityState(TRANSLUCENT_TEST_ACTIVITY, STATE_STOPPED);
548         mWmState.assertVisibility(TRANSLUCENT_TEST_ACTIVITY, false);
549         mWmState.assertVisibility(TEST_ACTIVITY_WITH_SAME_AFFINITY, false);
550 
551         // Finish the top opaque activity and both the two activities should be visible.
552         mBroadcastActionTrigger.doAction(TEST_ACTIVITY_ACTION_FINISH_SELF);
553         mWmState.computeState(new WaitForValidActivityState(TRANSLUCENT_TEST_ACTIVITY));
554         mWmState.assertVisibility(TRANSLUCENT_TEST_ACTIVITY, true);
555         mWmState.assertVisibility(TEST_ACTIVITY_WITH_SAME_AFFINITY, true);
556     }
557 
558     /**
559      * Ensure that the hierarchy operation : reorder is not allowed if the target task is violated
560      * the lock-task policy.
561      */
562     @Test
testDisallowReOrderOperationWhenInLockedTask()563     public void testDisallowReOrderOperationWhenInLockedTask() {
564         // Start LaunchingActivity and testActivity in two separate tasks.
565         launchActivity(LAUNCHING_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
566         launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
567         waitAndAssertResumedActivity(TEST_ACTIVITY, "Activity must be resumed");
568 
569         final int taskId = mWmState.getTaskByActivity(TEST_ACTIVITY).mTaskId;
570         final int taskId2 = mWmState.getTaskByActivity(LAUNCHING_ACTIVITY).mTaskId;
571         // Make sure the launching activity and the test activity are not in the same task.
572         assertNotEquals("Activity must be in different task.", taskId, taskId2);
573 
574         try {
575             runWithShellPermission(() -> {
576                 mAtm.startSystemLockTaskMode(taskId);
577             });
578             waitForOrFail("Fail to enter locked task mode", () ->
579                     mAm.getLockTaskModeState() != LOCK_TASK_MODE_NONE);
580 
581             boolean gotAssertionError = false;
582             try {
583                 runWithShellPermission(() -> {
584                     final WindowContainerToken token =
585                             mTaskOrganizer.getTaskInfo(taskId2).getToken();
586 
587                     // Verify performing reorder operation is no operation.
588                     final WindowContainerTransaction wct = new WindowContainerTransaction()
589                             .reorder(token, true /* onTop */);
590                     mTaskOrganizer.applyTransaction(wct);
591 
592                     final WindowManagerState.Task topTask = mWmState
593                             .getStandardRootTaskByWindowingMode(WINDOWING_MODE_FULLSCREEN)
594                             .getTopTask();
595                     waitForOrFail("Fail to reorder", () -> (topTask.mTaskId == taskId2));
596                 });
597             } catch (AssertionError e) {
598                 gotAssertionError = true;
599             }
600             assertTrue("Not allowed to perform reorder operation while in locked task mode.",
601                     gotAssertionError);
602         } finally {
603             runWithShellPermission(() -> {
604                 mAtm.stopSystemLockTaskMode();
605             });
606         }
607     }
608 }
609