From c4e6a6f30c9e59c88074d4b2138e42df10f132f3 Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Tue, 31 May 2022 16:45:02 +0800 Subject: [PATCH] Adding the new activity on the same TF of the cleared activity While starting an activity with FLAG_ACTIVITY_CLEAR_TOP, the existing activity could also be finished and therefore the new activity is added on the same TF of the top running activity. However, the top running activity could be on a TF which is different from the cleared activity. Bug: 233860721 Test: start Settings' shortcut activity Test: atest TaskTests Change-Id: I5607a2737e7d0d5986adf14f44f169791da3d38a --- .../android/server/wm/ActivityStarter.java | 35 +++++++++++++------ .../core/java/com/android/server/wm/Task.java | 3 +- .../src/com/android/server/wm/TaskTests.java | 2 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index b2f27ebaf5133..618c49ce0c7ce 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -192,6 +192,7 @@ class ActivityStarter { private Task mInTask; private TaskFragment mInTaskFragment; + private TaskFragment mAddingToTaskFragment; @VisibleForTesting boolean mAddingToTask; @@ -2254,20 +2255,27 @@ class ActivityStarter { // In this situation we want to remove all activities from the task up to the one // being started. In most cases this means we are resetting the task to its initial // state. - final ActivityRecord top = targetTask.performClearTop(mStartActivity, mLaunchFlags); + final ActivityRecord clearTop = targetTask.performClearTop(mStartActivity, + mLaunchFlags); - if (top != null) { - if (top.isRootOfTask()) { + if (clearTop != null && !clearTop.finishing) { + if (clearTop.isRootOfTask()) { // Activity aliases may mean we use different intents for the top activity, // so make sure the task now has the identity of the new intent. - top.getTask().setIntent(mStartActivity); + clearTop.getTask().setIntent(mStartActivity); } - deliverNewIntent(top, intentGrants); + deliverNewIntent(clearTop, intentGrants); } else { // A special case: we need to start the activity because it is not currently // running, and the caller has asked to clear the current task to have this // activity at the top. mAddingToTask = true; + // Adding the new activity to the same embedded TF of the clear-top activity if + // possible. + if (clearTop != null && clearTop.getTaskFragment() != null + && clearTop.getTaskFragment().isEmbedded()) { + mAddingToTaskFragment = clearTop.getTaskFragment(); + } if (targetTask.getRootTask() == null) { // Target root task got cleared when we all activities were removed above. // Go ahead and reset it. @@ -2892,14 +2900,19 @@ class ActivityStarter { newParent = mInTaskFragment; } } else { - final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */, - false /* includingEmbeddedTask */); - final TaskFragment taskFragment = top != null ? top.getTaskFragment() : null; - if (taskFragment != null && taskFragment.isEmbedded() - && canEmbedActivity(taskFragment, mStartActivity, false /* newTask */, task)) { + TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null; + if (candidateTf == null) { + final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */, + false /* includingEmbeddedTask */); + if (top != null) { + candidateTf = top.getTaskFragment(); + } + } + if (candidateTf != null && candidateTf.isEmbedded() + && canEmbedActivity(candidateTf, mStartActivity, false /* newTask */, task)) { // Use the embedded TaskFragment of the top activity as the new parent if the // activity can be embedded. - newParent = top.getTaskFragment(); + newParent = candidateTf; } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 7ad53f96a80e2..742918c0652c5 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1644,7 +1644,7 @@ class Task extends TaskFragment { * activities on top of it and return the instance. * * @param newR Description of the new activity being started. - * @return Returns the old activity that should be continued to be used, + * @return Returns the existing activity in the task that performs the clear-top operation, * or {@code null} if none was found. */ private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags) { @@ -1663,7 +1663,6 @@ class Task extends TaskFragment { && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) { if (!r.finishing) { r.finishIfPossible("clear-task-top", false /* oomAdj */); - return null; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 9304761fc1c96..202168bae869a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -266,7 +266,7 @@ public class TaskTests extends WindowTestsBase { // Detach from process so the activities can be removed from hierarchy when finishing. activity1.detachFromProcess(); activity2.detachFromProcess(); - assertNull(task.performClearTop(activity1, 0 /* launchFlags */)); + assertTrue(task.performClearTop(activity1, 0 /* launchFlags */).finishing); assertFalse(task.hasChild()); // In real case, the task should be preserved for adding new activity. assertTrue(task.isAttached());