1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
26 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
27 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
29 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
30 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
31 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
32 import static android.view.Display.DEFAULT_DISPLAY;
33 import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
34 
35 import static com.android.server.wm.ActivityStarter.Request;
36 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
37 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
38 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
39 
40 import static org.junit.Assert.assertEquals;
41 import static org.junit.Assert.assertTrue;
42 import static org.mockito.Mockito.doReturn;
43 import static org.mockito.Mockito.mock;
44 import static org.mockito.Mockito.when;
45 
46 import android.app.ActivityOptions;
47 import android.content.pm.ActivityInfo;
48 import android.content.pm.ApplicationInfo;
49 import android.content.res.Configuration;
50 import android.graphics.Rect;
51 import android.os.Build;
52 import android.platform.test.annotations.Presubmit;
53 import android.view.Gravity;
54 import android.view.InsetsSource;
55 import android.view.InsetsState;
56 import android.view.WindowInsets;
57 
58 import androidx.test.filters.SmallTest;
59 
60 import com.android.server.wm.LaunchParamsController.LaunchParams;
61 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier.Result;
62 
63 import org.junit.Before;
64 import org.junit.Test;
65 import org.junit.runner.RunWith;
66 
67 import java.util.ArrayList;
68 import java.util.List;
69 import java.util.Locale;
70 
71 /**
72  * Tests for default task bounds.
73  *
74  * Build/Install/Run:
75  *  atest WmTests:TaskLaunchParamsModifierTests
76  */
77 @SmallTest
78 @Presubmit
79 @RunWith(WindowTestRunner.class)
80 public class TaskLaunchParamsModifierTests extends WindowTestsBase {
81     private static final Rect DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0,
82             /* right */ 1920, /* bottom */ 1080);
83     private static final Rect DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100,
84             /* top */ 200, /* right */ 1620, /* bottom */ 680);
85 
86     private static final Rect SMALL_DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0,
87             /* right */ 1000, /* bottom */ 500);
88     private static final Rect SMALL_DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100,
89             /* top */ 50, /* right */ 900, /* bottom */ 450);
90 
91     private ActivityRecord mActivity;
92 
93     private TaskLaunchParamsModifier mTarget;
94 
95     private LaunchParams mCurrent;
96     private LaunchParams mResult;
97 
98     @Before
setUp()99     public void setUp() throws Exception {
100         mActivity = new ActivityBuilder(mAtm).build();
101         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
102         mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
103 
104         mTarget = new TaskLaunchParamsModifier(mSupervisor);
105 
106         mCurrent = new LaunchParams();
107         mCurrent.reset();
108         mResult = new LaunchParams();
109         mResult.reset();
110     }
111 
112     @Test
testReturnsSkipWithEmptyActivity()113     public void testReturnsSkipWithEmptyActivity() {
114         final Task task = new TaskBuilder(mSupervisor).build();
115         assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setActivity(null).calculate());
116     }
117 
118     // =======================
119     // Display Related Tests
120     // =======================
121     @Test
testDefaultToPrimaryDisplayArea()122     public void testDefaultToPrimaryDisplayArea() {
123         createNewDisplayContent(WINDOWING_MODE_FREEFORM);
124 
125         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
126 
127         assertEquals(mRootWindowContainer.getDefaultTaskDisplayArea(),
128                 mResult.mPreferredTaskDisplayArea);
129     }
130 
131     @Test
testUsesPreviousDisplayAreaIfSet()132     public void testUsesPreviousDisplayAreaIfSet() {
133         createNewDisplayContent(WINDOWING_MODE_FREEFORM);
134         final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
135 
136         mCurrent.mPreferredTaskDisplayArea = display.getDefaultTaskDisplayArea();
137 
138         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
139 
140         assertEquals(display.getDefaultTaskDisplayArea(), mResult.mPreferredTaskDisplayArea);
141     }
142 
143     @Test
testUsesSourcesDisplayAreaIfSet()144     public void testUsesSourcesDisplayAreaIfSet() {
145         final TestDisplayContent freeformDisplay = createNewDisplayContent(
146                 WINDOWING_MODE_FREEFORM);
147         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
148                 WINDOWING_MODE_FULLSCREEN);
149 
150         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
151 
152         ActivityRecord source = createSourceActivity(fullscreenDisplay);
153 
154         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setSource(source).calculate());
155 
156         assertEquals(fullscreenDisplay.getDefaultTaskDisplayArea(),
157                 mResult.mPreferredTaskDisplayArea);
158     }
159 
160     @Test
testUsesOptionsDisplayIdIfSet()161     public void testUsesOptionsDisplayIdIfSet() {
162         final TestDisplayContent freeformDisplay = createNewDisplayContent(
163                 WINDOWING_MODE_FREEFORM);
164         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
165                 WINDOWING_MODE_FULLSCREEN);
166 
167         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
168         ActivityRecord source = createSourceActivity(freeformDisplay);
169 
170         ActivityOptions options = ActivityOptions.makeBasic();
171         options.setLaunchDisplayId(fullscreenDisplay.mDisplayId);
172 
173         assertEquals(RESULT_CONTINUE,
174                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
175 
176         assertEquals(fullscreenDisplay.getDefaultTaskDisplayArea(),
177                 mResult.mPreferredTaskDisplayArea);
178     }
179 
180     @Test
testUsesOptionsDisplayAreaTokenIfSet()181     public void testUsesOptionsDisplayAreaTokenIfSet() {
182         final TestDisplayContent freeformDisplay = createNewDisplayContent(
183                 WINDOWING_MODE_FREEFORM);
184         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
185                 WINDOWING_MODE_FULLSCREEN);
186 
187         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
188         ActivityRecord source = createSourceActivity(freeformDisplay);
189 
190         ActivityOptions options = ActivityOptions.makeBasic();
191         options.setLaunchTaskDisplayArea(fullscreenDisplay.getDefaultTaskDisplayArea()
192                 .mRemoteToken.toWindowContainerToken());
193 
194         assertEquals(RESULT_CONTINUE,
195                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
196 
197         assertEquals(fullscreenDisplay.getDefaultTaskDisplayArea(),
198                 mResult.mPreferredTaskDisplayArea);
199     }
200 
201     @Test
testUsesOptionsDisplayAreaFeatureIdIfSet()202     public void testUsesOptionsDisplayAreaFeatureIdIfSet() {
203         final TestDisplayContent freeformDisplay = createNewDisplayContent(
204                 WINDOWING_MODE_FREEFORM);
205         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
206                 WINDOWING_MODE_FULLSCREEN);
207 
208         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
209         ActivityRecord source = createSourceActivity(freeformDisplay);
210 
211         ActivityOptions options = ActivityOptions.makeBasic();
212         options.setLaunchDisplayId(fullscreenDisplay.mDisplayId);
213         options.setLaunchTaskDisplayAreaFeatureId(
214                 fullscreenDisplay.getDefaultTaskDisplayArea().mFeatureId);
215 
216         assertEquals(RESULT_CONTINUE,
217                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
218 
219         assertEquals(fullscreenDisplay.getDefaultTaskDisplayArea(),
220                 mResult.mPreferredTaskDisplayArea);
221     }
222 
223     @Test
testUsesSourcesDisplayAreaIdPriorToTaskIfSet()224     public void testUsesSourcesDisplayAreaIdPriorToTaskIfSet() {
225         final TestDisplayContent freeformDisplay = createNewDisplayContent(
226                 WINDOWING_MODE_FREEFORM);
227         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
228                 WINDOWING_MODE_FULLSCREEN);
229 
230         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
231         ActivityRecord reusableActivity = createSourceActivity(fullscreenDisplay);
232         ActivityRecord source = createSourceActivity(freeformDisplay);
233 
234         assertEquals(RESULT_CONTINUE,
235                 new CalculateRequestBuilder()
236                         .setTask(reusableActivity.getTask())
237                         .setSource(source)
238                         .calculate());
239 
240         assertEquals(freeformDisplay.getDefaultTaskDisplayArea(),
241                 mResult.mPreferredTaskDisplayArea);
242     }
243 
244     @Test
testUsesTaskDisplayAreaIdIfSet()245     public void testUsesTaskDisplayAreaIdIfSet() {
246         final TestDisplayContent freeformDisplay = createNewDisplayContent(
247                 WINDOWING_MODE_FREEFORM);
248         ActivityRecord source = createSourceActivity(freeformDisplay);
249 
250         assertEquals(RESULT_CONTINUE,
251                 new CalculateRequestBuilder()
252                         .setTask(source.getTask())
253                         .calculate());
254 
255         assertEquals(freeformDisplay.getDefaultTaskDisplayArea(),
256                 mResult.mPreferredTaskDisplayArea);
257     }
258 
259     @Test
testUsesNoDisplaySourceHandoverDisplayIdIfSet()260     public void testUsesNoDisplaySourceHandoverDisplayIdIfSet() {
261         final TestDisplayContent freeformDisplay = createNewDisplayContent(
262                 WINDOWING_MODE_FREEFORM);
263         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
264                 WINDOWING_MODE_FULLSCREEN);
265 
266         mCurrent.mPreferredTaskDisplayArea = fullscreenDisplay.getDefaultTaskDisplayArea();
267         ActivityRecord reusableActivity = createSourceActivity(fullscreenDisplay);
268         ActivityRecord source = createSourceActivity(freeformDisplay);
269         source.mHandoverLaunchDisplayId = freeformDisplay.mDisplayId;
270         source.noDisplay = true;
271 
272         assertEquals(RESULT_CONTINUE,
273                 new CalculateRequestBuilder()
274                         .setTask(reusableActivity.getTask())
275                         .setSource(source)
276                         .calculate());
277 
278         assertEquals(freeformDisplay.getDefaultTaskDisplayArea(),
279                 mResult.mPreferredTaskDisplayArea);
280     }
281 
282     @Test
testUsesNoDisplaySourceHandoverDisplayAreaIdIfSet()283     public void testUsesNoDisplaySourceHandoverDisplayAreaIdIfSet() {
284         final TestDisplayContent freeformDisplay = createNewDisplayContent(
285                 WINDOWING_MODE_FREEFORM);
286         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
287                 WINDOWING_MODE_FULLSCREEN);
288 
289         mCurrent.mPreferredTaskDisplayArea = fullscreenDisplay.getDefaultTaskDisplayArea();
290         ActivityRecord reusableActivity = createSourceActivity(fullscreenDisplay);
291         ActivityRecord source = createSourceActivity(freeformDisplay);
292         source.mHandoverTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
293         source.noDisplay = true;
294 
295         assertEquals(RESULT_CONTINUE,
296                 new CalculateRequestBuilder()
297                         .setTask(reusableActivity.getTask())
298                         .setSource(source)
299                         .calculate());
300 
301         assertEquals(freeformDisplay.getDefaultTaskDisplayArea(),
302                 mResult.mPreferredTaskDisplayArea);
303     }
304 
305     @Test
testUsesDisplayAreaFromTopMostActivityInApplicationIfAvailable()306     public void testUsesDisplayAreaFromTopMostActivityInApplicationIfAvailable() {
307         final String processName = "processName";
308         final int uid = 124214;
309         final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
310         final TaskDisplayArea expectedDisplayArea = secondScreen.getDefaultTaskDisplayArea();
311         final WindowProcessController controller = mock(WindowProcessController.class);
312 
313         when(controller.getTopActivityDisplayArea()).thenReturn(expectedDisplayArea);
314 
315         when(mActivity.getProcessName()).thenReturn(processName);
316         when(mActivity.getUid()).thenReturn(uid);
317         doReturn(controller)
318                 .when(mAtm)
319                 .getProcessController(processName, uid);
320 
321         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
322 
323         assertEquals(expectedDisplayArea, mResult.mPreferredTaskDisplayArea);
324     }
325 
326     @Test
testUsesDisplayAreaFromLaunchingActivityIfApplicationLaunching()327     public void testUsesDisplayAreaFromLaunchingActivityIfApplicationLaunching() {
328         final String processName = "processName";
329         final int uid = 124214;
330         final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
331         final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea();
332         final WindowProcessController controller = mock(WindowProcessController.class);
333 
334         when(controller.getTopActivityDisplayArea()).thenReturn(expectedTaskDisplayArea);
335 
336         when(mActivity.getProcessName()).thenReturn(processName);
337         when(mActivity.getUid()).thenReturn(uid);
338         doReturn(null)
339                 .when(mAtm)
340                 .getProcessController(processName, uid);
341 
342         doReturn(controller)
343                 .when(mAtm)
344                 .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid);
345 
346         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
347 
348         assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea);
349     }
350 
351     @Test
testDisplayAreaFromLaunchingActivityTakesPrecedence()352     public void testDisplayAreaFromLaunchingActivityTakesPrecedence() {
353         final String processName = "processName";
354         final int uid = 124214;
355         final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
356         final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
357         final TaskDisplayArea firstTaskDisplayArea = firstScreen.getDefaultTaskDisplayArea();
358         final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea();
359         final WindowProcessController controllerForLaunching = mock(WindowProcessController.class);
360         final WindowProcessController controllerForApplication =
361                 mock(WindowProcessController.class);
362 
363         when(mActivity.getProcessName()).thenReturn(processName);
364         when(mActivity.getUid()).thenReturn(uid);
365 
366         when(controllerForApplication.getTopActivityDisplayArea()).thenReturn(firstTaskDisplayArea);
367         when(controllerForLaunching.getTopActivityDisplayArea())
368                 .thenReturn(expectedTaskDisplayArea);
369 
370         doReturn(controllerForApplication)
371                 .when(mAtm)
372                 .getProcessController(processName, uid);
373         doReturn(controllerForLaunching)
374                 .when(mAtm)
375                 .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid);
376 
377         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
378 
379         assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea);
380     }
381 
382     @Test
testUsesDisplayAreaOriginalProcessAsLastResort()383     public void testUsesDisplayAreaOriginalProcessAsLastResort() {
384         final TestDisplayContent firstScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
385         final TestDisplayContent secondScreen = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
386         final TaskDisplayArea expectedTaskDisplayArea = secondScreen.getDefaultTaskDisplayArea();
387         final Request request = new Request();
388         request.realCallingPid = 12412413;
389         request.realCallingUid = 235424;
390 
391         final WindowProcessController controller = mock(WindowProcessController.class);
392 
393         when(controller.getTopActivityDisplayArea()).thenReturn(expectedTaskDisplayArea);
394 
395         doReturn(null)
396                 .when(mAtm)
397                 .getProcessController(mActivity.processName, mActivity.info.applicationInfo.uid);
398 
399         doReturn(null)
400                 .when(mAtm)
401                 .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid);
402 
403         doReturn(controller)
404                 .when(mAtm)
405                 .getProcessController(request.realCallingPid, request.realCallingUid);
406 
407         assertEquals(RESULT_CONTINUE,
408                 new CalculateRequestBuilder().setRequest(request).calculate());
409 
410         assertEquals(expectedTaskDisplayArea, mResult.mPreferredTaskDisplayArea);
411     }
412 
413     @Test
testUsesDefaultDisplayAreaIfWindowProcessControllerIsNotPresent()414     public void testUsesDefaultDisplayAreaIfWindowProcessControllerIsNotPresent() {
415         doReturn(null)
416                 .when(mAtm)
417                 .getProcessController(mActivity.processName, mActivity.info.applicationInfo.uid);
418 
419         doReturn(null)
420                 .when(mAtm)
421                 .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid);
422 
423         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
424 
425         assertEquals(DEFAULT_DISPLAY, mResult.mPreferredTaskDisplayArea.getDisplayId());
426     }
427 
428     @Test
testOverridesDisplayAreaWithStandardTypeAndFullscreenMode()429     public void testOverridesDisplayAreaWithStandardTypeAndFullscreenMode() {
430         final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
431                 mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
432         final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
433                 ACTIVITY_TYPE_STANDARD);
434         launchRoot.mCreatedByOrganizer = true;
435 
436         secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN },
437                 new int[] { ACTIVITY_TYPE_STANDARD });
438 
439         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
440 
441         assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
442     }
443 
444     @Test
testOverridesDisplayAreaWithHomeTypeAndFullscreenMode()445     public void testOverridesDisplayAreaWithHomeTypeAndFullscreenMode() {
446         final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
447                 mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
448         final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
449                 ACTIVITY_TYPE_STANDARD);
450         launchRoot.mCreatedByOrganizer = true;
451 
452         mActivity.setActivityType(ACTIVITY_TYPE_HOME);
453         secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN },
454                 new int[] { ACTIVITY_TYPE_HOME });
455 
456         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
457 
458         assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
459     }
460 
461     @Test
testOverridesDisplayAreaWithStandardTypeAndFreeformMode()462     public void testOverridesDisplayAreaWithStandardTypeAndFreeformMode() {
463         final TestDisplayContent freeformDisplay = createNewDisplayContent(
464                 WINDOWING_MODE_FREEFORM);
465         final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay,
466                 mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
467         final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
468                 ACTIVITY_TYPE_STANDARD);
469         launchRoot.mCreatedByOrganizer = true;
470 
471         secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
472                 new int[] { ACTIVITY_TYPE_STANDARD });
473 
474         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
475         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
476 
477         assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
478     }
479 
480     @Test
testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayAreaToken()481     public void testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayAreaToken() {
482         final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
483                 mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
484         final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
485                 ACTIVITY_TYPE_STANDARD);
486         launchRoot.mCreatedByOrganizer = true;
487 
488         secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN },
489                 new int[] { ACTIVITY_TYPE_STANDARD });
490 
491         ActivityOptions options = ActivityOptions.makeBasic();
492         options.setLaunchTaskDisplayArea(
493                 mDefaultDisplay.getDefaultTaskDisplayArea().mRemoteToken.toWindowContainerToken());
494 
495         assertEquals(RESULT_CONTINUE,
496                 new CalculateRequestBuilder().setOptions(options).calculate());
497 
498         assertEquals(
499                 mDefaultDisplay.getDefaultTaskDisplayArea(), mResult.mPreferredTaskDisplayArea);
500     }
501 
502     @Test
testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayAreaFeatureId()503     public void testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayAreaFeatureId() {
504         final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay,
505                 mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
506         final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
507                 ACTIVITY_TYPE_STANDARD);
508         launchRoot.mCreatedByOrganizer = true;
509 
510         secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN },
511                 new int[] { ACTIVITY_TYPE_STANDARD });
512 
513         ActivityOptions options = ActivityOptions.makeBasic();
514         options.setLaunchTaskDisplayAreaFeatureId(
515                 mDefaultDisplay.getDefaultTaskDisplayArea().mFeatureId);
516 
517         assertEquals(RESULT_CONTINUE,
518                 new CalculateRequestBuilder().setOptions(options).calculate());
519 
520         assertEquals(
521                 mDefaultDisplay.getDefaultTaskDisplayArea(), mResult.mPreferredTaskDisplayArea);
522     }
523 
524     @Test
testUsesOptionsDisplayAreaFeatureIdDisplayIdNotSet()525     public void testUsesOptionsDisplayAreaFeatureIdDisplayIdNotSet() {
526         final TestDisplayContent secondaryDisplay = createNewDisplayContent(
527                 WINDOWING_MODE_FULLSCREEN);
528         final TaskDisplayArea tdaOnSecondaryDisplay = createTaskDisplayArea(secondaryDisplay,
529                 mWm, "TestTaskDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
530 
531         final TaskDisplayArea tdaOnDefaultDisplay = createTaskDisplayArea(mDefaultDisplay,
532                 mWm, "TestTaskDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
533 
534         mCurrent.mPreferredTaskDisplayArea = tdaOnSecondaryDisplay;
535         ActivityRecord source = createSourceActivity(tdaOnSecondaryDisplay,
536                 WINDOWING_MODE_FULLSCREEN);
537 
538         ActivityOptions options = ActivityOptions.makeBasic();
539         options.setLaunchTaskDisplayAreaFeatureId(tdaOnSecondaryDisplay.mFeatureId);
540 
541         assertEquals(RESULT_CONTINUE,
542                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
543         // Display id wasn't specified in ActivityOptions - the activity should be placed on the
544         // default display, into the TaskDisplayArea with the same feature id.
545         assertEquals(tdaOnDefaultDisplay, mResult.mPreferredTaskDisplayArea);
546     }
547 
548     @Test
testRecalculateFreeformInitialBoundsWithOverrideDisplayArea()549     public void testRecalculateFreeformInitialBoundsWithOverrideDisplayArea() {
550         final TestDisplayContent freeformDisplay = createNewDisplayContent(
551                 WINDOWING_MODE_FREEFORM);
552         final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay,
553                 mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
554         secondaryDisplayArea.setBounds(DISPLAY_BOUNDS.width() / 2, 0,
555                         DISPLAY_BOUNDS.width(), DISPLAY_BOUNDS.height());
556         final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
557                 ACTIVITY_TYPE_STANDARD);
558         launchRoot.mCreatedByOrganizer = true;
559         secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
560                 new int[] { ACTIVITY_TYPE_STANDARD });
561         final Rect secondaryDAStableBounds = new Rect();
562         secondaryDisplayArea.getStableRect(secondaryDAStableBounds);
563 
564         // Specify the display and provide a layout so that it will be set to freeform bounds.
565         final ActivityOptions options = ActivityOptions.makeBasic()
566                 .setLaunchDisplayId(freeformDisplay.getDisplayId());
567         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
568                 .setGravity(Gravity.LEFT).build();
569 
570         assertEquals(RESULT_CONTINUE,
571                 new CalculateRequestBuilder().setOptions(options).setLayout(layout).calculate());
572 
573         assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
574         assertTrue(secondaryDAStableBounds.contains(mResult.mBounds));
575     }
576 
577     @Test
testRecalculateFreeformInitialBoundsWithOverrideDisplayArea_unresizableApp()578     public void testRecalculateFreeformInitialBoundsWithOverrideDisplayArea_unresizableApp() {
579         mAtm.mDevEnableNonResizableMultiWindow = true;
580 
581         final TestDisplayContent freeformDisplay = createNewDisplayContent(
582                 WINDOWING_MODE_FREEFORM);
583         final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay,
584                 mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST);
585         secondaryDisplayArea.setBounds(DISPLAY_BOUNDS.width() / 2, 0,
586                 DISPLAY_BOUNDS.width(), DISPLAY_BOUNDS.height());
587         final Task launchRoot = createTask(secondaryDisplayArea, WINDOWING_MODE_FULLSCREEN,
588                 ACTIVITY_TYPE_STANDARD);
589         launchRoot.mCreatedByOrganizer = true;
590         secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM },
591                 new int[] { ACTIVITY_TYPE_STANDARD });
592         final Rect secondaryDAStableBounds = new Rect();
593         secondaryDisplayArea.getStableRect(secondaryDAStableBounds);
594 
595         // The bounds will get updated for unresizable with opposite orientation on freeform display
596         final Rect displayBounds = new Rect(freeformDisplay.getBounds());
597         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
598         mActivity.info.screenOrientation = displayBounds.width() > displayBounds.height()
599                 ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE;
600         final ActivityOptions options = ActivityOptions.makeBasic()
601                 .setLaunchDisplayId(freeformDisplay.getDisplayId());
602 
603         assertEquals(RESULT_CONTINUE,
604                 new CalculateRequestBuilder().setOptions(options).calculate());
605 
606         assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea);
607         assertTrue(secondaryDAStableBounds.contains(mResult.mBounds));
608     }
609 
610     // =====================================
611     // Launch Windowing Mode Related Tests
612     // =====================================
613     @Test
testBoundsInOptionsInfersFreeformOnFreeformDisplay()614     public void testBoundsInOptionsInfersFreeformOnFreeformDisplay() {
615         final TestDisplayContent freeformDisplay = createNewDisplayContent(
616                 WINDOWING_MODE_FREEFORM);
617 
618         final ActivityOptions options = ActivityOptions.makeBasic();
619         options.setLaunchBounds(new Rect(0, 0, 100, 100));
620 
621         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
622 
623         assertEquals(RESULT_CONTINUE,
624                 new CalculateRequestBuilder().setOptions(options).calculate());
625 
626         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
627                 WINDOWING_MODE_FREEFORM);
628     }
629 
630     @Test
testBoundsInOptionsInfersFreeformWithResizeableActivity()631     public void testBoundsInOptionsInfersFreeformWithResizeableActivity() {
632         final ActivityOptions options = ActivityOptions.makeBasic();
633         options.setLaunchBounds(new Rect(0, 0, 100, 100));
634 
635         mCurrent.mPreferredTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
636 
637         assertEquals(RESULT_CONTINUE,
638                 new CalculateRequestBuilder().setOptions(options).calculate());
639 
640         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
641                 WINDOWING_MODE_FULLSCREEN);
642     }
643 
644     @Test
testBoundsInOptionsInfersFullscreenWithBoundsOnFreeformSupportFullscreenDisplay()645     public void testBoundsInOptionsInfersFullscreenWithBoundsOnFreeformSupportFullscreenDisplay() {
646         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
647                 WINDOWING_MODE_FULLSCREEN);
648         mAtm.mTaskSupervisor.mService.mSupportsFreeformWindowManagement = true;
649 
650         final ActivityOptions options = ActivityOptions.makeBasic();
651         final Rect expectedBounds = new Rect(0, 0, 100, 100);
652         options.setLaunchBounds(expectedBounds);
653 
654         mCurrent.mPreferredTaskDisplayArea = fullscreenDisplay.getDefaultTaskDisplayArea();
655 
656         assertEquals(RESULT_CONTINUE,
657                 new CalculateRequestBuilder().setOptions(options).calculate());
658 
659         // Setting bounds shouldn't lead to freeform windowing mode on fullscreen display by
660         // default (even with freeform support), but we need to check here if the bounds is set even
661         // with fullscreen windowing mode in case it's restored later.
662         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
663                 WINDOWING_MODE_FULLSCREEN);
664         assertEquals(expectedBounds, mResult.mBounds);
665     }
666 
667     @Test
testInheritsFreeformModeFromSourceOnFullscreenDisplay()668     public void testInheritsFreeformModeFromSourceOnFullscreenDisplay() {
669         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
670                 WINDOWING_MODE_FULLSCREEN);
671         final ActivityRecord source = createSourceActivity(fullscreenDisplay);
672         source.getTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
673 
674         assertEquals(RESULT_CONTINUE,
675                 new CalculateRequestBuilder().setSource(source).calculate());
676 
677         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
678                 WINDOWING_MODE_FULLSCREEN);
679     }
680 
681     @Test
testInheritsSourceTaskWindowingModeWhenActivityIsInDifferentWindowingMode()682     public void testInheritsSourceTaskWindowingModeWhenActivityIsInDifferentWindowingMode() {
683         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
684                 WINDOWING_MODE_FULLSCREEN);
685         final ActivityRecord source = createSourceActivity(fullscreenDisplay);
686         source.setWindowingMode(WINDOWING_MODE_PINNED);
687         source.getTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
688 
689         assertEquals(RESULT_CONTINUE,
690                 new CalculateRequestBuilder().setSource(source).calculate());
691 
692         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
693                 WINDOWING_MODE_FULLSCREEN);
694     }
695 
696     @Test
testDoesNotInheritsSourceTaskWindowingModeWhenActivityIsInFreeformWindowingMode()697     public void testDoesNotInheritsSourceTaskWindowingModeWhenActivityIsInFreeformWindowingMode() {
698         // The activity could end up in different windowing mode state after calling finish()
699         // while the task would still hold the WINDOWING_MODE_PINNED state, or in other words
700         // be still in the Picture in Picture mode.
701         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
702                 WINDOWING_MODE_FULLSCREEN);
703         final ActivityRecord source = createSourceActivity(fullscreenDisplay);
704         source.setWindowingMode(WINDOWING_MODE_FREEFORM);
705         source.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
706 
707         assertEquals(RESULT_CONTINUE,
708                 new CalculateRequestBuilder().setSource(source).calculate());
709 
710         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
711                 WINDOWING_MODE_FULLSCREEN);
712     }
713 
714 
715     @Test
testKeepsPictureInPictureLaunchModeInOptions()716     public void testKeepsPictureInPictureLaunchModeInOptions() {
717         final TestDisplayContent freeformDisplay = createNewDisplayContent(
718                 WINDOWING_MODE_FREEFORM);
719 
720         final ActivityOptions options = ActivityOptions.makeBasic();
721         options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
722 
723         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
724 
725         assertEquals(RESULT_CONTINUE,
726                 new CalculateRequestBuilder().setOptions(options).calculate());
727 
728         assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
729                 WINDOWING_MODE_FREEFORM);
730     }
731 
732     @Test
testKeepsPictureInPictureLaunchModeWithBoundsInOptions()733     public void testKeepsPictureInPictureLaunchModeWithBoundsInOptions() {
734         final TestDisplayContent freeformDisplay = createNewDisplayContent(
735                 WINDOWING_MODE_FREEFORM);
736 
737         final ActivityOptions options = ActivityOptions.makeBasic();
738         options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
739         options.setLaunchBounds(new Rect(0, 0, 100, 100));
740 
741         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
742 
743         assertEquals(RESULT_CONTINUE,
744                 new CalculateRequestBuilder().setOptions(options).calculate());
745 
746         assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
747                 WINDOWING_MODE_FREEFORM);
748     }
749 
750     @Test
testKeepsFullscreenLaunchModeInOptionsOnNonFreeformDisplay()751     public void testKeepsFullscreenLaunchModeInOptionsOnNonFreeformDisplay() {
752         final ActivityOptions options = ActivityOptions.makeBasic();
753         options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
754 
755         mCurrent.mPreferredTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
756 
757         assertEquals(RESULT_CONTINUE,
758                 new CalculateRequestBuilder().setOptions(options).calculate());
759 
760         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
761                 WINDOWING_MODE_FULLSCREEN);
762     }
763 
764     @Test
testNonEmptyLayoutInfersFreeformOnFreeformDisplay()765     public void testNonEmptyLayoutInfersFreeformOnFreeformDisplay() {
766         final TestDisplayContent freeformDisplay = createNewDisplayContent(
767                 WINDOWING_MODE_FREEFORM);
768 
769         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
770 
771         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
772                 .setWidth(120).setHeight(80).build();
773 
774         assertEquals(RESULT_CONTINUE,
775                 new CalculateRequestBuilder().setLayout(layout).calculate());
776 
777         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
778                 WINDOWING_MODE_FREEFORM);
779     }
780 
781     @Test
testLayoutWithGravityAndEmptySizeInfersFreeformAndRespectsCurrentSize()782     public void testLayoutWithGravityAndEmptySizeInfersFreeformAndRespectsCurrentSize() {
783         final TestDisplayContent freeformDisplay = createNewDisplayContent(
784                 WINDOWING_MODE_FREEFORM);
785 
786         final Rect expectedLaunchBounds = new Rect(0, 0, 200, 100);
787 
788         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
789         mCurrent.mBounds.set(expectedLaunchBounds);
790 
791         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
792                 .setGravity(Gravity.LEFT).build();
793 
794         assertEquals(RESULT_CONTINUE,
795                 new CalculateRequestBuilder().setLayout(layout).calculate());
796 
797         assertEquals(expectedLaunchBounds.width(), mResult.mBounds.width());
798         assertEquals(expectedLaunchBounds.height(), mResult.mBounds.height());
799 
800         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
801                 WINDOWING_MODE_FREEFORM);
802     }
803 
804     @Test
testNonEmptyLayoutUsesFullscreenWithResizeableActivity()805     public void testNonEmptyLayoutUsesFullscreenWithResizeableActivity() {
806         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
807                 .setWidth(120).setHeight(80).build();
808 
809         mCurrent.mPreferredTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
810 
811         assertEquals(RESULT_CONTINUE,
812                 new CalculateRequestBuilder().setLayout(layout).calculate());
813 
814         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
815                 WINDOWING_MODE_FULLSCREEN);
816     }
817 
818     @Test
testLaunchesFullscreenOnFullscreenDisplayWithFreeformHistory()819     public void testLaunchesFullscreenOnFullscreenDisplayWithFreeformHistory() {
820         mCurrent.mPreferredTaskDisplayArea = null;
821         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
822         mCurrent.mBounds.set(0, 0, 200, 100);
823 
824         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
825 
826         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
827                 WINDOWING_MODE_FULLSCREEN);
828     }
829 
830     @Test
testRespectsFullyResolvedCurrentParam_Fullscreen()831     public void testRespectsFullyResolvedCurrentParam_Fullscreen() {
832         final TestDisplayContent freeformDisplay = createNewDisplayContent(
833                 WINDOWING_MODE_FREEFORM);
834 
835         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
836         mCurrent.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
837 
838         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
839 
840         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
841                 WINDOWING_MODE_FREEFORM);
842     }
843 
844     @Test
testRespectsModeFromFullyResolvedCurrentParam_NonEmptyBounds()845     public void testRespectsModeFromFullyResolvedCurrentParam_NonEmptyBounds() {
846         final TestDisplayContent freeformDisplay = createNewDisplayContent(
847                 WINDOWING_MODE_FREEFORM);
848 
849         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
850         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
851         mCurrent.mBounds.set(0, 0, 200, 100);
852 
853         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
854 
855         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
856                 WINDOWING_MODE_FREEFORM);
857     }
858 
859     @Test
testForceMaximizesUnresizeableApp()860     public void testForceMaximizesUnresizeableApp() {
861         mAtm.mDevEnableNonResizableMultiWindow = false;
862         final TestDisplayContent freeformDisplay = createNewDisplayContent(
863                 WINDOWING_MODE_FREEFORM);
864 
865         final ActivityOptions options = ActivityOptions.makeBasic();
866         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
867         options.setLaunchBounds(new Rect(0, 0, 200, 100));
868 
869         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
870         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
871         mCurrent.mBounds.set(0, 0, 200, 100);
872 
873         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
874 
875         assertEquals(RESULT_CONTINUE,
876                 new CalculateRequestBuilder().setOptions(options).calculate());
877 
878         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
879                 WINDOWING_MODE_FREEFORM);
880     }
881 
882     @Test
testLaunchesPortraitSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat()883     public void testLaunchesPortraitSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat() {
884         mAtm.mDevEnableNonResizableMultiWindow = true;
885         final TestDisplayContent freeformDisplay = createNewDisplayContent(
886                 WINDOWING_MODE_FREEFORM);
887 
888         Rect expectedLaunchBounds = new Rect(0, 0, 100, 200);
889 
890         final ActivityOptions options = ActivityOptions.makeBasic();
891         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
892         options.setLaunchBounds(expectedLaunchBounds);
893 
894         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
895         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
896         mCurrent.mBounds.set(expectedLaunchBounds);
897 
898         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
899         mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
900 
901         assertEquals(RESULT_CONTINUE,
902                 new CalculateRequestBuilder().setOptions(options).calculate());
903 
904         assertEquals(expectedLaunchBounds, mResult.mBounds);
905 
906         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
907                 WINDOWING_MODE_FREEFORM);
908     }
909 
910     @Test
testLaunchesLandscapeSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat()911     public void testLaunchesLandscapeSizeCompatOnFreeformLandscapeDisplayWithFreeformSizeCompat() {
912         mAtm.mDevEnableNonResizableMultiWindow = true;
913         final TestDisplayContent freeformDisplay = createNewDisplayContent(
914                 WINDOWING_MODE_FREEFORM);
915         final ActivityOptions options = ActivityOptions.makeBasic();
916         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
917         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
918         mActivity.info.screenOrientation = SCREEN_ORIENTATION_LANDSCAPE;
919         assertEquals(RESULT_CONTINUE,
920                 new CalculateRequestBuilder().setOptions(options).calculate());
921 
922         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
923                 WINDOWING_MODE_FREEFORM);
924     }
925 
926     @Test
testLaunchesPortraitUnresizableOnFreeformDisplayWithFreeformSizeCompat()927     public void testLaunchesPortraitUnresizableOnFreeformDisplayWithFreeformSizeCompat() {
928         mAtm.mDevEnableNonResizableMultiWindow = true;
929         final TestDisplayContent freeformDisplay = createNewDisplayContent(
930                 WINDOWING_MODE_FREEFORM);
931         final ActivityOptions options = ActivityOptions.makeBasic();
932         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
933         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
934         mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
935         assertEquals(RESULT_CONTINUE,
936                 new CalculateRequestBuilder().setOptions(options).calculate());
937 
938         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
939                 WINDOWING_MODE_FREEFORM);
940     }
941 
942     @Test
testSkipsForceMaximizingAppsOnNonFreeformDisplay()943     public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
944         final ActivityOptions options = ActivityOptions.makeBasic();
945         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
946         options.setLaunchBounds(new Rect(0, 0, 200, 100));
947 
948         mCurrent.mPreferredTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
949         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
950         mCurrent.mBounds.set(0, 0, 200, 100);
951 
952         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
953 
954         assertEquals(RESULT_CONTINUE,
955                 new CalculateRequestBuilder().setOptions(options).calculate());
956 
957         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
958                 WINDOWING_MODE_FULLSCREEN);
959     }
960 
961     @Test
testUsesFullscreenOnNonFreeformDisplay()962     public void testUsesFullscreenOnNonFreeformDisplay() {
963         final ActivityOptions options = ActivityOptions.makeBasic();
964         options.setLaunchDisplayId(DEFAULT_DISPLAY);
965 
966         assertEquals(RESULT_CONTINUE,
967                 new CalculateRequestBuilder().setOptions(options).calculate());
968 
969         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
970                 WINDOWING_MODE_FULLSCREEN);
971     }
972 
973     @Test
testUsesFullscreenWhenRequestedOnFreeformDisplay()974     public void testUsesFullscreenWhenRequestedOnFreeformDisplay() {
975         final TestDisplayContent freeformDisplay = createNewDisplayContent(
976                 WINDOWING_MODE_FREEFORM);
977 
978         final ActivityOptions options = ActivityOptions.makeBasic();
979         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
980         options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
981 
982         assertEquals(RESULT_CONTINUE,
983                 new CalculateRequestBuilder().setOptions(options).calculate());
984 
985         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
986                 WINDOWING_MODE_FREEFORM);
987     }
988 
989     @Test
testUsesFreeformByDefaultForPostNApp()990     public void testUsesFreeformByDefaultForPostNApp() {
991         final TestDisplayContent freeformDisplay = createNewDisplayContent(
992                 WINDOWING_MODE_FREEFORM);
993 
994         final ActivityOptions options = ActivityOptions.makeBasic();
995         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
996 
997         assertEquals(RESULT_CONTINUE,
998                 new CalculateRequestBuilder().setOptions(options).calculate());
999 
1000         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
1001                 WINDOWING_MODE_FREEFORM);
1002     }
1003 
1004     @Test
testUsesFreeformByDefaultForPreNResizeableAppWithoutOrientationRequest()1005     public void testUsesFreeformByDefaultForPreNResizeableAppWithoutOrientationRequest() {
1006         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1007                 WINDOWING_MODE_FREEFORM);
1008 
1009         final ActivityOptions options = ActivityOptions.makeBasic();
1010         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1011 
1012         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1013 
1014         assertEquals(RESULT_CONTINUE,
1015                 new CalculateRequestBuilder().setOptions(options).calculate());
1016 
1017         assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
1018                 WINDOWING_MODE_FREEFORM);
1019     }
1020 
1021     @Test
testSkipsFreeformForPreNResizeableAppOnNonFullscreenDisplay()1022     public void testSkipsFreeformForPreNResizeableAppOnNonFullscreenDisplay() {
1023         final ActivityOptions options = ActivityOptions.makeBasic();
1024         options.setLaunchDisplayId(DEFAULT_DISPLAY);
1025 
1026         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1027 
1028         assertEquals(RESULT_CONTINUE,
1029                 new CalculateRequestBuilder().setOptions(options).calculate());
1030 
1031         assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
1032                 WINDOWING_MODE_FULLSCREEN);
1033     }
1034 
1035     // ================================
1036     // Launching Bounds Related Tests
1037     // ===============================
1038     @Test
testKeepsBoundsWithPictureInPictureLaunchModeInOptions()1039     public void testKeepsBoundsWithPictureInPictureLaunchModeInOptions() {
1040         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1041                 WINDOWING_MODE_FREEFORM);
1042 
1043         final ActivityOptions options = ActivityOptions.makeBasic();
1044         options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
1045 
1046         final Rect expected = new Rect(0, 0, 100, 100);
1047         options.setLaunchBounds(expected);
1048 
1049         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1050 
1051         assertEquals(RESULT_CONTINUE,
1052                 new CalculateRequestBuilder().setOptions(options).calculate());
1053 
1054         assertEquals(expected, mResult.mBounds);
1055     }
1056 
1057     @Test
testKeepsBoundsForMultiWindowModeInOptions()1058     public void testKeepsBoundsForMultiWindowModeInOptions() {
1059         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1060                 WINDOWING_MODE_FULLSCREEN);
1061 
1062         final ActivityOptions options = ActivityOptions.makeBasic();
1063         options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
1064 
1065         final Rect expected = new Rect(0, 0, 100, 100);
1066         options.setLaunchBounds(expected);
1067 
1068         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1069 
1070         assertEquals(RESULT_CONTINUE,
1071                 new CalculateRequestBuilder().setOptions(options).calculate());
1072 
1073         assertEquals(expected, mResult.mBounds);
1074     }
1075 
1076     @Test
testRespectsLaunchBoundsWithFreeformSourceOnFullscreenDisplay()1077     public void testRespectsLaunchBoundsWithFreeformSourceOnFullscreenDisplay() {
1078         final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
1079                 WINDOWING_MODE_FULLSCREEN);
1080         final ActivityRecord source = createSourceActivity(fullscreenDisplay);
1081         source.getTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
1082         // Set some bounds to avoid conflict with the other activity.
1083         source.setBounds(100, 100, 200, 200);
1084 
1085         final ActivityOptions options = ActivityOptions.makeBasic();
1086         final Rect expected = new Rect(0, 0, 150, 150);
1087         options.setLaunchBounds(expected);
1088 
1089         assertEquals(RESULT_CONTINUE,
1090                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
1091 
1092         assertEquals(expected, mResult.mBounds);
1093     }
1094 
1095     @Test
testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity()1096     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity() {
1097         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1098                 WINDOWING_MODE_FREEFORM);
1099 
1100         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1101 
1102         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1103                 .setGravity(Gravity.LEFT).build();
1104 
1105         assertEquals(RESULT_CONTINUE,
1106                 new CalculateRequestBuilder().setLayout(layout).calculate());
1107 
1108         assertEquals(DISPLAY_STABLE_BOUNDS.left, mResult.mBounds.left);
1109     }
1110 
1111     @Test
testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity()1112     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity() {
1113         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1114                 WINDOWING_MODE_FREEFORM);
1115 
1116         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1117 
1118         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1119                 .setGravity(Gravity.TOP).build();
1120 
1121         assertEquals(RESULT_CONTINUE,
1122                 new CalculateRequestBuilder().setLayout(layout).calculate());
1123 
1124         assertEquals(DISPLAY_STABLE_BOUNDS.top, mResult.mBounds.top);
1125     }
1126 
1127     @Test
testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity()1128     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity() {
1129         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1130                 WINDOWING_MODE_FREEFORM);
1131 
1132         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1133 
1134         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1135                 .setGravity(Gravity.TOP | Gravity.LEFT).build();
1136 
1137         assertEquals(RESULT_CONTINUE,
1138                 new CalculateRequestBuilder().setLayout(layout).calculate());
1139 
1140         assertEquals(DISPLAY_STABLE_BOUNDS.left, mResult.mBounds.left);
1141         assertEquals(DISPLAY_STABLE_BOUNDS.top, mResult.mBounds.top);
1142     }
1143 
1144     @Test
testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity()1145     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity() {
1146         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1147                 WINDOWING_MODE_FREEFORM);
1148 
1149         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1150 
1151         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1152                 .setGravity(Gravity.RIGHT).build();
1153 
1154         assertEquals(RESULT_CONTINUE,
1155                 new CalculateRequestBuilder().setLayout(layout).calculate());
1156 
1157         assertEquals(DISPLAY_STABLE_BOUNDS.right, mResult.mBounds.right);
1158     }
1159 
1160     @Test
testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity()1161     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity() {
1162         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1163                 WINDOWING_MODE_FREEFORM);
1164 
1165         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1166 
1167         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1168                 .setGravity(Gravity.BOTTOM).build();
1169 
1170         assertEquals(RESULT_CONTINUE,
1171                 new CalculateRequestBuilder().setLayout(layout).calculate());
1172 
1173         assertEquals(DISPLAY_STABLE_BOUNDS.bottom, mResult.mBounds.bottom);
1174     }
1175 
1176     @Test
testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity()1177     public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity() {
1178         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1179                 WINDOWING_MODE_FREEFORM);
1180 
1181         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1182 
1183         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1184                 .setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
1185 
1186         assertEquals(RESULT_CONTINUE,
1187                 new CalculateRequestBuilder().setLayout(layout).calculate());
1188 
1189         assertEquals(DISPLAY_STABLE_BOUNDS.right, mResult.mBounds.right);
1190         assertEquals(DISPLAY_STABLE_BOUNDS.bottom, mResult.mBounds.bottom);
1191     }
1192 
1193     @Test
testNonEmptyLayoutBoundsOnFreeformDisplay_CenterToDisplay()1194     public void testNonEmptyLayoutBoundsOnFreeformDisplay_CenterToDisplay() {
1195         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1196                 WINDOWING_MODE_FREEFORM);
1197 
1198         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1199 
1200         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1201                 .setWidth(120).setHeight(80).build();
1202 
1203         assertEquals(RESULT_CONTINUE,
1204                 new CalculateRequestBuilder().setLayout(layout).calculate());
1205 
1206         assertEquals(new Rect(800, 400, 920, 480), mResult.mBounds);
1207     }
1208 
1209     @Test
testNonEmptyLayoutBoundsOnFreeformDisplay_LeftGravity()1210     public void testNonEmptyLayoutBoundsOnFreeformDisplay_LeftGravity() {
1211         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1212                 WINDOWING_MODE_FREEFORM);
1213 
1214         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1215 
1216         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1217                 .setWidth(120).setHeight(80).setGravity(Gravity.LEFT).build();
1218 
1219         assertEquals(RESULT_CONTINUE,
1220                 new CalculateRequestBuilder().setLayout(layout).calculate());
1221 
1222         assertEquals(new Rect(100, 400, 220, 480), mResult.mBounds);
1223     }
1224 
1225     @Test
testNonEmptyLayoutBoundsOnFreeformDisplay_TopGravity()1226     public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopGravity() {
1227         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1228                 WINDOWING_MODE_FREEFORM);
1229 
1230         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1231 
1232         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1233                 .setWidth(120).setHeight(80).setGravity(Gravity.TOP).build();
1234 
1235         assertEquals(RESULT_CONTINUE,
1236                 new CalculateRequestBuilder().setLayout(layout).calculate());
1237 
1238         assertEquals(new Rect(800, 200, 920, 280), mResult.mBounds);
1239     }
1240 
1241     @Test
testNonEmptyLayoutBoundsOnFreeformDisplay_TopLeftGravity()1242     public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopLeftGravity() {
1243         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1244                 WINDOWING_MODE_FREEFORM);
1245 
1246         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1247 
1248         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1249                 .setWidth(120).setHeight(80).setGravity(Gravity.TOP | Gravity.LEFT).build();
1250 
1251         assertEquals(RESULT_CONTINUE,
1252                 new CalculateRequestBuilder().setLayout(layout).calculate());
1253 
1254         assertEquals(new Rect(100, 200, 220, 280), mResult.mBounds);
1255     }
1256 
1257     @Test
testNonEmptyLayoutBoundsOnFreeformDisplay_RightGravity()1258     public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightGravity() {
1259         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1260                 WINDOWING_MODE_FREEFORM);
1261 
1262         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1263 
1264         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1265                 .setWidth(120).setHeight(80).setGravity(Gravity.RIGHT).build();
1266 
1267         assertEquals(RESULT_CONTINUE,
1268                 new CalculateRequestBuilder().setLayout(layout).calculate());
1269 
1270         assertEquals(new Rect(1500, 400, 1620, 480), mResult.mBounds);
1271     }
1272 
1273     @Test
testNonEmptyLayoutBoundsOnFreeformDisplay_BottomGravity()1274     public void testNonEmptyLayoutBoundsOnFreeformDisplay_BottomGravity() {
1275         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1276                 WINDOWING_MODE_FREEFORM);
1277 
1278         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1279 
1280         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1281                 .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM).build();
1282 
1283         assertEquals(RESULT_CONTINUE,
1284                 new CalculateRequestBuilder().setLayout(layout).calculate());
1285 
1286         assertEquals(new Rect(800, 600, 920, 680), mResult.mBounds);
1287     }
1288 
1289     @Test
testNonEmptyLayoutBoundsOnFreeformDisplay_RightBottomGravity()1290     public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightBottomGravity() {
1291         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1292                 WINDOWING_MODE_FREEFORM);
1293 
1294         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1295 
1296         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1297                 .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
1298 
1299         assertEquals(RESULT_CONTINUE,
1300                 new CalculateRequestBuilder().setLayout(layout).calculate());
1301 
1302         assertEquals(new Rect(1500, 600, 1620, 680), mResult.mBounds);
1303     }
1304 
1305     @Test
testNonEmptyLayoutFractionBoundsOnFreeformDisplay()1306     public void testNonEmptyLayoutFractionBoundsOnFreeformDisplay() {
1307         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1308                 WINDOWING_MODE_FREEFORM);
1309 
1310         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1311 
1312         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1313                 .setWidthFraction(0.125f).setHeightFraction(0.1f).build();
1314 
1315         assertEquals(RESULT_CONTINUE,
1316                 new CalculateRequestBuilder().setLayout(layout).calculate());
1317 
1318         assertEquals(new Rect(765, 416, 955, 464), mResult.mBounds);
1319     }
1320 
1321     @Test
testRespectBoundsFromFullyResolvedCurrentParam_NonEmptyBounds()1322     public void testRespectBoundsFromFullyResolvedCurrentParam_NonEmptyBounds() {
1323         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1324                 WINDOWING_MODE_FREEFORM);
1325 
1326         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1327         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
1328         mCurrent.mBounds.set(0, 0, 200, 100);
1329 
1330         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
1331 
1332         assertEquals(new Rect(0, 0, 200, 100), mResult.mBounds);
1333     }
1334 
1335     @Test
testReturnBoundsForFullscreenWindowingMode()1336     public void testReturnBoundsForFullscreenWindowingMode() {
1337         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1338                 WINDOWING_MODE_FREEFORM);
1339 
1340         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1341         mCurrent.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
1342         mCurrent.mBounds.set(0, 0, 200, 100);
1343 
1344         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
1345 
1346         assertEquals(new Rect(0, 0, 200, 100), mResult.mBounds);
1347     }
1348 
1349     @Test
testUsesDisplayOrientationForNoSensorOrientation()1350     public void testUsesDisplayOrientationForNoSensorOrientation() {
1351         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1352                 WINDOWING_MODE_FREEFORM);
1353 
1354         final ActivityOptions options = ActivityOptions.makeBasic();
1355         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1356         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
1357 
1358         mActivity.info.screenOrientation = SCREEN_ORIENTATION_NOSENSOR;
1359 
1360         assertEquals(RESULT_CONTINUE,
1361                 new CalculateRequestBuilder().setOptions(options).calculate());
1362 
1363         final int orientationForDisplay = orientationFromBounds(freeformDisplay.getBounds());
1364         final int orientationForTask = orientationFromBounds(mResult.mBounds);
1365         assertEquals("Launch bounds orientation should be the same as the display, but"
1366                         + " display orientation is "
1367                         + ActivityInfo.screenOrientationToString(orientationForDisplay)
1368                         + " launch bounds orientation is "
1369                         + ActivityInfo.screenOrientationToString(orientationForTask),
1370                 orientationForDisplay, orientationForTask);
1371     }
1372 
1373     @Test
testRespectsAppRequestedOrientation_Landscape()1374     public void testRespectsAppRequestedOrientation_Landscape() {
1375         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1376                 WINDOWING_MODE_FREEFORM);
1377 
1378         final ActivityOptions options = ActivityOptions.makeBasic();
1379         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1380         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
1381 
1382         mActivity.info.screenOrientation = SCREEN_ORIENTATION_LANDSCAPE;
1383 
1384         assertEquals(RESULT_CONTINUE,
1385                 new CalculateRequestBuilder().setOptions(options).calculate());
1386 
1387         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, orientationFromBounds(mResult.mBounds));
1388     }
1389 
1390     @Test
testRespectsAppRequestedOrientation_Portrait()1391     public void testRespectsAppRequestedOrientation_Portrait() {
1392         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1393                 WINDOWING_MODE_FREEFORM);
1394 
1395         final ActivityOptions options = ActivityOptions.makeBasic();
1396         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1397         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
1398 
1399         mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
1400 
1401         assertEquals(RESULT_CONTINUE,
1402                 new CalculateRequestBuilder().setOptions(options).calculate());
1403 
1404         assertEquals(SCREEN_ORIENTATION_PORTRAIT, orientationFromBounds(mResult.mBounds));
1405     }
1406 
1407     @Test
testDefaultSizeSmallerThanBigScreen()1408     public void testDefaultSizeSmallerThanBigScreen() {
1409         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1410                 WINDOWING_MODE_FREEFORM);
1411 
1412         final ActivityOptions options = ActivityOptions.makeBasic();
1413         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1414 
1415         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1416 
1417         assertEquals(RESULT_CONTINUE,
1418                 new CalculateRequestBuilder().setOptions(options).calculate());
1419 
1420         final int resultWidth = mResult.mBounds.width();
1421         final int displayWidth = freeformDisplay.getBounds().width();
1422         assertTrue("Result width " + resultWidth + " is not smaller than " + displayWidth,
1423                 resultWidth < displayWidth);
1424 
1425         final int resultHeight = mResult.mBounds.height();
1426         final int displayHeight = freeformDisplay.getBounds().height();
1427         assertTrue("Result width " + resultHeight + " is not smaller than "
1428                         + displayHeight, resultHeight < displayHeight);
1429     }
1430 
1431     @Test
testDefaultFreeformSizeCenteredToDisplay()1432     public void testDefaultFreeformSizeCenteredToDisplay() {
1433         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1434                 WINDOWING_MODE_FREEFORM);
1435 
1436         final ActivityOptions options = ActivityOptions.makeBasic();
1437         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1438 
1439         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1440 
1441         assertEquals(RESULT_CONTINUE,
1442                 new CalculateRequestBuilder().setOptions(options).calculate());
1443 
1444         assertEquals("Distance to left and right should be equal.",
1445                 mResult.mBounds.left - DISPLAY_STABLE_BOUNDS.left,
1446                 DISPLAY_STABLE_BOUNDS.right - mResult.mBounds.right, /* delta */ 1);
1447         assertEquals("Distance to top and bottom should be equal.",
1448                 mResult.mBounds.top - DISPLAY_STABLE_BOUNDS.top,
1449                 DISPLAY_STABLE_BOUNDS.bottom - mResult.mBounds.bottom, /* delta */ 1);
1450     }
1451 
1452     @Test
testDefaultFreeformSizeShrinksOnSmallDisplay()1453     public void testDefaultFreeformSizeShrinksOnSmallDisplay() {
1454         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1455                 WINDOWING_MODE_FREEFORM, SMALL_DISPLAY_BOUNDS, SMALL_DISPLAY_STABLE_BOUNDS);
1456 
1457         final ActivityOptions options = ActivityOptions.makeBasic();
1458         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1459 
1460         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setOptions(options)
1461                 .calculate());
1462 
1463         assertEquals(new Rect(414, 77, 587, 423), mResult.mBounds);
1464     }
1465 
1466     @Test
testDefaultFreeformSizeRespectsMinAspectRatio()1467     public void testDefaultFreeformSizeRespectsMinAspectRatio() {
1468         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1469                 WINDOWING_MODE_FREEFORM);
1470 
1471         final ActivityOptions options = ActivityOptions.makeBasic();
1472         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1473 
1474         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1475         mActivity.info.setMinAspectRatio(5f);
1476 
1477         assertEquals(RESULT_CONTINUE,
1478                 new CalculateRequestBuilder()
1479                         .setOptions(options).calculate());
1480 
1481         final float aspectRatio =
1482                 (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height())
1483                         / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height());
1484         assertTrue("Bounds aspect ratio should be at least 5.0, but was " + aspectRatio,
1485                 aspectRatio >= 5f);
1486     }
1487 
1488     @Test
testDefaultFreeformSizeRespectsMaxAspectRatio()1489     public void testDefaultFreeformSizeRespectsMaxAspectRatio() {
1490         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1491                 WINDOWING_MODE_FREEFORM);
1492 
1493         final ActivityOptions options = ActivityOptions.makeBasic();
1494         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1495 
1496         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1497         mActivity.info.setMaxAspectRatio(1.5f);
1498 
1499         assertEquals(RESULT_CONTINUE,
1500                 new CalculateRequestBuilder()
1501                         .setOptions(options).calculate());
1502 
1503         final float aspectRatio =
1504                 (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height())
1505                         / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height());
1506         assertTrue("Bounds aspect ratio should be at most 1.5, but was " + aspectRatio,
1507                 aspectRatio <= 1.5f);
1508     }
1509 
1510     @Test
testCascadesToSourceSizeForFreeform()1511     public void testCascadesToSourceSizeForFreeform() {
1512         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1513                 WINDOWING_MODE_FREEFORM);
1514 
1515         final ActivityOptions options = ActivityOptions.makeBasic();
1516         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1517 
1518         final ActivityRecord source = createSourceActivity(freeformDisplay);
1519         source.setBounds(0, 0, 412, 732);
1520 
1521         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1522 
1523         assertEquals(RESULT_CONTINUE,
1524                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
1525 
1526         final Rect displayBounds = freeformDisplay.getBounds();
1527         assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0);
1528         assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0);
1529         assertTrue("Bounds should be centered at somewhere in the left half, but it's "
1530                 + "centerX is " + mResult.mBounds.centerX(),
1531                 mResult.mBounds.centerX() < displayBounds.centerX());
1532         assertTrue("Bounds should be centered at somewhere in the top half, but it's "
1533                         + "centerY is " + mResult.mBounds.centerY(),
1534                 mResult.mBounds.centerY() < displayBounds.centerY());
1535     }
1536 
1537     @Test
testCascadesToSourceSizeForFreeformRespectingMinAspectRatio()1538     public void testCascadesToSourceSizeForFreeformRespectingMinAspectRatio() {
1539         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1540                 WINDOWING_MODE_FREEFORM);
1541 
1542         final ActivityOptions options = ActivityOptions.makeBasic();
1543         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1544 
1545         final ActivityRecord source = createSourceActivity(freeformDisplay);
1546         source.setBounds(0, 0, 412, 732);
1547 
1548         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1549         mActivity.info.setMinAspectRatio(5f);
1550 
1551         assertEquals(RESULT_CONTINUE,
1552                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
1553 
1554         final Rect displayBounds = freeformDisplay.getBounds();
1555         assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0);
1556         assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0);
1557         assertTrue("Bounds should be centered at somewhere in the left half, but it's "
1558                         + "centerX is " + mResult.mBounds.centerX(),
1559                 mResult.mBounds.centerX() < displayBounds.centerX());
1560         assertTrue("Bounds should be centered at somewhere in the top half, but it's "
1561                         + "centerY is " + mResult.mBounds.centerY(),
1562                 mResult.mBounds.centerY() < displayBounds.centerY());
1563         final float aspectRatio =
1564                 (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height())
1565                         / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height());
1566         assertTrue("Bounds aspect ratio should be at least 5.0, but was " + aspectRatio,
1567                 aspectRatio >= 5f);
1568     }
1569 
1570     @Test
testCascadesToSourceSizeForFreeformRespectingMaxAspectRatio()1571     public void testCascadesToSourceSizeForFreeformRespectingMaxAspectRatio() {
1572         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1573                 WINDOWING_MODE_FREEFORM);
1574 
1575         final ActivityOptions options = ActivityOptions.makeBasic();
1576         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1577 
1578         final ActivityRecord source = createSourceActivity(freeformDisplay);
1579         source.setBounds(0, 0, 412, 732);
1580 
1581         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1582         mActivity.info.setMaxAspectRatio(1.5f);
1583 
1584         assertEquals(RESULT_CONTINUE,
1585                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
1586 
1587         final Rect displayBounds = freeformDisplay.getBounds();
1588         assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0);
1589         assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0);
1590         assertTrue("Bounds should be centered at somewhere in the left half, but it's "
1591                         + "centerX is " + mResult.mBounds.centerX(),
1592                 mResult.mBounds.centerX() < displayBounds.centerX());
1593         assertTrue("Bounds should be centered at somewhere in the top half, but it's "
1594                         + "centerY is " + mResult.mBounds.centerY(),
1595                 mResult.mBounds.centerY() < displayBounds.centerY());
1596         final float aspectRatio =
1597                 (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height())
1598                         / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height());
1599         assertTrue("Bounds aspect ratio should be at most 1.5, but was " + aspectRatio,
1600                 aspectRatio <= 1.5f);
1601     }
1602 
1603     @Test
testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay()1604     public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() {
1605         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1606                 WINDOWING_MODE_FREEFORM);
1607 
1608         final ActivityOptions options = ActivityOptions.makeBasic();
1609         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1610 
1611         final ActivityRecord source = createSourceActivity(freeformDisplay);
1612         source.setBounds(0, 0, 200, 400);
1613 
1614         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1615 
1616         assertEquals(RESULT_CONTINUE,
1617                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
1618 
1619         final Rect displayBounds = freeformDisplay.getBounds();
1620         assertTrue("display bounds doesn't contain result. display bounds: "
1621                 + displayBounds + " result: " + mResult.mBounds,
1622                 displayBounds.contains(mResult.mBounds));
1623     }
1624 
1625     @Test
testAdjustBoundsToFitDisplay_BottomRightOutOfDisplay()1626     public void testAdjustBoundsToFitDisplay_BottomRightOutOfDisplay() {
1627         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1628                 WINDOWING_MODE_FREEFORM);
1629 
1630         final ActivityOptions options = ActivityOptions.makeBasic();
1631         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1632 
1633         final ActivityRecord source = createSourceActivity(freeformDisplay);
1634         source.setBounds(1720, 680, 1920, 1080);
1635 
1636         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1637 
1638         assertEquals(RESULT_CONTINUE,
1639                 new CalculateRequestBuilder().setSource(source).setOptions(options).calculate());
1640 
1641         final Rect displayBounds = freeformDisplay.getBounds();
1642         assertTrue("display bounds doesn't contain result. display bounds: "
1643                         + displayBounds + " result: " + mResult.mBounds,
1644                 displayBounds.contains(mResult.mBounds));
1645     }
1646 
1647     @Test
testAdjustBoundsToFitNewDisplay_LargerThanDisplay()1648     public void testAdjustBoundsToFitNewDisplay_LargerThanDisplay() {
1649         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1650                 WINDOWING_MODE_FREEFORM);
1651 
1652         final ActivityOptions options = ActivityOptions.makeBasic();
1653         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1654 
1655         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
1656         mCurrent.mBounds.set(0, 0, 3000, 2000);
1657 
1658         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1659 
1660         assertEquals(RESULT_CONTINUE,
1661                 new CalculateRequestBuilder().setOptions(options).calculate());
1662 
1663         // Must shrink to fit the display while reserving aspect ratio.
1664         assertEquals(new Rect(127, 227, 766, 653), mResult.mBounds);
1665     }
1666 
1667     @Test
testAdjustBoundsToFitNewDisplay_LargerThanDisplay_RTL()1668     public void testAdjustBoundsToFitNewDisplay_LargerThanDisplay_RTL() {
1669         final Configuration overrideConfig =
1670                 mRootWindowContainer.getRequestedOverrideConfiguration();
1671         // Egyptian Arabic is a RTL language.
1672         overrideConfig.setLayoutDirection(new Locale("ar", "EG"));
1673         mRootWindowContainer.onRequestedOverrideConfigurationChanged(overrideConfig);
1674 
1675         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1676                 WINDOWING_MODE_FREEFORM);
1677 
1678         final ActivityOptions options = ActivityOptions.makeBasic();
1679         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1680         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1681                 .setMinWidth(500).setMinHeight(500).build();
1682 
1683         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
1684         mCurrent.mBounds.set(0, 0, 2000, 3000);
1685 
1686         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1687 
1688         assertEquals(RESULT_CONTINUE,
1689                 new CalculateRequestBuilder().setOptions(options).setLayout(layout).calculate());
1690 
1691         // Must shrink to fit the display while reserving aspect ratio.
1692         assertEquals(new Rect(1093, 227, 1593, 727), mResult.mBounds);
1693     }
1694 
1695     @Test
testRespectsLayoutMinDimensions()1696     public void testRespectsLayoutMinDimensions() {
1697         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1698                 WINDOWING_MODE_FREEFORM);
1699 
1700         // This test case requires a relatively big app bounds to ensure the default size calculated
1701         // by letterbox won't be too small to hold the minimum width/height.
1702         configInsetsState(
1703                 freeformDisplay.getInsetsStateController().getRawInsetsState(), freeformDisplay,
1704                 new Rect(10, 10, 1910, 1070));
1705 
1706         final ActivityOptions options = ActivityOptions.makeBasic();
1707         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1708 
1709         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
1710                 .setMinWidth(500).setMinHeight(800).build();
1711 
1712         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
1713 
1714         assertEquals(RESULT_CONTINUE,
1715                 new CalculateRequestBuilder().setLayout(layout).setOptions(options).calculate());
1716 
1717         assertEquals(500, mResult.mBounds.width());
1718         assertEquals(800, mResult.mBounds.height());
1719     }
1720 
1721     @Test
testRotatesInPlaceInitialBoundsMismatchOrientation()1722     public void testRotatesInPlaceInitialBoundsMismatchOrientation() {
1723         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1724                 WINDOWING_MODE_FREEFORM);
1725 
1726         final ActivityOptions options = ActivityOptions.makeBasic();
1727         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1728         options.setLaunchBounds(new Rect(100, 100, 500, 300));
1729 
1730         mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
1731 
1732         assertEquals(RESULT_CONTINUE,
1733                 new CalculateRequestBuilder().setOptions(options).calculate());
1734 
1735         assertEquals(new Rect(200, 0, 400, 400), mResult.mBounds);
1736     }
1737 
1738     @Test
testShiftsToRightForCloseToLeftBoundsWhenConflict()1739     public void testShiftsToRightForCloseToLeftBoundsWhenConflict() {
1740         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1741                 WINDOWING_MODE_FREEFORM);
1742 
1743         addFreeformTaskTo(freeformDisplay, new Rect(50, 50, 100, 150));
1744 
1745         final ActivityOptions options = ActivityOptions.makeBasic();
1746         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1747         options.setLaunchBounds(new Rect(50, 50, 500, 300));
1748 
1749         assertEquals(RESULT_CONTINUE,
1750                 new CalculateRequestBuilder().setOptions(options).calculate());
1751 
1752         assertEquals(new Rect(170, 50, 620, 300), mResult.mBounds);
1753     }
1754 
1755     @Test
testShiftsToLeftForCloseToRightBoundsWhenConflict()1756     public void testShiftsToLeftForCloseToRightBoundsWhenConflict() {
1757         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1758                 WINDOWING_MODE_FREEFORM);
1759 
1760         addFreeformTaskTo(freeformDisplay, new Rect(1720, 50, 1830, 150));
1761 
1762         final ActivityOptions options = ActivityOptions.makeBasic();
1763         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1764         options.setLaunchBounds(new Rect(1720, 50, 1850, 300));
1765 
1766         assertEquals(RESULT_CONTINUE,
1767                 new CalculateRequestBuilder().setOptions(options).calculate());
1768 
1769         assertEquals(new Rect(1600, 50, 1730, 300), mResult.mBounds);
1770     }
1771 
1772     @Test
testShiftsToRightFirstForHorizontallyCenteredAndCloseToTopWhenConflict()1773     public void testShiftsToRightFirstForHorizontallyCenteredAndCloseToTopWhenConflict() {
1774         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1775                 WINDOWING_MODE_FREEFORM);
1776 
1777         addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 100, 300));
1778 
1779         final ActivityOptions options = ActivityOptions.makeBasic();
1780         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1781         options.setLaunchBounds(new Rect(0, 0, 1800, 200));
1782 
1783         assertEquals(RESULT_CONTINUE,
1784                 new CalculateRequestBuilder().setOptions(options).calculate());
1785 
1786         assertEquals(new Rect(120, 0, 1920, 200), mResult.mBounds);
1787     }
1788 
1789     @Test
testShiftsToLeftNoSpaceOnRightForHorizontallyCenteredAndCloseToTopWhenConflict()1790     public void testShiftsToLeftNoSpaceOnRightForHorizontallyCenteredAndCloseToTopWhenConflict() {
1791         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1792                 WINDOWING_MODE_FREEFORM);
1793 
1794         addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 300));
1795 
1796         final ActivityOptions options = ActivityOptions.makeBasic();
1797         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1798         options.setLaunchBounds(new Rect(120, 0, 1860, 200));
1799 
1800         assertEquals(RESULT_CONTINUE,
1801                 new CalculateRequestBuilder().setOptions(options).calculate());
1802 
1803         assertEquals(new Rect(0, 0, 1740, 200), mResult.mBounds);
1804     }
1805 
1806     @Test
testShiftsToBottomRightFirstForCenteredBoundsWhenConflict()1807     public void testShiftsToBottomRightFirstForCenteredBoundsWhenConflict() {
1808         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1809                 WINDOWING_MODE_FREEFORM);
1810 
1811         addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 100));
1812 
1813         final ActivityOptions options = ActivityOptions.makeBasic();
1814         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1815         options.setLaunchBounds(new Rect(120, 0, 1800, 1013));
1816 
1817         assertEquals(RESULT_CONTINUE,
1818                 new CalculateRequestBuilder().setOptions(options).calculate());
1819 
1820         assertEquals(new Rect(240, 67, 1920, 1080), mResult.mBounds);
1821     }
1822 
1823     @Test
testShiftsToTopLeftIfNoSpaceOnBottomRightForCenteredBoundsWhenConflict()1824     public void testShiftsToTopLeftIfNoSpaceOnBottomRightForCenteredBoundsWhenConflict() {
1825         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1826                 WINDOWING_MODE_FREEFORM);
1827 
1828         addFreeformTaskTo(freeformDisplay, new Rect(120, 67, 240, 100));
1829 
1830         final ActivityOptions options = ActivityOptions.makeBasic();
1831         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1832         options.setLaunchBounds(new Rect(120, 67, 1800, 1020));
1833 
1834         assertEquals(RESULT_CONTINUE,
1835                 new CalculateRequestBuilder().setOptions(options).calculate());
1836 
1837         assertEquals(new Rect(0, 0, 1680, 953), mResult.mBounds);
1838     }
1839 
1840     @Test
returnsNonFullscreenBoundsOnFullscreenDisplayWithFreeformHistory()1841     public void returnsNonFullscreenBoundsOnFullscreenDisplayWithFreeformHistory() {
1842         mCurrent.mPreferredTaskDisplayArea = null;
1843         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
1844         mCurrent.mBounds.set(0, 0, 200, 100);
1845 
1846         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
1847 
1848         // Returned bounds with in fullscreen mode will be set to last non-fullscreen bounds.
1849         assertEquals(new Rect(0, 0, 200, 100), mResult.mBounds);
1850     }
1851 
1852     @Test
testAdjustsBoundsToFitInDisplayFullyResolvedBounds()1853     public void testAdjustsBoundsToFitInDisplayFullyResolvedBounds() {
1854         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1855                 WINDOWING_MODE_FREEFORM);
1856 
1857         mCurrent.mPreferredTaskDisplayArea = null;
1858         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
1859         mCurrent.mBounds.set(-100, -200, 200, 100);
1860 
1861         final ActivityOptions options = ActivityOptions.makeBasic();
1862         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
1863 
1864         assertEquals(RESULT_CONTINUE,
1865                 new CalculateRequestBuilder().setOptions(options).calculate());
1866 
1867         assertEquals(new Rect(127, 227, 427, 527), mResult.mBounds);
1868     }
1869 
1870     @Test
testAdjustsBoundsToAvoidConflictFullyResolvedBounds()1871     public void testAdjustsBoundsToAvoidConflictFullyResolvedBounds() {
1872         final TestDisplayContent freeformDisplay = createNewDisplayContent(
1873                 WINDOWING_MODE_FREEFORM);
1874 
1875         addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 200, 100));
1876 
1877         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
1878         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
1879         mCurrent.mBounds.set(0, 0, 200, 100);
1880 
1881         assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
1882 
1883         assertEquals(new Rect(120, 0, 320, 100), mResult.mBounds);
1884     }
1885 
1886     @Test
testAdjustBoundsToAvoidConflictAlwaysExits()1887     public void testAdjustBoundsToAvoidConflictAlwaysExits() {
1888         Rect displayBounds = new Rect(0, 0, 40, 40);
1889         List<Rect> existingTaskBounds = new ArrayList<>();
1890         for (int i = 0; i < 9; i++) {
1891             for (int j = 0; j < 9; j++) {
1892                 int left = i * 5;
1893                 int top = j * 5;
1894                 existingTaskBounds.add(new Rect(left, top, left + 20, top + 20));
1895             }
1896         }
1897         Rect startingBounds = new Rect(0, 0, 20, 20);
1898         Rect adjustedBounds = new Rect(startingBounds);
1899         mTarget.adjustBoundsToAvoidConflict(displayBounds, existingTaskBounds, adjustedBounds);
1900         assertEquals(startingBounds, adjustedBounds);
1901     }
1902 
1903     @Test
testNoMultiDisplaySupports()1904     public void testNoMultiDisplaySupports() {
1905         final boolean orgValue = mAtm.mSupportsMultiDisplay;
1906         final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN);
1907         mCurrent.mPreferredTaskDisplayArea = display.getDefaultTaskDisplayArea();
1908 
1909         try {
1910             mAtm.mSupportsMultiDisplay = false;
1911             assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate());
1912             assertEquals(mRootWindowContainer.getDefaultTaskDisplayArea(),
1913                     mResult.mPreferredTaskDisplayArea);
1914         } finally {
1915             mAtm.mSupportsMultiDisplay = orgValue;
1916         }
1917     }
1918 
createNewDisplayContent(int windowingMode)1919     private TestDisplayContent createNewDisplayContent(int windowingMode) {
1920         return createNewDisplayContent(windowingMode, DISPLAY_BOUNDS, DISPLAY_STABLE_BOUNDS);
1921     }
1922 
createNewDisplayContent(int windowingMode, Rect displayBounds, Rect displayStableBounds)1923     private TestDisplayContent createNewDisplayContent(int windowingMode, Rect displayBounds,
1924                                                        Rect displayStableBounds) {
1925         final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
1926         display.getDefaultTaskDisplayArea().setWindowingMode(windowingMode);
1927         display.setBounds(displayBounds);
1928         display.getConfiguration().densityDpi = DENSITY_DEFAULT;
1929         display.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
1930         configInsetsState(display.getInsetsStateController().getRawInsetsState(), display,
1931                 displayStableBounds);
1932         return display;
1933     }
1934 
1935     /**
1936      * Creates insets sources so that we can get the expected stable frame.
1937      */
configInsetsState(InsetsState state, DisplayContent display, Rect stableFrame)1938     private static void configInsetsState(InsetsState state, DisplayContent display,
1939             Rect stableFrame) {
1940         final Rect displayFrame = display.getBounds();
1941         final int dl = displayFrame.left;
1942         final int dt = displayFrame.top;
1943         final int dr = displayFrame.right;
1944         final int db = displayFrame.bottom;
1945         final int sl = stableFrame.left;
1946         final int st = stableFrame.top;
1947         final int sr = stableFrame.right;
1948         final int sb = stableFrame.bottom;
1949         final @WindowInsets.Type.InsetsType int statusBarType = WindowInsets.Type.statusBars();
1950         final @WindowInsets.Type.InsetsType int navBarType = WindowInsets.Type.navigationBars();
1951 
1952         state.setDisplayFrame(displayFrame);
1953         if (sl > dl) {
1954             state.getOrCreateSource(InsetsSource.createId(null, 0, statusBarType), statusBarType)
1955                     .setFrame(dl, dt, sl, db);
1956         }
1957         if (st > dt) {
1958             state.getOrCreateSource(InsetsSource.createId(null, 1, statusBarType), statusBarType)
1959                     .setFrame(dl, dt, dr, st);
1960         }
1961         if (sr < dr) {
1962             state.getOrCreateSource(InsetsSource.createId(null, 0, navBarType), navBarType)
1963                     .setFrame(sr, dt, dr, db);
1964         }
1965         if (sb < db) {
1966             state.getOrCreateSource(InsetsSource.createId(null, 1, navBarType), navBarType)
1967                     .setFrame(dl, sb, dr, db);
1968         }
1969         // Recompute config and push to children.
1970         display.onRequestedOverrideConfigurationChanged(display.getConfiguration());
1971     }
1972 
createSourceActivity(TestDisplayContent display)1973     private ActivityRecord createSourceActivity(TestDisplayContent display) {
1974         final Task rootTask = display.getDefaultTaskDisplayArea()
1975                 .createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
1976         return new ActivityBuilder(mAtm).setTask(rootTask).build();
1977     }
1978 
createSourceActivity(TaskDisplayArea taskDisplayArea, int windowingMode)1979     private ActivityRecord createSourceActivity(TaskDisplayArea taskDisplayArea,
1980             int windowingMode) {
1981         final Task rootTask = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD,
1982                 true);
1983         return new ActivityBuilder(mAtm).setTask(rootTask).build();
1984     }
1985 
addFreeformTaskTo(TestDisplayContent display, Rect bounds)1986     private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
1987         final Task rootTask = display.getDefaultTaskDisplayArea()
1988                 .createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
1989         rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
1990         final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
1991         // Just work around the unnecessary adjustments for bounds.
1992         task.getWindowConfiguration().setBounds(bounds);
1993     }
1994 
assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode)1995     private void assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode) {
1996         if (expected != parentWindowingMode) {
1997             assertEquals(expected, actual);
1998         } else {
1999             assertEquals(WINDOWING_MODE_UNDEFINED, actual);
2000         }
2001     }
2002 
orientationFromBounds(Rect bounds)2003     private int orientationFromBounds(Rect bounds) {
2004         return bounds.width() > bounds.height() ? SCREEN_ORIENTATION_LANDSCAPE
2005                 : SCREEN_ORIENTATION_PORTRAIT;
2006     }
2007 
2008     private class CalculateRequestBuilder {
2009         private Task mTask;
2010         private ActivityInfo.WindowLayout mLayout;
2011         private ActivityRecord mActivity = TaskLaunchParamsModifierTests.this.mActivity;
2012         private ActivityRecord mSource;
2013         private ActivityOptions mOptions;
2014         private Request mRequest;
2015         private int mPhase = PHASE_BOUNDS;
2016         private LaunchParams mCurrentParams = mCurrent;
2017         private LaunchParams mOutParams = mResult;
2018 
setTask(Task task)2019         private CalculateRequestBuilder setTask(Task task) {
2020             mTask = task;
2021             return this;
2022         }
2023 
setLayout(ActivityInfo.WindowLayout layout)2024         private CalculateRequestBuilder setLayout(ActivityInfo.WindowLayout layout) {
2025             mLayout = layout;
2026             return this;
2027         }
2028 
setActivity(ActivityRecord activity)2029         private CalculateRequestBuilder setActivity(ActivityRecord activity) {
2030             mActivity = activity;
2031             return this;
2032         }
2033 
setSource(ActivityRecord source)2034         private CalculateRequestBuilder setSource(ActivityRecord source) {
2035             mSource = source;
2036             return this;
2037         }
2038 
setOptions(ActivityOptions options)2039         private CalculateRequestBuilder setOptions(ActivityOptions options) {
2040             mOptions = options;
2041             return this;
2042         }
2043 
setRequest(Request request)2044         private CalculateRequestBuilder setRequest(Request request) {
2045             mRequest = request;
2046             return this;
2047         }
2048 
calculate()2049         private @Result int calculate() {
2050             return mTarget.onCalculate(mTask, mLayout, mActivity, mSource, mOptions, mRequest,
2051                     mPhase, mCurrentParams, mOutParams);
2052         }
2053     }
2054 
2055     private static class WindowLayoutBuilder {
2056         private int mWidth = -1;
2057         private int mHeight = -1;
2058         private float mWidthFraction = -1f;
2059         private float mHeightFraction = -1f;
2060         private int mGravity = Gravity.NO_GRAVITY;
2061         private int mMinWidth = -1;
2062         private int mMinHeight = -1;
2063 
setWidth(int width)2064         private WindowLayoutBuilder setWidth(int width) {
2065             mWidth = width;
2066             return this;
2067         }
2068 
setHeight(int height)2069         private WindowLayoutBuilder setHeight(int height) {
2070             mHeight = height;
2071             return this;
2072         }
2073 
setWidthFraction(float widthFraction)2074         private WindowLayoutBuilder setWidthFraction(float widthFraction) {
2075             mWidthFraction = widthFraction;
2076             return this;
2077         }
2078 
setHeightFraction(float heightFraction)2079         private WindowLayoutBuilder setHeightFraction(float heightFraction) {
2080             mHeightFraction = heightFraction;
2081             return this;
2082         }
2083 
setGravity(int gravity)2084         private WindowLayoutBuilder setGravity(int gravity) {
2085             mGravity = gravity;
2086             return this;
2087         }
2088 
setMinWidth(int minWidth)2089         private WindowLayoutBuilder setMinWidth(int minWidth) {
2090             mMinWidth = minWidth;
2091             return this;
2092         }
2093 
setMinHeight(int minHeight)2094         private WindowLayoutBuilder setMinHeight(int minHeight) {
2095             mMinHeight = minHeight;
2096             return this;
2097         }
2098 
build()2099         private ActivityInfo.WindowLayout build() {
2100             return new ActivityInfo.WindowLayout(mWidth, mWidthFraction, mHeight, mHeightFraction,
2101                     mGravity, mMinWidth, mMinHeight);
2102         }
2103     }
2104 }
2105