diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java index 35653f96a14a6..285145a7fb078 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsController.java +++ b/services/core/java/com/android/server/wm/LaunchParamsController.java @@ -277,7 +277,8 @@ class LaunchParamsController { @interface Phase {} /** - * Stops once we are done with preferred display calculation. + * Stops once we are done with preferred display calculation. The result returned from this + * phase is only guaranteed to have a display area which display is the launch display. */ int PHASE_DISPLAY = 0; @@ -286,10 +287,15 @@ class LaunchParamsController { */ int PHASE_WINDOWING_MODE = 1; + /** + * Stops once we are done with display area calculation. + */ + int PHASE_DISPLAY_AREA = 2; + /** * Stops once we are done with window bounds calculation. */ - int PHASE_BOUNDS = 2; + int PHASE_BOUNDS = 3; /** * Returns the launch params that the provided activity launch params should be overridden diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 12f86112d751e..eca59e68a479a 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -89,6 +89,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { private final Rect mTmpStableBounds = new Rect(); private final int[] mTmpDirections = new int[2]; + private TaskDisplayArea mTmpDisplayArea; + private StringBuilder mLogBuilder; TaskLaunchParamsModifier(ActivityTaskSupervisor supervisor) { @@ -127,15 +129,15 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { return RESULT_SKIP; } - // STEP 1: Determine the display area to launch the activity/task. - final TaskDisplayArea taskDisplayArea = getPreferredLaunchTaskDisplayArea(task, + // STEP 1: Determine the suggested display area to launch the activity/task. + final TaskDisplayArea suggestedDisplayArea = getPreferredLaunchTaskDisplayArea(task, options, source, currentParams, activity, request); - outParams.mPreferredTaskDisplayArea = taskDisplayArea; - // TODO(b/152116619): Update the usages of display to use taskDisplayArea below. - final DisplayContent display = taskDisplayArea.mDisplayContent; + outParams.mPreferredTaskDisplayArea = suggestedDisplayArea; + final DisplayContent display = suggestedDisplayArea.mDisplayContent; if (DEBUG) { - appendLog("task-display-area=" + outParams.mPreferredTaskDisplayArea - + " display-area-windowing-mode=" + taskDisplayArea.getWindowingMode()); + appendLog("display-id=" + display.getDisplayId() + + " display-windowing-mode=" + display.getWindowingMode() + + " suggested-display-area=" + suggestedDisplayArea); } if (phase == PHASE_DISPLAY) { @@ -204,9 +206,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { // We inherit launch params from previous modifiers or LaunchParamsController if options, // layout and display conditions are not contradictory to their suggestions. It's important // to carry over their values because LaunchParamsController doesn't automatically do that. + // We only check if display matches because display area can be changed later. if (!currentParams.isEmpty() && !hasInitialBounds && (currentParams.mPreferredTaskDisplayArea == null - || currentParams.mPreferredTaskDisplayArea == taskDisplayArea)) { + || currentParams.mPreferredTaskDisplayArea.getDisplayId() + == display.getDisplayId())) { // Only set windowing mode if display is in freeform. If the display is in fullscreen // mode we should only launch a task in fullscreen mode. if (currentParams.hasWindowingMode() && display.inFreeformWindowingMode()) { @@ -255,14 +259,47 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { return RESULT_CONTINUE; } - // STEP 3: Determine final launch bounds based on resolved windowing mode and activity + // STEP 3: Finalize the display area. Here we allow WM shell route all launches that match + // certain criteria to specific task display areas. + final int resolvedMode = (launchMode != WINDOWING_MODE_UNDEFINED) ? launchMode + : display.getWindowingMode(); + TaskDisplayArea taskDisplayArea = suggestedDisplayArea; + // If launch task display area is set in options we should just use it. We assume the + // suggestedDisplayArea has the right one in this case. + if (options == null || options.getLaunchTaskDisplayArea() == null) { + final int activityType = + mSupervisor.mRootWindowContainer.resolveActivityType(root, options, task); + display.forAllTaskDisplayAreas(displayArea -> { + final Task launchRoot = displayArea.getLaunchRootTask(resolvedMode, activityType); + if (launchRoot == null) { + return false; + } + mTmpDisplayArea = displayArea; + return true; + }); + if (mTmpDisplayArea != null) { + taskDisplayArea = mTmpDisplayArea; + mTmpDisplayArea = null; + appendLog("overridden-display-area=[" + + WindowConfiguration.activityTypeToString(activityType) + ", " + + WindowConfiguration.windowingModeToString(resolvedMode) + ", " + + taskDisplayArea + "]"); + } + } + appendLog("display-area=" + taskDisplayArea); + outParams.mPreferredTaskDisplayArea = taskDisplayArea; + + if (phase == PHASE_DISPLAY_AREA) { + return RESULT_CONTINUE; + } + // TODO(b/152116619): Update the usages of display to use taskDisplayArea below. + + // STEP 4: Determine final launch bounds based on resolved windowing mode and activity // requested orientation. We set bounds to empty for fullscreen mode and keep bounds as is // for all other windowing modes that's not freeform mode. One can read comments in // relevant methods to further understand this step. // // We skip making adjustments if the params are fully resolved from previous results. - final int resolvedMode = (launchMode != WINDOWING_MODE_UNDEFINED) ? launchMode - : display.getWindowingMode(); if (fullyResolvedCurrentParam) { if (resolvedMode == WINDOWING_MODE_FREEFORM) { // Make sure bounds are in the display if it's possibly in a different display/area. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index 99bdf9f1caa41..6a108a4407675 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -32,6 +33,7 @@ import static android.view.InsetsState.ITYPE_CLIMATE_BAR; import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -113,9 +115,9 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setActivity(null).calculate()); } - // ============================= - // Display ID Related Tests - // ============================= + // ======================= + // Display Related Tests + // ======================= @Test public void testDefaultToPrimaryDisplayArea() { createNewDisplayContent(WINDOWING_MODE_FREEFORM); @@ -291,7 +293,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { when(mActivity.getProcessName()).thenReturn(processName); when(mActivity.getUid()).thenReturn(uid); doReturn(controller) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(processName, uid); assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate()); @@ -312,11 +314,11 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { when(mActivity.getProcessName()).thenReturn(processName); when(mActivity.getUid()).thenReturn(uid); doReturn(null) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(processName, uid); doReturn(controller) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid); assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate()); @@ -344,10 +346,10 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { .thenReturn(expectedTaskDisplayArea); doReturn(controllerForApplication) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(processName, uid); doReturn(controllerForLaunching) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid); assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate()); @@ -369,15 +371,15 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { when(controller.getTopActivityDisplayArea()).thenReturn(expectedTaskDisplayArea); doReturn(null) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(mActivity.processName, mActivity.info.applicationInfo.uid); doReturn(null) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid); doReturn(controller) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(request.realCallingPid, request.realCallingUid); assertEquals(RESULT_CONTINUE, @@ -389,11 +391,11 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { @Test public void testUsesDefaultDisplayAreaIfWindowProcessControllerIsNotPresent() { doReturn(null) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(mActivity.processName, mActivity.info.applicationInfo.uid); doReturn(null) - .when(mSupervisor.mService) + .when(mAtm) .getProcessController(mActivity.launchedFromPid, mActivity.launchedFromUid); assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate()); @@ -401,6 +403,80 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { assertEquals(DEFAULT_DISPLAY, mResult.mPreferredTaskDisplayArea.getDisplayId()); } + @Test + public void testOverridesDisplayAreaWithStandardTypeAndFullscreenMode() { + final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay, + mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST); + final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, secondaryDisplayArea); + launchRoot.mCreatedByOrganizer = true; + + secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN }, + new int[] { ACTIVITY_TYPE_STANDARD }); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate()); + + assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea); + } + + @Test + public void testOverridesDisplayAreaWithHomeTypeAndFullscreenMode() { + final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay, + mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST); + final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, secondaryDisplayArea); + launchRoot.mCreatedByOrganizer = true; + + mActivity.setActivityType(ACTIVITY_TYPE_HOME); + secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN }, + new int[] { ACTIVITY_TYPE_HOME }); + + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate()); + + assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea); + } + + @Test + public void testOverridesDisplayAreaWithStandardTypeAndFreeformMode() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(freeformDisplay, + mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST); + final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, secondaryDisplayArea); + launchRoot.mCreatedByOrganizer = true; + + secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FREEFORM }, + new int[] { ACTIVITY_TYPE_STANDARD }); + + mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea(); + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().calculate()); + + assertEquals(secondaryDisplayArea, mResult.mPreferredTaskDisplayArea); + } + + @Test + public void testNotOverrideDisplayAreaWhenActivityOptionsHasDisplayArea() { + final TaskDisplayArea secondaryDisplayArea = createTaskDisplayArea(mDefaultDisplay, + mWm, "SecondaryDisplayArea", FEATURE_RUNTIME_TASK_CONTAINER_FIRST); + final Task launchRoot = createTaskStackOnTaskDisplayArea(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, secondaryDisplayArea); + launchRoot.mCreatedByOrganizer = true; + + secondaryDisplayArea.setLaunchRootTask(launchRoot, new int[] { WINDOWING_MODE_FULLSCREEN }, + new int[] { ACTIVITY_TYPE_STANDARD }); + + ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchTaskDisplayArea( + mDefaultDisplay.getDefaultTaskDisplayArea().mRemoteToken.toWindowContainerToken()); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder().setOptions(options).calculate()); + + assertEquals( + mDefaultDisplay.getDefaultTaskDisplayArea(), mResult.mPreferredTaskDisplayArea); + } + // ===================================== // Launch Windowing Mode Related Tests // =====================================