Removing RWC#getValidLaunchRootTaskInTaskDisplayArea

... and consolidate the flow with TDA#getOrCreateRootTask.

Updating few changes regarding to the launch windowing mode
calculation since the windowing mode is an important input
while determining the root task. It wasn't needed because
the candidate root task was reused in most cases.

Secondly, the root task was always created on default TDA
(regardless the preferable one is the secondary TDA) if no
launching activity was given. This CL also changes the behavior
to allow creating root tasks from the preferable TDA.

Bug: 184806710
Test: atest RootWindowContainerTests
Change-Id: I1e8055bb7bb2da8fe35bdfae1f85c610d5751434
This commit is contained in:
Louis Chang
2022-01-18 10:57:12 +08:00
parent 038fd80ce8
commit bbcd34357b
6 changed files with 62 additions and 151 deletions

View File

@@ -18,15 +18,9 @@ package com.android.server.wm;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -2791,35 +2785,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Task rootTask = null;
// Next preference for root task goes to the taskDisplayArea candidate.
if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null) {
if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null
&& canLaunchOnDisplay(r, launchParams.mPreferredTaskDisplayArea.getDisplayId())) {
taskDisplayArea = launchParams.mPreferredTaskDisplayArea;
}
if (taskDisplayArea == null && displayId != INVALID_DISPLAY) {
final DisplayContent displayContent = getDisplayContent(displayId);
if (displayContent != null) {
taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
}
if (taskDisplayArea == null && displayId != INVALID_DISPLAY
&& canLaunchOnDisplay(r, displayId)) {
taskDisplayArea = getDisplayContent(displayId).getDefaultTaskDisplayArea();
}
if (taskDisplayArea != null) {
final int tdaDisplayId = taskDisplayArea.getDisplayId();
if (canLaunchOnDisplay(r, tdaDisplayId)) {
if (r != null) {
final Task result = getValidLaunchRootTaskInTaskDisplayArea(
taskDisplayArea, r, candidateTask, options, launchParams);
if (result != null) {
return result;
}
}
// Falling back to default task container
taskDisplayArea = taskDisplayArea.mDisplayContent.getDefaultTaskDisplayArea();
rootTask = taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
sourceTask, launchParams, launchFlags, activityType, onTop);
if (rootTask != null) {
return rootTask;
}
}
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
sourceTask, launchParams, launchFlags, activityType, onTop);
}
// Give preference to the root task and display of the input task and activity if they
@@ -2869,103 +2845,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return r.canBeLaunchedOnDisplay(displayId);
}
/**
* Get a topmost root task on the display area, that is a valid launch root task for
* specified activity. If there is no such root task, new dynamic root task can be created.
*
* @param taskDisplayArea Target display area.
* @param r Activity that should be launched there.
* @param candidateTask The possible task the activity might be put in.
* @return Existing root task if there is a valid one, new dynamic root task if it is valid
* or null.
*/
@VisibleForTesting
Task getValidLaunchRootTaskInTaskDisplayArea(@NonNull TaskDisplayArea taskDisplayArea,
@NonNull ActivityRecord r, @Nullable Task candidateTask,
@Nullable ActivityOptions options,
@Nullable LaunchParamsController.LaunchParams launchParams) {
if (!r.canBeLaunchedOnDisplay(taskDisplayArea.getDisplayId())) {
return null;
}
// If {@code r} is already in target display area and its task is the same as the candidate
// task, the intention should be getting a launch root task for the reusable activity, so we
// can use the existing root task.
if (candidateTask != null) {
final TaskDisplayArea attachedTaskDisplayArea = candidateTask.getDisplayArea();
if (attachedTaskDisplayArea == null || attachedTaskDisplayArea == taskDisplayArea) {
return candidateTask.getRootTask();
}
// Or the candidate task is already a root task that can be reused by reparenting
// it to the target display.
if (candidateTask.isRootTask()) {
final Task rootTask = candidateTask.getRootTask();
rootTask.reparent(taskDisplayArea, true /* onTop */);
return rootTask;
}
}
int windowingMode;
if (launchParams != null) {
// When launch params is not null, we always defer to its windowing mode. Sometimes
// it could be unspecified, which indicates it should inherit windowing mode from
// display.
windowingMode = launchParams.mWindowingMode;
} else {
windowingMode = options != null ? options.getLaunchWindowingMode()
: r.getWindowingMode();
}
windowingMode = taskDisplayArea.validateWindowingMode(windowingMode, r, candidateTask);
// Return the topmost valid root task on the display.
final int targetWindowingMode = windowingMode;
final Task topmostValidRootTask = taskDisplayArea.getRootTask(rootTask ->
isValidLaunchRootTask(rootTask, r, targetWindowingMode));
if (topmostValidRootTask != null) {
return topmostValidRootTask;
}
// If there is no valid root task on the secondary display area - check if new dynamic root
// task will do.
if (taskDisplayArea != getDisplayContent(taskDisplayArea.getDisplayId())
.getDefaultTaskDisplayArea()) {
final int activityType =
options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED
? options.getLaunchActivityType() : r.getActivityType();
return taskDisplayArea.createRootTask(
windowingMode, activityType, true /*onTop*/, options);
}
return null;
}
// TODO: Can probably be consolidated into getLaunchRootTask()...
private boolean isValidLaunchRootTask(Task task, ActivityRecord r, int windowingMode) {
switch (task.getActivityType()) {
case ACTIVITY_TYPE_HOME:
return r.isActivityTypeHome();
case ACTIVITY_TYPE_RECENTS:
return r.isActivityTypeRecents();
case ACTIVITY_TYPE_ASSISTANT:
return r.isActivityTypeAssistant();
case ACTIVITY_TYPE_DREAM:
return r.isActivityTypeDream();
}
if (task.mCreatedByOrganizer) {
// Don't launch directly into task created by organizer...but why can't we?
return false;
}
// There is a 1-to-1 relationship between root task and task when not in
// primary split-windowing mode.
if (task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
&& r.supportsSplitScreenWindowingModeInDisplayArea(task.getDisplayArea())
&& (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| windowingMode == WINDOWING_MODE_UNDEFINED)) {
return true;
}
return false;
}
int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable Task task) {
// Preference is given to the activity type for the activity then the task since the type

View File

@@ -941,36 +941,32 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
@Nullable Task candidateTask, @Nullable Task sourceTask,
@Nullable ActivityOptions options, int launchFlags) {
final int resolvedWindowingMode =
windowingMode == WINDOWING_MODE_UNDEFINED ? getWindowingMode() : windowingMode;
// Need to pass in a determined windowing mode to see if a new root task should be created,
// so use its parent's windowing mode if it is undefined.
if (!alwaysCreateRootTask(
windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(),
activityType)) {
Task rootTask = getRootTask(windowingMode, activityType);
if (!alwaysCreateRootTask(resolvedWindowingMode, activityType)) {
Task rootTask = getRootTask(resolvedWindowingMode, activityType);
if (rootTask != null) {
return rootTask;
}
} else if (candidateTask != null) {
final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
final Task launchRootTask = getLaunchRootTask(windowingMode, activityType, options,
sourceTask, launchFlags);
final Task launchRootTask = getLaunchRootTask(resolvedWindowingMode, activityType,
options, sourceTask, launchFlags);
if (launchRootTask != null) {
if (candidateTask.getParent() == null) {
launchRootTask.addChild(candidateTask, position);
} else if (candidateTask.getParent() != launchRootTask) {
candidateTask.reparent(launchRootTask, position);
}
} else if (candidateTask.getDisplayArea() != this || !candidateTask.isRootTask()) {
} else if (candidateTask.getDisplayArea() != this) {
if (candidateTask.getParent() == null) {
addChild(candidateTask, position);
} else {
candidateTask.reparent(this, onTop);
}
}
// Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
if (candidateTask.getWindowingMode() != windowingMode) {
candidateTask.setWindowingMode(windowingMode);
}
return candidateTask.getRootTask();
}
return new Task.Builder(mAtmService)

View File

@@ -157,12 +157,26 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
// display.
if (launchMode == WINDOWING_MODE_UNDEFINED
&& canInheritWindowingModeFromSource(display, source)) {
launchMode = source.getWindowingMode();
// The source's windowing mode may be different from its task, e.g. activity is set
// to fullscreen and its task is pinned windowing mode when the activity is entering
// pip.
launchMode = source.getTask().getWindowingMode();
if (DEBUG) {
appendLog("inherit-from-source="
+ WindowConfiguration.windowingModeToString(launchMode));
}
}
// If the launch windowing mode is still undefined, inherit from the target task if the
// task is already on the right display area (otherwise, the task may be on a different
// display area that has incompatible windowing mode).
if (launchMode == WINDOWING_MODE_UNDEFINED
&& task != null && task.getTaskDisplayArea() == suggestedDisplayArea) {
launchMode = task.getWindowingMode();
if (DEBUG) {
appendLog("inherit-from-task="
+ WindowConfiguration.windowingModeToString(launchMode));
}
}
// hasInitialBounds is set if either activity options or layout has specified bounds. If
// that's set we'll skip some adjustments later to avoid overriding the initial bounds.
boolean hasInitialBounds = false;

View File

@@ -925,14 +925,10 @@ public class ActivityStarterTests extends WindowTestsBase {
any(), anyBoolean(), anyBoolean(), eq(false));
}
private ActivityRecord createSingleTaskActivityOn(Task stack) {
private ActivityRecord createSingleTaskActivityOn(Task task) {
final ComponentName componentName = ComponentName.createRelative(
DEFAULT_COMPONENT_PACKAGE_NAME,
DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
final Task task = new TaskBuilder(mSupervisor)
.setComponent(componentName)
.setParentTaskFragment(stack)
.build();
return new ActivityBuilder(mAtm)
.setComponent(componentName)
.setLaunchMode(LAUNCH_SINGLE_TASK)

View File

@@ -938,7 +938,33 @@ public class RootWindowContainerTests extends WindowTestsBase {
}
@Test
public void testGetValidLaunchRootTaskOnDisplayWithCandidateRootTask() {
public void testGetLaunchRootTaskOnSecondaryTaskDisplayArea() {
// Adding another TaskDisplayArea to the default display.
final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(display,
mWm, "TDA", FEATURE_VENDOR_FIRST);
display.addChild(taskDisplayArea, POSITION_BOTTOM);
// Making sure getting the root task from the preferred TDA
LaunchParamsController.LaunchParams launchParams =
new LaunchParamsController.LaunchParams();
launchParams.mPreferredTaskDisplayArea = taskDisplayArea;
Task root = mRootWindowContainer.getLaunchRootTask(null /* r */, null /* options */,
null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams,
0 /* launchParams */);
assertEquals(taskDisplayArea, root.getTaskDisplayArea());
// Making sure still getting the root task from the preferred TDA when passing in a
// launching activity.
ActivityRecord r = new ActivityBuilder(mAtm).build();
root = mRootWindowContainer.getLaunchRootTask(r, null /* options */,
null /* candidateTask */, null /* sourceTask */, true /* onTop */, launchParams,
0 /* launchParams */);
assertEquals(taskDisplayArea, root.getTaskDisplayArea());
}
@Test
public void testGetOrCreateRootTaskOnDisplayWithCandidateRootTask() {
// Create a root task with an activity on secondary display.
final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300,
600).build();
@@ -947,9 +973,9 @@ public class RootWindowContainerTests extends WindowTestsBase {
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
// Make sure the root task is valid and can be reused on default display.
final Task rootTask = mRootWindowContainer.getValidLaunchRootTaskInTaskDisplayArea(
mRootWindowContainer.getDefaultTaskDisplayArea(), activity, task,
null /* options */, null /* launchParams */);
final Task rootTask = mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootTask(
activity, null /* options */, task, null /* sourceTask */, null /* launchParams */,
0 /* launchFlags */, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(task, rootTask);
}

View File

@@ -575,7 +575,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
final ActivityRecord source = createSourceActivity(fullscreenDisplay);
source.setWindowingMode(WINDOWING_MODE_FREEFORM);
source.getTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(RESULT_CONTINUE,
new CalculateRequestBuilder().setSource(source).calculate());
@@ -951,7 +951,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
WINDOWING_MODE_FULLSCREEN);
final ActivityRecord source = createSourceActivity(fullscreenDisplay);
source.setWindowingMode(WINDOWING_MODE_FREEFORM);
source.getTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
final ActivityOptions options = ActivityOptions.makeBasic();
final Rect expected = new Rect(0, 0, 150, 150);