From c5024fc2b453b80db43cf56130f8e01150e343be Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Thu, 26 Aug 2021 11:32:04 +0800 Subject: [PATCH] Not removing primary TaskFragment when clear task Placeholder activity was finished while starting the task root activity from launcher because the task root activity was set as singleTask launch mode. Meanwhile, the primary TaskFragment was also removed because of the split-rule finishPrimaryWithSecondary. Sending the information of whether the last activity on the TaskFragment was finished due to launch other activity to client. So that the organizer can decide whether the primary TaskFragment should removed. Bug: 196179714 Test: relaunch singleTask activity with placeholder Change-Id: I9a0369285adfbdef1edc5a7f2af944ec5b434566 --- core/api/test-current.txt | 1 + .../java/android/window/TaskFragmentInfo.java | 20 +++++++++++++++++-- .../extensions/organizer/SplitController.java | 6 +++++- .../com/android/server/wm/ActivityRecord.java | 5 +++++ .../com/android/server/wm/TaskFragment.java | 11 +++++++++- 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/core/api/test-current.txt b/core/api/test-current.txt index becdd92b5ff6b..f7164cf3761e7 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3234,6 +3234,7 @@ package android.window { method public int getWindowingMode(); method public boolean hasRunningActivity(); method public boolean isEmpty(); + method public boolean isTaskClearedForReuse(); method public boolean isVisible(); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java index b55372b08b3af..165dcdf3a8368 100644 --- a/core/java/android/window/TaskFragmentInfo.java +++ b/core/java/android/window/TaskFragmentInfo.java @@ -71,11 +71,18 @@ public final class TaskFragmentInfo implements Parcelable { /** Relative position of the fragment's top left corner in the parent container. */ private final Point mPositionInParent; + /** + * Whether the last running activity in the TaskFragment was finished due to clearing task while + * launching an activity in the host Task. + */ + private final boolean mIsTaskClearedForReuse; + /** @hide */ public TaskFragmentInfo( @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token, @NonNull Configuration configuration, boolean isEmpty, int runningActivityCount, - boolean isVisible, @NonNull List activities, @NonNull Point positionInParent) { + boolean isVisible, @NonNull List activities, @NonNull Point positionInParent, + boolean isTaskClearedForReuse) { mFragmentToken = requireNonNull(fragmentToken); mToken = requireNonNull(token); mConfiguration.setTo(configuration); @@ -84,6 +91,7 @@ public final class TaskFragmentInfo implements Parcelable { mIsVisible = isVisible; mActivities.addAll(activities); mPositionInParent = requireNonNull(positionInParent); + mIsTaskClearedForReuse = isTaskClearedForReuse; } @NonNull @@ -128,6 +136,10 @@ public final class TaskFragmentInfo implements Parcelable { return mPositionInParent; } + public boolean isTaskClearedForReuse() { + return mIsTaskClearedForReuse; + } + @WindowingMode public int getWindowingMode() { return mConfiguration.windowConfiguration.getWindowingMode(); @@ -149,7 +161,8 @@ public final class TaskFragmentInfo implements Parcelable { && mIsVisible == that.mIsVisible && getWindowingMode() == that.getWindowingMode() && mActivities.equals(that.mActivities) - && mPositionInParent.equals(that.mPositionInParent); + && mPositionInParent.equals(that.mPositionInParent) + && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse; } private TaskFragmentInfo(Parcel in) { @@ -161,6 +174,7 @@ public final class TaskFragmentInfo implements Parcelable { mIsVisible = in.readBoolean(); in.readBinderList(mActivities); mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR)); + mIsTaskClearedForReuse = in.readBoolean(); } /** @hide */ @@ -174,6 +188,7 @@ public final class TaskFragmentInfo implements Parcelable { dest.writeBoolean(mIsVisible); dest.writeBinderList(mActivities); dest.writeTypedObject(mPositionInParent, flags); + dest.writeBoolean(mIsTaskClearedForReuse); } @NonNull @@ -199,6 +214,7 @@ public final class TaskFragmentInfo implements Parcelable { + " runningActivityCount=" + mRunningActivityCount + " isVisible=" + mIsVisible + " positionInParent=" + mPositionInParent + + " isTaskClearedForReuse=" + mIsTaskClearedForReuse + "}"; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java index 05c6792a3fc75..756255017d9fb 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java @@ -130,7 +130,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // Check if there are no running activities - consider the container empty if there are no // non-finishing activities left. if (!taskFragmentInfo.hasRunningActivity()) { - mPresenter.cleanupContainer(container, true /* shouldFinishDependent */); + // Do not finish the dependents if this TaskFragment was cleared due to launching + // activity in the Task. + final boolean shouldFinishDependent = + !taskFragmentInfo.isTaskClearedForReuse(); + mPresenter.cleanupContainer(container, shouldFinishDependent); updateCallbackIfNecessary(); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 73faca70de6b0..d1d33c5846e7e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3505,6 +3505,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A finishing = true; final TaskFragment taskFragment = getTaskFragment(); if (taskFragment != null) { + final Task task = taskFragment.getTask(); + if (task != null && task.isClearingToReuseTask() + && taskFragment.getTopNonFinishingActivity() == null) { + taskFragment.mClearedTaskForReuse = true; + } taskFragment.sendTaskFragmentInfoChanged(); } if (stopped) { diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 7c939e67077ce..ca1d83e2bd15b 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -173,6 +173,12 @@ class TaskFragment extends WindowContainer { */ boolean mTaskFragmentAppearedSent; + /** + * The last running activity of the TaskFragment was finished due to clear task while launching + * an activity in the Task. + */ + boolean mClearedTaskForReuse; + /** * When we are in the process of pausing an activity, before starting the * next one, this variable holds the activity that is currently being paused. @@ -1587,6 +1593,8 @@ class TaskFragment extends WindowContainer { @Override void addChild(WindowContainer child, int index) { + mClearedTaskForReuse = false; + boolean isAddingActivity = child.asActivityRecord() != null; final Task task = isAddingActivity ? getTask() : null; @@ -2093,7 +2101,8 @@ class TaskFragment extends WindowContainer { runningActivityCount[0], isVisible(), childActivities, - positionInParent); + positionInParent, + mClearedTaskForReuse); } @Nullable