diff options
7 files changed, 81 insertions, 21 deletions
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java index fa5195727afe..23a1224fcc4e 100644 --- a/core/java/android/window/TaskFragmentInfo.java +++ b/core/java/android/window/TaskFragmentInfo.java @@ -102,6 +102,8 @@ public final class TaskFragmentInfo implements Parcelable { @NonNull private final Point mMinimumDimensions = new Point(); + private final boolean mIsTopNonFishingChild; + /** @hide */ public TaskFragmentInfo( @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token, @@ -110,7 +112,7 @@ public final class TaskFragmentInfo implements Parcelable { @NonNull List<IBinder> inRequestedTaskFragmentActivities, @NonNull Point positionInParent, boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip, boolean isClearedForReorderActivityToFront, - @NonNull Point minimumDimensions) { + @NonNull Point minimumDimensions, boolean isTopNonFinishingChild) { mFragmentToken = requireNonNull(fragmentToken); mToken = requireNonNull(token); mConfiguration.setTo(configuration); @@ -123,6 +125,7 @@ public final class TaskFragmentInfo implements Parcelable { mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip; mIsClearedForReorderActivityToFront = isClearedForReorderActivityToFront; mMinimumDimensions.set(minimumDimensions); + mIsTopNonFishingChild = isTopNonFinishingChild; } @NonNull @@ -212,6 +215,16 @@ public final class TaskFragmentInfo implements Parcelable { } /** + * Indicates that this TaskFragment is the top non-finishing child of its parent container + * among all Activities and TaskFragment siblings. + * + * @hide + */ + public boolean isTopNonFinishingChild() { + return mIsTopNonFishingChild; + } + + /** * Returns {@code true} if the parameters that are important for task fragment organizers are * equal between this {@link TaskFragmentInfo} and {@param that}. * Note that this method is usually called with @@ -236,7 +249,8 @@ public final class TaskFragmentInfo implements Parcelable { && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip && mIsClearedForReorderActivityToFront == that.mIsClearedForReorderActivityToFront - && mMinimumDimensions.equals(that.mMinimumDimensions); + && mMinimumDimensions.equals(that.mMinimumDimensions) + && mIsTopNonFishingChild == that.mIsTopNonFishingChild; } private TaskFragmentInfo(Parcel in) { @@ -252,6 +266,7 @@ public final class TaskFragmentInfo implements Parcelable { mIsTaskFragmentClearedForPip = in.readBoolean(); mIsClearedForReorderActivityToFront = in.readBoolean(); mMinimumDimensions.readFromParcel(in); + mIsTopNonFishingChild = in.readBoolean(); } /** @hide */ @@ -269,6 +284,7 @@ public final class TaskFragmentInfo implements Parcelable { dest.writeBoolean(mIsTaskFragmentClearedForPip); dest.writeBoolean(mIsClearedForReorderActivityToFront); mMinimumDimensions.writeToParcel(dest, flags); + dest.writeBoolean(mIsTopNonFishingChild); } @NonNull @@ -299,6 +315,7 @@ public final class TaskFragmentInfo implements Parcelable { + " isTaskFragmentClearedForPip=" + mIsTaskFragmentClearedForPip + " mIsClearedForReorderActivityToFront=" + mIsClearedForReorderActivityToFront + " minimumDimensions=" + mMinimumDimensions + + " isTopNonFinishingChild=" + mIsTopNonFishingChild + "}"; } 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 e71d844ade59..409cde30cf8c 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -2759,9 +2759,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // in the same task, the overlay will be dismissed in case an activity above // the overlay is dismissed and the overlay is shown unexpectedly. for (final TaskFragmentContainer overlayContainer : overlayContainers) { - final boolean isTopNonFinishingOverlay = overlayContainer.equals( - overlayContainer.getTaskContainer().getTopNonFinishingTaskFragmentContainer( - true /* includePin */, true /* includeOverlay */)); + final boolean isTopNonFinishingOverlay = overlayContainer.isTopNonFinishingChild(); final boolean areInSameTask = taskId == overlayContainer.getTaskId(); final boolean haveSameTag = overlayTag.equals(overlayContainer.getOverlayTag()); if (!associateLaunchingActivity && overlayContainer.isAlwaysOnTopOverlay() diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java index 7173b0c95230..d0e2c998e961 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -340,6 +340,13 @@ class TaskFragmentContainer { return mInfo != null && mInfo.isVisible(); } + /** + * See {@link TaskFragmentInfo#isTopNonFinishingChild()} + */ + boolean isTopNonFinishingChild() { + return mInfo != null && mInfo.isTopNonFinishingChild(); + } + /** Whether the TaskFragment is in an intermediate state waiting for the server update.*/ boolean isInIntermediateState() { if (mInfo == null) { 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 d649c6d57137..7dc78fdd601f 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 @@ -163,12 +163,14 @@ public class EmbeddingTestUtils { } /** Creates a mock TaskFragmentInfo for the given TaskFragment. */ + @NonNull static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container, @NonNull Activity activity) { return createMockTaskFragmentInfo(container, activity, true /* isVisible */); } /** Creates a mock TaskFragmentInfo for the given TaskFragment. */ + @NonNull static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container, @NonNull Activity activity, boolean isVisible) { return new TaskFragmentInfo(container.getTaskFragmentToken(), @@ -182,7 +184,27 @@ public class EmbeddingTestUtils { false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */, false /* isClearedForReorderActivityToFront */, - new Point()); + new Point(), + false /* isTopChild */); + } + + /** Creates a mock TaskFragmentInfo for the given TaskFragment. */ + @NonNull + static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container, + @NonNull Activity activity, boolean isVisible, boolean isOnTop) { + return new TaskFragmentInfo(container.getTaskFragmentToken(), + mock(WindowContainerToken.class), + new Configuration(), + 1, + isVisible, + Collections.singletonList(activity.getActivityToken()), + new ArrayList<>(), + new Point(), + false /* isTaskClearedForReuse */, + false /* isTaskFragmentClearedForPip */, + false /* isClearedForReorderActivityToFront */, + new Point(), + isOnTop); } static ActivityInfo createActivityInfoWithMinDimensions() { 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 ad41b18dcbc6..8911d18b9b97 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 @@ -114,6 +114,7 @@ public class JetpackTaskFragmentOrganizerTest { mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */, false /* isVisible */, new ArrayList<>(), new ArrayList<>(), new Point(), false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */, - false /* isClearedForReorderActivityToFront */, new Point()); + false /* isClearedForReorderActivityToFront */, new Point(), + false /* isTopChild */); } } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java index f799bf9a1052..475475b05272 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java @@ -269,7 +269,7 @@ public class OverlayPresentationTest { } @Test - public void testCreateOrUpdateOverlay_visibleOverlayInTask_dismissOverlay() { + public void testCreateOrUpdateOverlay_topOverlayInTask_dismissOverlay() { createExistingOverlayContainers(); final TaskFragmentContainer overlayContainer = @@ -400,13 +400,13 @@ public class OverlayPresentationTest { } private void createExistingOverlayContainers() { - createExistingOverlayContainers(true /* visible */); + createExistingOverlayContainers(true /* isOnTop */); } - private void createExistingOverlayContainers(boolean visible) { - mOverlayContainer1 = createTestOverlayContainer(TASK_ID, "test1", visible, + private void createExistingOverlayContainers(boolean isOnTop) { + mOverlayContainer1 = createTestOverlayContainer(TASK_ID, "test1", isOnTop, true /* associatedLaunchingActivity */, mActivity); - mOverlayContainer2 = createTestOverlayContainer(TASK_ID + 1, "test2", visible); + mOverlayContainer2 = createTestOverlayContainer(TASK_ID + 1, "test2", isOnTop); List<TaskFragmentContainer> overlayContainers = mSplitController .getAllNonFinishingOverlayContainers(); assertThat(overlayContainers).containsExactly(mOverlayContainer1, mOverlayContainer2); @@ -1004,10 +1004,10 @@ public class OverlayPresentationTest { /** Creates a mock TaskFragment that has been registered and appeared in the organizer. */ @NonNull private TaskFragmentContainer createMockTaskFragmentContainer( - @NonNull Activity activity, boolean isVisible) { + @NonNull Activity activity, boolean isOnTop) { final TaskFragmentContainer container = createTfContainer(mSplitController, activity.getTaskId(), activity); - setupTaskFragmentInfo(container, activity, isVisible); + setupTaskFragmentInfo(container, activity, isOnTop); return container; } @@ -1019,8 +1019,8 @@ public class OverlayPresentationTest { @NonNull private TaskFragmentContainer createTestOverlayContainer(int taskId, @NonNull String tag, - boolean isVisible) { - return createTestOverlayContainer(taskId, tag, isVisible, + boolean isOnTop) { + return createTestOverlayContainer(taskId, tag, isOnTop, true /* associateLaunchingActivity */); } @@ -1033,7 +1033,7 @@ public class OverlayPresentationTest { @NonNull private TaskFragmentContainer createTestOverlayContainer(int taskId, @NonNull String tag, - boolean isVisible, boolean associateLaunchingActivity, + boolean isOnTop, boolean associateLaunchingActivity, @Nullable Activity launchingActivity) { final Activity activity = launchingActivity != null ? launchingActivity : createMockActivity(); @@ -1044,14 +1044,15 @@ public class OverlayPresentationTest { .setLaunchOptions(Bundle.EMPTY) .setAssociatedActivity(associateLaunchingActivity ? activity : null) .build(); - setupTaskFragmentInfo(overlayContainer, createMockActivity(), isVisible); + setupTaskFragmentInfo(overlayContainer, createMockActivity(), isOnTop); return overlayContainer; } private void setupTaskFragmentInfo(@NonNull TaskFragmentContainer container, @NonNull Activity activity, - boolean isVisible) { - final TaskFragmentInfo info = createMockTaskFragmentInfo(container, activity, isVisible); + boolean isOnTop) { + final TaskFragmentInfo info = createMockTaskFragmentInfo(container, activity, isOnTop, + isOnTop); container.setInfo(mTransaction, info); mSplitPresenter.mFragmentInfos.put(container.getTaskFragmentToken(), info); } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index c83b28055a2f..ed0dc3be9465 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2819,7 +2819,21 @@ class TaskFragment extends WindowContainer<WindowContainer> { mClearedTaskForReuse, mClearedTaskFragmentForPip, mClearedForReorderActivityToFront, - calculateMinDimension()); + calculateMinDimension(), + isTopNonFinishingChild()); + } + + private boolean isTopNonFinishingChild() { + final WindowContainer<?> parent = getParent(); + if (parent == null) { + // Either the TaskFragment is not attached or is going to destroy. Return false. + return false; + } + final ActivityRecord topNonFishingActivity = parent.getActivity(ar -> !ar.finishing); + // If the parent's top non-finishing activity is this TaskFragment's, it means + // this TaskFragment is the top non-finishing container of its parent. + return topNonFishingActivity != null && topNonFishingActivity + .equals(getTopNonFinishingActivity()); } /** |