diff options
9 files changed, 84 insertions, 24 deletions
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java index e2c8a31cc987..dc60eddaf7db 100644 --- a/core/java/android/window/TaskFragmentInfo.java +++ b/core/java/android/window/TaskFragmentInfo.java @@ -83,6 +83,12 @@ public final class TaskFragmentInfo implements Parcelable { private final boolean mIsTaskFragmentClearedForPip; /** + * Whether the last running activity of the TaskFragment was removed because it was reordered to + * front of the Task. + */ + private final boolean mIsClearedForReorderActivityToFront; + + /** * The maximum {@link ActivityInfo.WindowLayout#minWidth} and * {@link ActivityInfo.WindowLayout#minHeight} aggregated from the TaskFragment's child * activities. @@ -96,7 +102,7 @@ public final class TaskFragmentInfo implements Parcelable { @NonNull Configuration configuration, int runningActivityCount, boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent, boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip, - @NonNull Point minimumDimensions) { + boolean isClearedForReorderActivityToFront, @NonNull Point minimumDimensions) { mFragmentToken = requireNonNull(fragmentToken); mToken = requireNonNull(token); mConfiguration.setTo(configuration); @@ -106,6 +112,7 @@ public final class TaskFragmentInfo implements Parcelable { mPositionInParent.set(positionInParent); mIsTaskClearedForReuse = isTaskClearedForReuse; mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip; + mIsClearedForReorderActivityToFront = isClearedForReorderActivityToFront; mMinimumDimensions.set(minimumDimensions); } @@ -160,6 +167,11 @@ public final class TaskFragmentInfo implements Parcelable { return mIsTaskFragmentClearedForPip; } + /** @hide */ + public boolean isClearedForReorderActivityToFront() { + return mIsClearedForReorderActivityToFront; + } + @WindowingMode public int getWindowingMode() { return mConfiguration.windowConfiguration.getWindowingMode(); @@ -207,6 +219,7 @@ public final class TaskFragmentInfo implements Parcelable { && mPositionInParent.equals(that.mPositionInParent) && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip + && mIsClearedForReorderActivityToFront == that.mIsClearedForReorderActivityToFront && mMinimumDimensions.equals(that.mMinimumDimensions); } @@ -220,6 +233,7 @@ public final class TaskFragmentInfo implements Parcelable { mPositionInParent.readFromParcel(in); mIsTaskClearedForReuse = in.readBoolean(); mIsTaskFragmentClearedForPip = in.readBoolean(); + mIsClearedForReorderActivityToFront = in.readBoolean(); mMinimumDimensions.readFromParcel(in); } @@ -235,6 +249,7 @@ public final class TaskFragmentInfo implements Parcelable { mPositionInParent.writeToParcel(dest, flags); dest.writeBoolean(mIsTaskClearedForReuse); dest.writeBoolean(mIsTaskFragmentClearedForPip); + dest.writeBoolean(mIsClearedForReorderActivityToFront); mMinimumDimensions.writeToParcel(dest, flags); } @@ -262,8 +277,9 @@ public final class TaskFragmentInfo implements Parcelable { + " activities=" + mActivities + " positionInParent=" + mPositionInParent + " isTaskClearedForReuse=" + mIsTaskClearedForReuse - + " isTaskFragmentClearedForPip" + mIsTaskFragmentClearedForPip - + " minimumDimensions" + mMinimumDimensions + + " isTaskFragmentClearedForPip=" + mIsTaskFragmentClearedForPip + + " mIsClearedForReorderActivityToFront=" + mIsClearedForReorderActivityToFront + + " minimumDimensions=" + mMinimumDimensions + "}"; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 16760e26b3f1..d52caaf4c3e8 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -389,6 +389,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // launching activity in the Task. mTransactionManager.getCurrentTransactionRecord().setOriginType(TRANSIT_CLOSE); mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */); + } else if (taskFragmentInfo.isClearedForReorderActivityToFront()) { + // Do not finish the dependents if this TaskFragment was cleared to reorder + // the launching Activity to front of the Task. + mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */); } else if (!container.isWaitingActivityAppear()) { // Do not finish the container before the expected activity appear until // timeout. diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java index 40f7a273980a..92011af27619 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java @@ -169,6 +169,7 @@ public class EmbeddingTestUtils { new Point(), false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */, + false /* isClearedForReorderActivityToFront */, new Point()); } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java index 957a24873998..79813c7d064e 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java @@ -144,6 +144,6 @@ public class JetpackTaskFragmentOrganizerTest { mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */, false /* isVisible */, new ArrayList<>(), new Point(), false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */, - new Point()); + false /* isClearedForReorderActivityToFront */, new Point()); } } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index a857d900d771..3ec24d5d4d7d 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2136,7 +2136,7 @@ class ActivityStarter { mStartActivity.mUserId); if (act != null) { final Task task = act.getTask(); - boolean actuallyMoved = task.moveActivityToFrontLocked(act); + boolean actuallyMoved = task.moveActivityToFront(act); if (actuallyMoved) { // Only record if the activity actually moved. mMovedToTopActivity = act; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index dfb61a8cf989..51d4bd220bc1 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1401,13 +1401,26 @@ class Task extends TaskFragment { * Reorder the history task so that the passed activity is brought to the front. * @return whether it was actually moved (vs already being top). */ - final boolean moveActivityToFrontLocked(ActivityRecord newTop) { + final boolean moveActivityToFront(ActivityRecord newTop) { ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to root task at top " + "callers=%s", newTop, Debug.getCallers(4)); - int origDist = getDistanceFromTop(newTop); - positionChildAtTop(newTop); + final TaskFragment taskFragment = newTop.getTaskFragment(); + boolean moved; + if (taskFragment != this) { + if (taskFragment.isEmbedded() && taskFragment.getNonFinishingActivityCount() == 1) { + taskFragment.mClearedForReorderActivityToFront = true; + } + newTop.reparent(this, POSITION_TOP); + moved = true; + if (taskFragment.isEmbedded()) { + mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController + .onActivityReparentedToTask(newTop); + } + } else { + moved = moveChildToFront(newTop); + } updateEffectiveIntent(); - return getDistanceFromTop(newTop) != origDist; + return moved; } @Override @@ -3075,20 +3088,6 @@ class Task extends TaskFragment { }); } - void positionChildAtTop(ActivityRecord child) { - positionChildAt(child, POSITION_TOP); - } - - void positionChildAt(ActivityRecord child, int position) { - if (child == null) { - Slog.w(TAG_WM, - "Attempted to position of non-existing app"); - return; - } - - positionChildAt(position, child, false /* includeParents */); - } - void setTaskDescription(TaskDescription taskDescription) { mTaskDescription = taskDescription; } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 6588f26c513a..911a8da1db99 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -249,6 +249,12 @@ class TaskFragment extends WindowContainer<WindowContainer> { boolean mClearedTaskFragmentForPip; /** + * The last running activity of the TaskFragment was removed and added to the top-most of the + * Task because it was launched with FLAG_ACTIVITY_REORDER_TO_FRONT. + */ + boolean mClearedForReorderActivityToFront; + + /** * 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. * @@ -1868,6 +1874,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { ActivityRecord r = topRunningActivity(); mClearedTaskForReuse = false; mClearedTaskFragmentForPip = false; + mClearedForReorderActivityToFront = false; final ActivityRecord addingActivity = child.asActivityRecord(); final boolean isAddingActivity = addingActivity != null; @@ -2456,6 +2463,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { positionInParent, mClearedTaskForReuse, mClearedTaskFragmentForPip, + mClearedForReorderActivityToFront, calculateMinDimension()); } @@ -2742,6 +2750,16 @@ class TaskFragment extends WindowContainer<WindowContainer> { return callback.test(this) ? this : null; } + /** + * Moves the passed child to front + * @return whether it was actually moved (vs already being top). + */ + boolean moveChildToFront(WindowContainer newTop) { + int origDist = getDistanceFromTop(newTop); + positionChildAt(POSITION_TOP, newTop, false /* includeParents */); + return getDistanceFromTop(newTop) != origDist; + } + String toFullString() { final StringBuilder sb = new StringBuilder(128); sb.append(this); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index bd8da4e713b7..079897bc099f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2806,7 +2806,7 @@ public class ActivityRecordTests extends WindowTestsBase { final Task task = activity.getTask(); final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); topActivity.setVisible(false); - task.positionChildAt(topActivity, POSITION_TOP); + task.positionChildAt(POSITION_TOP, topActivity, false /* includeParents */); activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false, true, false, false, false); waitUntilHandlersIdle(); 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 0b6cea28e86b..d52c34bdc9e1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -36,6 +36,7 @@ import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_90; import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; @@ -80,6 +81,7 @@ import android.util.DisplayMetrics; import android.util.Xml; import android.view.Display; import android.view.DisplayInfo; +import android.window.TaskFragmentOrganizer; import androidx.test.filters.MediumTest; @@ -1489,6 +1491,26 @@ public class TaskTests extends WindowTestsBase { tf0, parentTask.getTaskFragment(TaskFragment::isOrganizedTaskFragment)); } + @Test + public void testReorderActivityToFront() { + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); + doNothing().when(task).onActivityVisibleRequestedChanged(); + final ActivityRecord activity = task.getTopMostActivity(); + + final TaskFragment fragment = createTaskFragmentWithEmbeddedActivity(task, organizer); + final ActivityRecord embeddedActivity = fragment.getTopMostActivity(); + task.moveActivityToFront(activity); + assertEquals("Activity must be moved to front", activity, task.getTopMostActivity()); + + doNothing().when(fragment).sendTaskFragmentInfoChanged(); + task.moveActivityToFront(embeddedActivity); + assertEquals("Activity must be moved to front", embeddedActivity, + task.getTopMostActivity()); + assertEquals("Activity must not be embedded", embeddedActivity, + task.getTopChild()); + } + private Task getTestTask() { final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); return task.getBottomMostTask(); |