summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/TaskFragmentParentInfo.java23
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java28
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java10
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java28
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java2
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java8
-rw-r--r--services/core/java/com/android/server/wm/Task.java7
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java1
10 files changed, 117 insertions, 11 deletions
diff --git a/core/java/android/window/TaskFragmentParentInfo.java b/core/java/android/window/TaskFragmentParentInfo.java
index 841354a92192..e6eeca4b4801 100644
--- a/core/java/android/window/TaskFragmentParentInfo.java
+++ b/core/java/android/window/TaskFragmentParentInfo.java
@@ -35,17 +35,21 @@ public class TaskFragmentParentInfo implements Parcelable {
private final boolean mVisible;
+ private final boolean mHasDirectActivity;
+
public TaskFragmentParentInfo(@NonNull Configuration configuration, int displayId,
- boolean visible) {
+ boolean visible, boolean hasDirectActivity) {
mConfiguration.setTo(configuration);
mDisplayId = displayId;
mVisible = visible;
+ mHasDirectActivity = hasDirectActivity;
}
public TaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
mConfiguration.setTo(info.getConfiguration());
mDisplayId = info.mDisplayId;
mVisible = info.mVisible;
+ mHasDirectActivity = info.mHasDirectActivity;
}
/** The {@link Configuration} of the parent Task */
@@ -68,6 +72,14 @@ public class TaskFragmentParentInfo implements Parcelable {
}
/**
+ * Whether the parent Task has any direct child activity, which is not embedded in any
+ * TaskFragment, or not
+ */
+ public boolean hasDirectActivity() {
+ return mHasDirectActivity;
+ }
+
+ /**
* Returns {@code true} if the parameters which are important for task fragment
* organizers are equal between this {@link TaskFragmentParentInfo} and {@code that}.
* Note that this method is usually called with
@@ -80,7 +92,7 @@ public class TaskFragmentParentInfo implements Parcelable {
return false;
}
return getWindowingMode() == that.getWindowingMode() && mDisplayId == that.mDisplayId
- && mVisible == that.mVisible;
+ && mVisible == that.mVisible && mHasDirectActivity == that.mHasDirectActivity;
}
@WindowConfiguration.WindowingMode
@@ -94,6 +106,7 @@ public class TaskFragmentParentInfo implements Parcelable {
+ "config=" + mConfiguration
+ ", displayId=" + mDisplayId
+ ", visible=" + mVisible
+ + ", hasDirectActivity=" + mHasDirectActivity
+ "}";
}
@@ -114,7 +127,8 @@ public class TaskFragmentParentInfo implements Parcelable {
final TaskFragmentParentInfo that = (TaskFragmentParentInfo) obj;
return mConfiguration.equals(that.mConfiguration)
&& mDisplayId == that.mDisplayId
- && mVisible == that.mVisible;
+ && mVisible == that.mVisible
+ && mHasDirectActivity == that.mHasDirectActivity;
}
@Override
@@ -122,6 +136,7 @@ public class TaskFragmentParentInfo implements Parcelable {
int result = mConfiguration.hashCode();
result = 31 * result + mDisplayId;
result = 31 * result + (mVisible ? 1 : 0);
+ result = 31 * result + (mHasDirectActivity ? 1 : 0);
return result;
}
@@ -130,12 +145,14 @@ public class TaskFragmentParentInfo implements Parcelable {
mConfiguration.writeToParcel(dest, flags);
dest.writeInt(mDisplayId);
dest.writeBoolean(mVisible);
+ dest.writeBoolean(mHasDirectActivity);
}
private TaskFragmentParentInfo(Parcel in) {
mConfiguration.readFromParcel(in);
mDisplayId = in.readInt();
mVisible = in.readBoolean();
+ mHasDirectActivity = in.readBoolean();
}
public static final Creator<TaskFragmentParentInfo> CREATOR =
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 49606f0bf485..7743ad55debb 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -1763,6 +1763,15 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return;
}
+ if (container.isFinished()) {
+ return;
+ }
+
+ if (container.isOverlay()) {
+ updateOverlayContainer(wct, container);
+ return;
+ }
+
if (launchPlaceholderIfNecessary(wct, container)) {
// Placeholder was launched, the positions will be updated when the activity is added
// to the secondary container.
@@ -1783,6 +1792,25 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
updateSplitContainerIfNeeded(splitContainer, wct, null /* splitAttributes */);
}
+
+ @VisibleForTesting
+ // Suppress GuardedBy warning because lint ask to mark this method as
+ // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
+ @SuppressWarnings("GuardedBy")
+ @GuardedBy("mLock")
+ void updateOverlayContainer(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer container) {
+ final TaskContainer taskContainer = container.getTaskContainer();
+ // Dismiss the overlay container if it's the only container in the task and there's no
+ // direct activity in the parent task.
+ if (taskContainer.getTaskFragmentContainers().size() == 1
+ && !taskContainer.hasDirectActivity()) {
+ container.finish(false /* shouldFinishDependent */, mPresenter, wct, this);
+ }
+
+ // TODO(b/295805054): Add the logic to update overlay container
+ }
+
/**
* Updates {@link SplitContainer} with the given {@link SplitAttributes} if the
* {@link SplitContainer} is the top most and not finished. If passed {@link SplitAttributes}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 9e533808ccc0..eeb3ccf0d4cb 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -75,6 +75,8 @@ class TaskContainer {
private boolean mIsVisible;
+ private boolean mHasDirectActivity;
+
/**
* TaskFragments that the organizer has requested to be closed. They should be removed when
* the organizer receives
@@ -102,8 +104,9 @@ class TaskContainer {
mConfiguration = taskProperties.getConfiguration();
mDisplayId = taskProperties.getDisplayId();
// Note that it is always called when there's a new Activity is started, which implies
- // the host task is visible.
+ // the host task is visible and has an activity in the task.
mIsVisible = true;
+ mHasDirectActivity = true;
}
int getTaskId() {
@@ -118,6 +121,10 @@ class TaskContainer {
return mIsVisible;
}
+ boolean hasDirectActivity() {
+ return mHasDirectActivity;
+ }
+
@NonNull
TaskProperties getTaskProperties() {
return new TaskProperties(mDisplayId, mConfiguration);
@@ -127,6 +134,7 @@ class TaskContainer {
mConfiguration.setTo(info.getConfiguration());
mDisplayId = info.getDisplayId();
mIsVisible = info.isVisible();
+ mHasDirectActivity = info.hasDirectActivity();
}
/**
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 405f0b2f51dc..e74d5fb4d0be 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
@@ -58,6 +58,7 @@ import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentParentInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -413,6 +414,33 @@ public class OverlayPresentationTest {
.isEqualTo(overlayContainer);
}
+ @Test
+ public void testUpdateContainer_dontInvokeUpdateOverlayForNonOverlayContainer() {
+ TaskFragmentContainer taskFragmentContainer = createMockTaskFragmentContainer(mActivity);
+
+ mSplitController.updateContainer(mTransaction, taskFragmentContainer);
+ verify(mSplitController, never()).updateOverlayContainer(any(), any());
+ }
+
+ @Test
+ public void testUpdateOverlayContainer_dismissOverlayIfNeeded() {
+ TaskFragmentContainer overlayContainer = createTestOverlayContainer(TASK_ID, "test");
+
+ mSplitController.updateOverlayContainer(mTransaction, overlayContainer);
+
+ final TaskContainer taskContainer = overlayContainer.getTaskContainer();
+ assertThat(taskContainer.getTaskFragmentContainers()).containsExactly(overlayContainer);
+
+ taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(Configuration.EMPTY,
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
+
+ mSplitController.updateOverlayContainer(mTransaction, overlayContainer);
+
+ assertWithMessage("The overlay must be dismissed since there's no activity"
+ + " in the task and other taskFragment.")
+ .that(taskContainer.getTaskFragmentContainers()).isEmpty();
+ }
+
/**
* A simplified version of {@link SplitController.ActivityStartMonitor
* #createOrUpdateOverlayTaskFragmentIfNeeded}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 96839c57d745..02031a67e7e3 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -1139,7 +1139,7 @@ public class SplitControllerTest {
public void testOnTransactionReady_taskFragmentParentInfoChanged() {
final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
final TaskFragmentParentInfo parentInfo = new TaskFragmentParentInfo(Configuration.EMPTY,
- DEFAULT_DISPLAY, true);
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */);
transaction.addChange(new TaskFragmentTransaction.Change(
TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
.setTaskId(TASK_ID)
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index 21889960a8b2..e3f51697c284 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -79,14 +79,14 @@ public class TaskContainerTest {
configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
- DEFAULT_DISPLAY, true /* visible */));
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
assertEquals(WINDOWING_MODE_MULTI_WINDOW,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
- DEFAULT_DISPLAY, true /* visible */));
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
assertEquals(WINDOWING_MODE_FREEFORM,
taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
@@ -106,13 +106,13 @@ public class TaskContainerTest {
configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
- DEFAULT_DISPLAY, true /* visible */));
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
assertFalse(taskContainer.isInPictureInPicture());
configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
- DEFAULT_DISPLAY, true /* visible */));
+ DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
assertTrue(taskContainer.isInPictureInPicture());
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6c31e3e69350..12ef22841a4d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3643,7 +3643,7 @@ class Task extends TaskFragment {
*/
TaskFragmentParentInfo getTaskFragmentParentInfo() {
return new TaskFragmentParentInfo(getConfiguration(), getDisplayId(),
- shouldBeVisible(null /* starting */));
+ shouldBeVisible(null /* starting */), hasNonFinishingDirectActivity());
}
@Override
@@ -6056,6 +6056,11 @@ class Task extends TaskFragment {
// Non-root task position changed.
mRootWindowContainer.invalidateTaskLayers();
}
+
+ if (child.asActivityRecord() != null) {
+ // Send for TaskFragmentParentInfo#hasDirectActivity change.
+ sendTaskFragmentParentInfoChangedIfNeeded();
+ }
}
void reparent(TaskDisplayArea newParent, boolean onTop) {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 82d34246f857..2fc531a4e9f6 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1049,6 +1049,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return getActivity(ActivityRecord::canBeTopRunning);
}
+ /**
+ * Reports non-finishing activity count including this TaskFragment's child embedded
+ * TaskFragments' children activities.
+ */
int getNonFinishingActivityCount() {
final int[] runningActivityCount = new int[1];
forAllActivities(a -> {
@@ -1059,6 +1063,20 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return runningActivityCount[0];
}
+ /**
+ * Returns {@code true} if there's any non-finishing direct children activity, which is not
+ * embedded in TaskFragments
+ */
+ boolean hasNonFinishingDirectActivity() {
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ActivityRecord activity = getChildAt(i).asActivityRecord();
+ if (activity != null && !activity.finishing) {
+ return true;
+ }
+ }
+ return false;
+ }
+
boolean isTopActivityFocusable() {
final ActivityRecord r = topRunningActivity();
return r != null ? r.isFocusable()
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 6235b3b67145..c57b05130e77 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -1742,6 +1742,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
private void testApplyTransaction_reorder_failsIfNotSystemOrganizer_common(
@TaskFragmentOperation.OperationType int opType) {
final Task task = createTask(mDisplayContent);
+ doNothing().when(task).sendTaskFragmentParentInfoChangedIfNeeded();
// Create a non-embedded Activity at the bottom.
final ActivityRecord bottomActivity = new ActivityBuilder(mAtm)
.setTask(task)
@@ -1934,7 +1935,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
/** Setups the mock Task as the parent of the given TaskFragment. */
private static void setupMockParent(TaskFragment taskFragment, Task mockParent) {
doReturn(mockParent).when(taskFragment).getTask();
- doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true))
+ doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true, true))
.when(mockParent).getTaskFragmentParentInfo();
// Task needs to be visible
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 0c580697bc4a..435a8357dabb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -1568,6 +1568,7 @@ public class TaskTests extends WindowTestsBase {
final TaskFragment fragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
final ActivityRecord embeddedActivity = fragment.getTopMostActivity();
+ doNothing().when(task).sendTaskFragmentParentInfoChangedIfNeeded();
task.moveActivityToFront(activity);
assertEquals("Activity must be moved to front", activity, task.getTopMostActivity());