From f4c655bb3d306ec0f301456cea0701e06e9c2c98 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Mon, 11 Apr 2022 06:54:15 +0000 Subject: [PATCH] Consider adjacent launch target when recycling an existing task If there's a launch target indicated while recycling an existing task, consider to use the adjacent task of the launch target. So the existing task won't be reparent to adjacent task redundantly. Fix: 224901460 Test: atest ActivityStarterTests Test: put single-instance app in split and make sure it gain focus, dropping the same app icon to another side of the split, observed it will switch split position without dismissing split Change-Id: I4d4b4bcb6c036601a4fa68905ae66d91526bfe84 --- .../android/server/wm/ActivityStarter.java | 28 +++++++++---------- .../server/wm/ActivityStarterTests.java | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index b97ee7ef76b3e..b2f27ebaf5133 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2732,8 +2732,8 @@ class ActivityStarter { intentActivity.getTaskFragment().clearLastPausedActivity(); Task intentTask = intentActivity.getTask(); - // Only update the target-root-task when it is not indicated. if (mTargetRootTask == null) { + // Update launch target task when it is not indicated. if (mSourceRecord != null && mSourceRecord.mLaunchRootTask != null) { // Inherit the target-root-task from source to ensure trampoline activities will be // launched into the same root task. @@ -2742,6 +2742,17 @@ class ActivityStarter { mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, intentTask, mOptions); } + } else { + // If a launch target indicated, and the matching task is already in the adjacent task + // of the launch target. Adjust to use the adjacent task as its launch target. So the + // existing task will be launched into the closer one and won't be reparent redundantly. + // TODO(b/231541706): Migrate the logic to wm-shell after having proper APIs to help + // resolve target task without actually starting the activity. + final Task adjacentTargetTask = mTargetRootTask.getAdjacentTaskFragment() != null + ? mTargetRootTask.getAdjacentTaskFragment().asTask() : null; + if (adjacentTargetTask != null && intentActivity.isDescendantOf(adjacentTargetTask)) { + mTargetRootTask = adjacentTargetTask; + } } // If the target task is not in the front, then we need to bring it to the front... @@ -2771,7 +2782,7 @@ class ActivityStarter { intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask()); } - if (mTargetRootTask == intentActivity.getRootTask()) { + if (intentActivity.isDescendantOf(mTargetRootTask)) { // TODO(b/151572268): Figure out a better way to move tasks in above 2-levels // tasks hierarchies. if (mTargetRootTask != intentTask @@ -2818,19 +2829,6 @@ class ActivityStarter { mTargetRootTask = intentActivity.getRootTask(); mSupervisor.handleNonResizableTaskIfNeeded(intentTask, WINDOWING_MODE_UNDEFINED, mRootWindowContainer.getDefaultTaskDisplayArea(), mTargetRootTask); - - // We need to check if there is a launch root task in TDA for this target root task. - // If it exist, we need to reparent target root task from TDA to launch root task. - final TaskDisplayArea tda = mTargetRootTask.getDisplayArea(); - final Task launchRootTask = tda.getLaunchRootTask(mTargetRootTask.getWindowingMode(), - mTargetRootTask.getActivityType(), null /** options */, mSourceRootTask, - mLaunchFlags); - // If target root task is created by organizer, let organizer handle reparent itself. - if (!mTargetRootTask.mCreatedByOrganizer && launchRootTask != null - && launchRootTask != mTargetRootTask) { - mTargetRootTask.reparent(launchRootTask, POSITION_TOP); - mTargetRootTask = launchRootTask; - } } private void resumeTargetRootTaskIfNeeded() { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index f59ec42a4a71c..b9432753c17fb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -784,6 +784,34 @@ public class ActivityStarterTests extends WindowTestsBase { } } + /** + * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will task the + * adjacent task of indicated launch target into account. So the existing task will be launched + * into closer target. + */ + @Test + public void testAdjustLaunchTargetWithAdjacentTask() { + // Create adjacent tasks and put one activity under it + final Task parent = new TaskBuilder(mSupervisor).build(); + final Task adjacentParent = new TaskBuilder(mSupervisor).build(); + parent.setAdjacentTaskFragment(adjacentParent, true); + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setParentTask(parent) + .setCreateTask(true).build(); + + // Launch the activity to its adjacent parent + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchRootTask(adjacentParent.mRemoteToken.toWindowContainerToken()); + prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */) + .setReason("testAdjustLaunchTargetWithAdjacentTask") + .setIntent(activity.intent) + .setActivityOptions(options.toBundle()) + .execute(); + + // Verify the activity will be launched into the original parent + assertTrue(activity.isDescendantOf(parent)); + } + /** * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will * move the existing task to front if the current focused root task doesn't have running task.