Merge changes from topic "reparentTasks"
* changes:
1/ Refactor LegacySplitScreenTests
Support WCT#reparentTasks and WCT#setLaunchRoot
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c03461a..1422561 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2512,7 +2512,6 @@
method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
method @BinderThread public void removeStartingWindow(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer();
}
@@ -2527,6 +2526,7 @@
method public int describeContents();
method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean);
method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int);
method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
@@ -2534,6 +2534,7 @@
method @NonNull public android.window.WindowContainerTransaction setBoundsChangeTransaction(@NonNull android.window.WindowContainerToken, @NonNull android.view.SurfaceControl.Transaction);
method @NonNull public android.window.WindowContainerTransaction setFocusable(@NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction setHidden(@NonNull android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction setLaunchRoot(@NonNull android.window.WindowContainerToken, @Nullable int[], @Nullable int[]);
method @NonNull public android.window.WindowContainerTransaction setScreenSizeDp(@NonNull android.window.WindowContainerToken, int, int);
method @NonNull public android.window.WindowContainerTransaction setSmallestScreenWidthDp(@NonNull android.window.WindowContainerToken, int);
method @NonNull public android.window.WindowContainerTransaction setWindowingMode(@NonNull android.window.WindowContainerToken, int);
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 4a43a43..2d0211e 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -56,12 +56,6 @@
WindowContainerToken getImeTarget(int display);
/**
- * Set's the root task to launch new tasks into on a display. {@code null} means no launch root
- * and thus new tasks just end up directly on the display.
- */
- void setLaunchRoot(int displayId, in WindowContainerToken root);
-
- /**
* Requests that the given task organizer is notified when back is pressed on the root activity
* of one of its controlled tasks.
*/
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 73b2fe1..f29eb39 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -184,19 +184,6 @@
}
/**
- * Set's the root task to launch new tasks into on a display. {@code null} means no launch
- * root and thus new tasks just end up directly on the display.
- */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
- public void setLaunchRoot(int displayId, @NonNull WindowContainerToken root) {
- try {
- mTaskOrganizerController.setLaunchRoot(displayId, root);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Requests that the given task organizer is notified when back is pressed on the root activity
* of one of its controlled tasks.
*/
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index eba4fd2..6bc3110 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -30,6 +30,7 @@
import android.view.SurfaceControl;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -263,8 +264,9 @@
@NonNull
public WindowContainerTransaction reparent(@NonNull WindowContainerToken child,
@Nullable WindowContainerToken parent, boolean onTop) {
- mHierarchyOps.add(new HierarchyOp(child.asBinder(),
- parent == null ? null : parent.asBinder(), onTop));
+ mHierarchyOps.add(HierarchyOp.createForReparent(child.asBinder(),
+ parent == null ? null : parent.asBinder(),
+ onTop));
return this;
}
@@ -276,7 +278,47 @@
*/
@NonNull
public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop) {
- mHierarchyOps.add(new HierarchyOp(child.asBinder(), onTop));
+ mHierarchyOps.add(HierarchyOp.createForReorder(child.asBinder(), onTop));
+ return this;
+ }
+
+ /**
+ * Reparent's all children tasks of {@param currentParent} in the specified
+ * {@param windowingMode} and {@param activityType} to {@param newParent} in their current
+ * z-order.
+ *
+ * @param currentParent of the tasks to perform the operation no.
+ * {@code null} will perform the operation on the display.
+ * @param newParent for the tasks. {@code null} will perform the operation on the display.
+ * @param windowingModes of the tasks to reparent.
+ * @param activityTypes of the tasks to reparent.
+ * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
+ * the bottom.
+ */
+ @NonNull
+ public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent,
+ @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes,
+ @Nullable int[] activityTypes, boolean onTop) {
+ mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent(
+ currentParent != null ? currentParent.asBinder() : null,
+ newParent != null ? newParent.asBinder() : null,
+ windowingModes,
+ activityTypes,
+ onTop));
+ return this;
+ }
+
+ /**
+ * Sets whether a container should be the launch root for the specified windowing mode and
+ * activity type. This currently only applies to Task containers created by organizer.
+ */
+ @NonNull
+ public WindowContainerTransaction setLaunchRoot(@NonNull WindowContainerToken container,
+ @Nullable int[] windowingModes, @Nullable int[] activityTypes) {
+ mHierarchyOps.add(HierarchyOp.createForSetLaunchRoot(
+ container.asBinder(),
+ windowingModes,
+ activityTypes));
return this;
}
@@ -363,6 +405,7 @@
private boolean mFocusable = true;
private boolean mHidden = false;
private boolean mIgnoreOrientationRequest = false;
+
private int mChangeMask = 0;
private @ActivityInfo.Config int mConfigSetMask = 0;
private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
@@ -595,6 +638,14 @@
* @hide
*/
public static class HierarchyOp implements Parcelable {
+ public static final int HIERARCHY_OP_TYPE_REPARENT = 0;
+ public static final int HIERARCHY_OP_TYPE_REORDER = 1;
+ public static final int HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT = 2;
+ public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT = 3;
+
+ private final int mType;
+
+ // Container we are performing the operation on.
private final IBinder mContainer;
// If this is same as mContainer, then only change position, don't reparent.
@@ -603,32 +654,68 @@
// Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
private final boolean mToTop;
- public HierarchyOp(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
- mContainer = container;
- mReparent = reparent;
- mToTop = toTop;
+ final private int[] mWindowingModes;
+ final private int[] mActivityTypes;
+
+ public static HierarchyOp createForReparent(
+ @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
+ return new HierarchyOp(HIERARCHY_OP_TYPE_REPARENT,
+ container, reparent, null, null, toTop);
}
- public HierarchyOp(@NonNull IBinder container, boolean toTop) {
+ public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop) {
+ return new HierarchyOp(HIERARCHY_OP_TYPE_REORDER,
+ container, container, null, null, toTop);
+ }
+
+ public static HierarchyOp createForChildrenTasksReparent(IBinder currentParent,
+ IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop) {
+ return new HierarchyOp(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT,
+ currentParent, newParent, windowingModes, activityTypes, onTop);
+ }
+
+ public static HierarchyOp createForSetLaunchRoot(IBinder container,
+ int[] windowingModes, int[] activityTypes) {
+ return new HierarchyOp(HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT,
+ container, null, windowingModes, activityTypes, false);
+ }
+
+ private HierarchyOp(int type, @NonNull IBinder container, @Nullable IBinder reparent,
+ int[] windowingModes, int[] activityTypes, boolean toTop) {
+ mType = type;
mContainer = container;
- mReparent = container;
+ mReparent = reparent;
+ mWindowingModes = windowingModes != null ?
+ Arrays.copyOf(windowingModes, windowingModes.length) : null;
+ mActivityTypes = activityTypes != null ?
+ Arrays.copyOf(activityTypes, activityTypes.length) : null;
mToTop = toTop;
}
public HierarchyOp(@NonNull HierarchyOp copy) {
+ mType = copy.mType;
mContainer = copy.mContainer;
mReparent = copy.mReparent;
mToTop = copy.mToTop;
+ mWindowingModes = copy.mWindowingModes;
+ mActivityTypes = copy.mActivityTypes;
}
protected HierarchyOp(Parcel in) {
+ mType = in.readInt();
mContainer = in.readStrongBinder();
mReparent = in.readStrongBinder();
mToTop = in.readBoolean();
+ mWindowingModes = in.createIntArray();
+ mActivityTypes = in.createIntArray();
+ }
+
+ public int getType() {
+ return mType;
}
public boolean isReparent() {
- return mContainer != mReparent;
+ return mType == HIERARCHY_OP_TYPE_REPARENT;
}
@Nullable
@@ -645,21 +732,45 @@
return mToTop;
}
+ public int[] getWindowingModes() {
+ return mWindowingModes;
+ }
+
+ public int[] getActivityTypes() {
+ return mActivityTypes;
+ }
+
@Override
public String toString() {
- if (isReparent()) {
- return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ")
- + mReparent + "}";
- } else {
- return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
+ switch (mType) {
+ case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
+ return "{ChildrenTasksReparent: from=" + mContainer + " to=" + mReparent
+ + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes
+ + " mActivityType=" + mActivityTypes + "}";
+ case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT:
+ return "{SetLaunchRoot: container=" + mContainer
+ + " mWindowingMode=" + mWindowingModes
+ + " mActivityType=" + mActivityTypes + "}";
+ case HIERARCHY_OP_TYPE_REPARENT:
+ return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ")
+ + mReparent + "}";
+ case HIERARCHY_OP_TYPE_REORDER:
+ return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
+ default:
+ return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
+ + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes
+ + " mActivityType=" + mActivityTypes + "}";
}
}
@Override
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mType);
dest.writeStrongBinder(mContainer);
dest.writeStrongBinder(mReparent);
dest.writeBoolean(mToTop);
+ dest.writeIntArray(mWindowingModes);
+ dest.writeIntArray(mActivityTypes);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
index ad05e6d..a8cd1dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
@@ -18,7 +18,10 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
@@ -54,6 +57,17 @@
private static final String TAG = "WindowManagerProxy";
private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS};
+ private static final int[] CONTROLLED_ACTIVITY_TYPES = {
+ ACTIVITY_TYPE_STANDARD,
+ ACTIVITY_TYPE_HOME,
+ ACTIVITY_TYPE_RECENTS,
+ ACTIVITY_TYPE_UNDEFINED
+ };
+ private static final int[] CONTROLLED_WINDOWING_MODES = {
+ WINDOWING_MODE_FULLSCREEN,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ WINDOWING_MODE_UNDEFINED
+ };
@GuardedBy("mDockedRect")
private final Rect mDockedRect = new Rect();
@@ -191,8 +205,9 @@
// Set launchtile first so that any stack created after
// getAllRootTaskInfos and before reparent (even if unlikely) are placed
// correctly.
- mTaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token);
WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setLaunchRoot(tiles.mSecondary.token, CONTROLLED_WINDOWING_MODES,
+ CONTROLLED_ACTIVITY_TYPES);
final boolean isHomeResizable = buildEnterSplit(wct, tiles, layout);
applySyncTransaction(wct);
return isHomeResizable;
@@ -251,12 +266,12 @@
/** @see #buildDismissSplit */
void applyDismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
boolean dismissOrMaximize) {
- // Set launch root first so that any task created after getChildContainers and
- // before reparent (pretty unlikely) are put into fullscreen.
- mTaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null);
// TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
// plus specific APIs to clean this up.
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ // Set launch root first so that any task created after getChildContainers and
+ // before reparent (pretty unlikely) are put into fullscreen.
+ wct.setLaunchRoot(tiles.mSecondary.token, null, null);
buildDismissSplit(wct, tiles, layout, dismissOrMaximize);
applySyncTransaction(wct);
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 5ab1c39..8543850 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -44,6 +44,18 @@
}
@JvmOverloads
+fun LayersAssertion.appPairsDividerBecomesVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("dividerLayerBecomesVisible") {
+ this.hidesLayer(FlickerTestBase.DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(FlickerTestBase.DOCKED_STACK_DIVIDER)
+ }
+}
+
+@JvmOverloads
fun LayersAssertion.dockedStackDividerIsVisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
index b33fa55..85bf4a1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
@@ -21,7 +21,6 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.dsl.runWithFlicker
-import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.canSplitScreen
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.isInSplitScreen
@@ -35,6 +34,7 @@
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+
import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
import org.junit.Assert
@@ -59,8 +59,6 @@
rotationName: String,
rotation: Int
) : SplitScreenTestBase(rotationName, rotation) {
- private val letterBox = "Letterbox"
-
private val splitScreenSetup: FlickerBuilder
get() = FlickerBuilder(instrumentation).apply {
val testLaunchActivity = "launch_splitScreen_test_activity"
@@ -91,7 +89,6 @@
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(launcherPackageName))
}
}
}
@@ -114,7 +111,8 @@
rotation, splitScreenApp.defaultWindowName, 169271943)
dockedStackDividerBecomesVisible()
visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(launcherPackageName, splitScreenApp.defaultWindowName)
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+ LIVE_WALLPAPER_PACKAGE_NAME)
)
}
windowManagerTrace {
@@ -148,7 +146,7 @@
rotation, secondaryApp.defaultWindowName, 169271943)
dockedStackDividerBecomesVisible()
visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(launcherPackageName, splitScreenApp.defaultWindowName,
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
secondaryApp.defaultWindowName)
)
}
@@ -157,6 +155,7 @@
showsAppWindow(splitScreenApp.defaultWindowName)
.and().showsAppWindow(secondaryApp.defaultWindowName)
}
+ visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(LAUNCHER_PACKAGE_NAME))
}
}
}
@@ -181,85 +180,14 @@
layersTrace {
dockedStackDividerIsInvisible()
visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(launcherPackageName, nonResizeableApp.defaultWindowName)
+ listOf(LAUNCHER_PACKAGE_NAME, nonResizeableApp.defaultWindowName)
)
}
windowManagerTrace {
end {
hidesAppWindow(nonResizeableApp.defaultWindowName)
}
- }
- }
- }
- }
-
- @Test
- fun testNonResizeableWhenAlreadyInSplitScreenPrimary() {
- val testTag = "testNonResizeableWhenAlreadyInSplitScreenPrimary"
- runWithFlicker(splitScreenSetup) {
- withTestName { testTag }
- repeat {
- TEST_REPETITIONS
- }
- transitions {
- nonResizeableApp.launchViaIntent()
- splitScreenApp.launchViaIntent()
- uiDevice.launchSplitScreen()
- nonResizeableApp.reopenAppFromOverview()
- }
- assertions {
- layersTrace {
- dockedStackDividerIsInvisible()
- end("appsEndingBounds", enabled = false) {
- val displayBounds = WindowUtils.getDisplayBounds(rotation)
- this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds)
- }
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(launcherPackageName, splitScreenApp.defaultWindowName,
- nonResizeableApp.defaultWindowName, letterBox)
- )
- }
- windowManagerTrace {
- end {
- showsAppWindow(nonResizeableApp.defaultWindowName)
- hidesAppWindow(splitScreenApp.defaultWindowName)
- }
- }
- }
- }
- }
-
- @Test
- fun testNonResizeableWhenAlreadyInSplitScreenSecondary() {
- val testTag = "testNonResizeableWhenAlreadyInSplitScreenSecondary"
- runWithFlicker(splitScreenSetup) {
- withTestName { testTag }
- repeat {
- TEST_REPETITIONS
- }
- transitions {
- splitScreenApp.launchViaIntent()
- uiDevice.launchSplitScreen()
- uiDevice.pressBack()
- nonResizeableApp.launchViaIntent()
- }
- assertions {
- layersTrace {
- dockedStackDividerIsInvisible()
- end("appsEndingBounds", enabled = false) {
- val displayBounds = WindowUtils.getDisplayBounds(rotation)
- this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds)
- }
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(launcherPackageName, splitScreenApp.defaultWindowName,
- nonResizeableApp.defaultWindowName, letterBox)
- )
- }
- windowManagerTrace {
- end {
- showsAppWindow(nonResizeableApp.defaultWindowName)
- hidesAppWindow(splitScreenApp.defaultWindowName)
- }
+ visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(LAUNCHER_PACKAGE_NAME))
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
index 573ffc6..9586fd1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
@@ -22,16 +22,20 @@
import com.android.server.wm.flicker.Flicker
import com.android.server.wm.flicker.FlickerTestRunner
import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
import com.android.server.wm.flicker.helpers.isInSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+
import com.android.server.wm.flicker.repetitions
+import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import com.android.wm.shell.flicker.testapp.Components
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -53,23 +57,24 @@
@JvmStatic
fun getParams(): Collection<Array<Any>> {
val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = StandardAppHelper(instrumentation,
- "com.android.wm.shell.flicker.testapp", "SimpleApp")
+ val splitScreenApp = SplitScreenHelper(instrumentation,
+ TEST_APP_SPLITSCREEN_PRIMARY_LABEL,
+ Components.SplitScreenActivity())
- // b/161435597 causes the test not to work on 90 degrees
- return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+ // TODO(b/162923992) Use of multiple segments of flicker spec for testing
+ return FlickerTestRunnerFactory(instrumentation,
+ listOf(Surface.ROTATION_0, Surface.ROTATION_90))
.buildTest { configuration ->
withTestName {
- buildTestTag("exitSplitScreenFromBottom", testApp,
+ buildTestTag("exitSplitScreenFromBottom", splitScreenApp,
configuration)
}
repeat { configuration.repetitions }
setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
eachRun {
- testApp.open()
+ device.wakeUpAndGoToHomeScreen()
+ device.openQuickStepAndClearRecentAppsFromOverview()
+ splitScreenApp.launchViaIntent()
device.launchSplitScreen()
device.waitForIdle()
this.setRotation(configuration.endRotation)
@@ -77,12 +82,10 @@
}
teardown {
eachRun {
- testApp.exit()
- }
- test {
if (device.isInSplitScreen()) {
device.exitSplitScreen()
}
+ splitScreenApp.exit()
}
}
transitions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
index c51c73a..84bfe945 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
@@ -82,7 +82,7 @@
}
layersTrace {
visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(launcherPackageName))
+ listOf(LAUNCHER_PACKAGE_NAME))
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt
new file mode 100644
index 0000000..e9d3eb7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableDismissInLegacySplitScreenTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.legacysplitscreen
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.dsl.runWithFlicker
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest WMShellFlickerTests:NonResizableDismissInLegacySplitScreenTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class NonResizableDismissInLegacySplitScreenTest(
+ rotationName: String,
+ rotation: Int
+) : SplitScreenTestBase(rotationName, rotation) {
+
+ @Test
+ fun testNonResizableDismissInLegacySplitScreenTest() {
+ val testTag = "testNonResizableDismissInLegacySplitScreenTest"
+
+ runWithFlicker(transitionSetup) {
+ withTestName { testTag }
+ repeat { SplitScreenHelper.TEST_REPETITIONS }
+ transitions {
+ nonResizeableApp.launchViaIntent()
+ splitScreenApp.launchViaIntent()
+ device.launchSplitScreen()
+ nonResizeableApp.reopenAppFromOverview()
+ }
+ assertions {
+ layersTrace {
+ dockedStackDividerIsInvisible()
+ end("appsEndingBounds", enabled = false) {
+ val displayBounds = WindowUtils.getDisplayBounds(rotation)
+ this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds)
+ }
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+ nonResizeableApp.defaultWindowName, LETTER_BOX_NAME)
+ )
+ }
+ windowManagerTrace {
+ end {
+ showsAppWindow(nonResizeableApp.defaultWindowName)
+ hidesAppWindow(splitScreenApp.defaultWindowName)
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt
new file mode 100644
index 0000000..b5a36f5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/NonResizableLaunchInLegacySplitScreenTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.legacysplitscreen
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.dsl.runWithFlicker
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest WMShellFlickerTests:NonResizableLaunchInLegacySplitScreenTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class NonResizableLaunchInLegacySplitScreenTest(
+ rotationName: String,
+ rotation: Int
+) : SplitScreenTestBase(rotationName, rotation) {
+
+ @Test
+ fun testNonResizableLaunchInLegacySplitScreenTest() {
+ val testTag = "NonResizableLaunchInLegacySplitScreenTest"
+
+ runWithFlicker(transitionSetup) {
+ withTestName { testTag }
+ repeat { SplitScreenHelper.TEST_REPETITIONS }
+ transitions {
+ nonResizeableApp.launchViaIntent()
+ splitScreenApp.launchViaIntent()
+ device.launchSplitScreen()
+ nonResizeableApp.reopenAppFromOverview()
+ }
+ assertions {
+ layersTrace {
+ dockedStackDividerIsInvisible()
+ end("appsEndingBounds", enabled = false) {
+ val displayBounds = WindowUtils.getDisplayBounds(rotation)
+ this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds)
+ }
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
+ nonResizeableApp.defaultWindowName, LETTER_BOX_NAME)
+ )
+ }
+ windowManagerTrace {
+ end {
+ showsAppWindow(nonResizeableApp.defaultWindowName)
+ hidesAppWindow(splitScreenApp.defaultWindowName)
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
index af03869..90577ef 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
@@ -17,37 +17,22 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Presubmit
-import android.support.test.launcherhelper.LauncherStrategyFactory
import android.view.Surface
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.Flicker
-import com.android.server.wm.flicker.FlickerTestRunner
-import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.focusChanges
-import com.android.server.wm.flicker.helpers.buildTestTag
-import com.android.server.wm.flicker.helpers.exitSplitScreen
-import com.android.server.wm.flicker.helpers.isInSplitScreen
-import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.appWindowBecomesVisible
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.layerBecomesVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.dsl.runWithFlicker
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -56,85 +41,59 @@
* Test open app to split screen.
* To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreenTest`
*/
-@Presubmit
+// TODO: Add back to pre-submit when stable.
+//@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppToLegacySplitScreenTest(
- testName: String,
- flickerSpec: Flicker
-) : FlickerTestRunner(testName, flickerSpec) {
+ rotationName: String,
+ rotation: Int
+) : SplitScreenTestBase(rotationName, rotation) {
+ @Test
+ fun OpenAppToLegacySplitScreenTest() {
+ val testTag = "OpenAppToLegacySplitScreenTest"
+
+ runWithFlicker(transitionSetup) {
+ withTestName { testTag }
+ repeat { SplitScreenHelper.TEST_REPETITIONS }
+ transitions {
+ splitScreenApp.launchViaIntent()
+ device.pressHome()
+ this.setRotation(rotation)
+ device.launchSplitScreen()
+ }
+ assertions {
+ windowManagerTrace {
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+ appWindowBecomesVisible(splitScreenApp.getPackage())
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(rotation, enabled = false)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(LAUNCHER_PACKAGE_NAME))
+ appPairsDividerBecomesVisible()
+ layerBecomesVisible(splitScreenApp.getPackage())
+ }
+
+ eventLog {
+ focusChanges(splitScreenApp.`package`,
+ "recents_animation_input_consumer", "NexusLauncherActivity",
+ bugId = 151179149)
+ }
+ }
+ }
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
- .launcherStrategy.supportedLauncherPackage
- val testApp = StandardAppHelper(instrumentation,
- "com.android.wm.shell.flicker.testapp", "SimpleApp")
-
- // b/161435597 causes the test not to work on 90 degrees
- return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
- .buildTest { configuration ->
- withTestName {
- buildTestTag("appToSplitScreen", testApp, configuration)
- }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- device.openQuickStepAndClearRecentAppsFromOverview()
- }
- eachRun {
- testApp.open()
- device.pressHome()
- this.setRotation(configuration.endRotation)
- }
- }
- teardown {
- eachRun {
- if (device.isInSplitScreen()) {
- device.exitSplitScreen()
- }
- }
- test {
- testApp.exit()
- }
- }
- transitions {
- device.launchSplitScreen()
- }
- assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- appWindowBecomesVisible(testApp.getPackage())
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.endRotation, enabled = false)
- navBarLayerRotatesAndScales(configuration.endRotation,
- bugId = 140855415)
- statusBarLayerRotatesScales(configuration.endRotation)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(launcherPackageName))
-
- dockedStackDividerBecomesVisible()
- layerBecomesVisible(testApp.getPackage())
- }
-
- eventLog {
- focusChanges(testApp.`package`,
- "recents_animation_input_consumer", "NexusLauncherActivity",
- bugId = 151179149)
- }
- }
- }
+ val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
index a536ec8..2b94c5f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
@@ -17,6 +17,15 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.NonRotationTestBase
import com.android.wm.shell.flicker.TEST_APP_NONRESIZEABLE_LABEL
import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL
@@ -37,6 +46,39 @@
protected val nonResizeableApp = SplitScreenHelper(instrumentation,
TEST_APP_NONRESIZEABLE_LABEL,
Components.NonResizeableActivity())
- protected val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
+
+ protected val LAUNCHER_PACKAGE_NAME = LauncherStrategyFactory.getInstance(instrumentation)
.launcherStrategy.supportedLauncherPackage
+ protected val LIVE_WALLPAPER_PACKAGE_NAME =
+ "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2"
+ protected val LETTER_BOX_NAME = "Letterbox"
+
+ protected val transitionSetup: FlickerBuilder
+ get() = FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ uiDevice.wakeUpAndGoToHomeScreen()
+ uiDevice.openQuickStepAndClearRecentAppsFromOverview()
+ }
+ }
+ teardown {
+ eachRun {
+ if (uiDevice.isInSplitScreen()) {
+ uiDevice.exitSplitScreen()
+ }
+ splitScreenApp.exit()
+ nonResizeableApp.exit()
+ }
+ }
+ assertions {
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ }
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c6cc83b..7a4bcb1 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1646,7 +1646,7 @@
if (startedActivityStack != null && startedActivityStack.isAttached()
&& !startedActivityStack.hasActivity()
&& !startedActivityStack.isActivityTypeHome()) {
- startedActivityStack.removeIfPossible();
+ startedActivityStack.removeIfPossible("handleStartResult");
startedActivityStack = null;
}
return startedActivityStack;
@@ -1834,7 +1834,7 @@
return top.getTask();
} else {
// Remove the stack if no activity in the stack.
- stack.removeIfPossible();
+ stack.removeIfPossible("computeTargetTask");
}
}
return null;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c3a7542..4494d99 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5490,7 +5490,7 @@
if (!hasNonEmptyHomeRootTask && getRootTaskCount() > 0) {
// Release this display if only empty home root task(s) are left. This display will be
// released along with the root task(s) removal.
- forAllRootTasks(Task::removeIfPossible);
+ forAllRootTasks(t -> {t.removeIfPossible("releaseSelfIfNeeded");});
} else if (getTopRootTask() == null) {
removeIfPossible();
mRootWindowContainer.mTaskSupervisor
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a88e453..a2a6985 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -916,21 +916,26 @@
mTaskSupervisor.mRecentTasks.remove(this);
}
- removeIfPossible();
+ removeIfPossible("cleanUpResourcesForDestroy");
}
@VisibleForTesting
@Override
void removeIfPossible() {
+ removeIfPossible("removeTaskIfPossible");
+ }
+
+ void removeIfPossible(String reason) {
final boolean isRootTask = isRootTask();
if (!isRootTask) {
mAtmService.getLockTaskController().clearLockedTask(this);
}
if (shouldDeferRemoval()) {
- if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
+ if (DEBUG_ROOT_TASK) Slog.i(TAG,
+ "removeTask:" + reason + " deferring removing taskId=" + mTaskId);
return;
}
- removeImmediately();
+ removeImmediately(reason);
if (isLeafTask()) {
mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
@@ -1774,8 +1779,8 @@
getRootTask().removeChild(this, reason);
}
EventLogTags.writeWmTaskRemoved(mTaskId,
- "removeChild: last r=" + r + " in t=" + this);
- removeIfPossible();
+ "removeChild:" + reason + " last r=" + r + " in t=" + this);
+ removeIfPossible(reason);
}
}
@@ -1818,7 +1823,7 @@
if (r.finishing) return;
// Task was restored from persistent storage.
r.takeFromHistory();
- removeChild(r);
+ removeChild(r, reason);
});
} else {
forAllActivities((r) -> {
@@ -3214,8 +3219,12 @@
@Override
void removeImmediately() {
- if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
- EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
+ removeImmediately("removeTask");
+ }
+
+ void removeImmediately(String reason) {
+ if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask:" + reason + " removing taskId=" + mTaskId);
+ EventLogTags.writeWmTaskRemoved(mTaskId, reason);
// If applicable let the TaskOrganizer know the Task is vanishing.
setTaskOrganizer(null);
@@ -4986,7 +4995,7 @@
mTaskAppearedSent = false;
setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
if (mCreatedByOrganizer) {
- removeImmediately();
+ removeImmediately("setTaskOrganizer");
}
}
@@ -6708,7 +6717,7 @@
/** Finish all activities in the stack without waiting. */
void finishAllActivitiesImmediately() {
if (!hasChild()) {
- removeIfPossible();
+ removeIfPossible("finishAllActivitiesImmediately");
return;
}
forAllActivities((r) -> {
@@ -8002,7 +8011,7 @@
// Task created by organizer are added as root.
final Task launchRootTask = mCreatedByOrganizer
- ? null : tda.updateLaunchRootTask(mWindowingMode);
+ ? null : tda.getLaunchRootTask(mWindowingMode, mActivityType);
if (launchRootTask != null) {
// Since this task will be put into a root task, its windowingMode will be
// inherited.
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 3f4150b..2ebdda6 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -28,7 +28,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -54,6 +53,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
@@ -117,8 +117,18 @@
private RootWindowContainer mRootWindowContainer;
- // When non-null, new tasks get put into this root task.
- Task mLaunchRootTask = null;
+ // Launch root tasks by activityType then by windowingMode.
+ static private class LaunchRootTaskDef {
+ Task task;
+ int[] windowingModes;
+ int[] activityTypes;
+
+ boolean contains(int windowingMode, int activityType) {
+ return ArrayUtils.contains(windowingModes, windowingMode)
+ && ArrayUtils.contains(activityTypes, activityType);
+ }
+ }
+ private final ArrayList<LaunchRootTaskDef> mLaunchRootTasks = new ArrayList<>();
/**
* A focusable stack that is purposely to be positioned at the top. Although the stack may not
@@ -1017,7 +1027,7 @@
} else if (candidateTask != null) {
final Task stack = candidateTask;
final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
- Task launchRootTask = updateLaunchRootTask(windowingMode);
+ final Task launchRootTask = getLaunchRootTask(windowingMode, activityType);
if (launchRootTask != null) {
if (stack.getParent() == null) {
@@ -1096,40 +1106,41 @@
.build();
}
- /** @return the root task to create the next task in. */
- Task updateLaunchRootTask(int windowingMode) {
- if (!isSplitScreenWindowingMode(windowingMode)) {
- // Only split-screen windowing modes can do this currently...
- return null;
+ // TODO: Also clear when task is removed from system?
+ void setLaunchRootTask(Task rootTask, int[] windowingModes, int[] activityTypes) {
+ if (!rootTask.mCreatedByOrganizer) {
+ throw new IllegalArgumentException(
+ "Can't set not mCreatedByOrganizer as launch root tr=" + rootTask);
}
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowContainer child = mChildren.get(i);
- if (child.asTaskDisplayArea() != null) {
- final Task t = child.asTaskDisplayArea().updateLaunchRootTask(windowingMode);
- if (t != null) {
- return t;
- }
- continue;
- }
- final Task t = mChildren.get(i).asTask();
- if (t == null || !t.mCreatedByOrganizer
- || t.getRequestedOverrideWindowingMode() != windowingMode) {
- continue;
- }
- // If not already set, pick a launch root which is not the one we are launching into.
- if (mLaunchRootTask == null) {
- for (int j = 0, n = mChildren.size(); j < n; ++j) {
- final Task tt = mChildren.get(j).asTask();
- if (tt != null && tt.mCreatedByOrganizer && tt != t) {
- mLaunchRootTask = tt;
- break;
- }
- }
- }
- return t;
+ LaunchRootTaskDef def = null;
+ for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
+ if (mLaunchRootTasks.get(i).task.mTaskId != rootTask.mTaskId) continue;
+ def = mLaunchRootTasks.get(i);
}
- return mLaunchRootTask;
+
+ if (def != null) {
+ // Remove so we add to the end of the list.
+ mLaunchRootTasks.remove(def);
+ } else {
+ def = new LaunchRootTaskDef();
+ def.task = rootTask;
+ }
+
+ def.activityTypes = activityTypes;
+ def.windowingModes = windowingModes;
+ if (!ArrayUtils.isEmpty(windowingModes) || !ArrayUtils.isEmpty(activityTypes)) {
+ mLaunchRootTasks.add(def);
+ }
+ }
+
+ Task getLaunchRootTask(int windowingMode, int activityType) {
+ for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
+ if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) {
+ return mLaunchRootTasks.get(i).task;
+ }
+ }
+ return null;
}
/**
@@ -1321,7 +1332,6 @@
void onSplitScreenModeDismissed(Task toTop) {
mAtmService.deferWindowLayout();
try {
- mLaunchRootTask = null;
moveSplitScreenTasksToFullScreen();
} finally {
final Task topFullscreenStack = toTop != null
@@ -1919,7 +1929,20 @@
if (mLastFocusedRootTask != null) {
pw.println(doublePrefix + "mLastFocusedRootTask=" + mLastFocusedRootTask);
}
+
final String triplePrefix = doublePrefix + " ";
+
+ if (mLaunchRootTasks.size() > 0) {
+ pw.println(doublePrefix + "mLaunchRootTasks:");
+ for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
+ final LaunchRootTaskDef def = mLaunchRootTasks.get(i);
+ pw.println(triplePrefix
+ + def.activityTypes + " "
+ + def.windowingModes + " "
+ + " task=" + def.task);
+ }
+ }
+
pw.println(doublePrefix + "Application tokens in top down Z order:");
for (int index = getChildCount() - 1; index >= 0; --index) {
final WindowContainer child = getChildAt(index);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 089071f..9a83ac7 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -510,7 +510,7 @@
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d",
task.getDisplayId(), task.getWindowingMode());
- task.removeImmediately();
+ task.removeImmediately("deleteRootTask");
return true;
}
} finally {
@@ -601,45 +601,6 @@
}
@Override
- public void setLaunchRoot(int displayId, @Nullable WindowContainerToken token) {
- enforceTaskPermission("setLaunchRoot()");
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- TaskDisplayArea defaultTaskDisplayArea = mService.mRootWindowContainer
- .getDisplayContent(displayId).getDefaultTaskDisplayArea();
- if (defaultTaskDisplayArea == null) {
- return;
- }
- WindowContainer wc = null;
- if (token != null) {
- wc = WindowContainer.fromBinder(token.asBinder());
- if (wc == null) {
- throw new IllegalArgumentException("Can't resolve window from token");
- }
- }
- final Task task = wc == null ? null : wc.asTask();
- if (task == null) {
- defaultTaskDisplayArea.mLaunchRootTask = null;
- return;
- }
- if (!task.mCreatedByOrganizer) {
- throw new IllegalArgumentException("Attempt to set task not created by "
- + "organizer as launch root task=" + task);
- }
- if (task.getDisplayArea() == null
- || task.getDisplayArea().getDisplayId() != displayId) {
- throw new RuntimeException("Can't set launch root for display " + displayId
- + " to task on display " + task.getDisplayContent().getDisplayId());
- }
- task.getDisplayArea().mLaunchRootTask = task;
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
public List<RunningTaskInfo> getChildTasks(WindowContainerToken parent,
@Nullable int[] activityTypes) {
enforceTaskPermission("getChildTasks()");
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index b0e67ce..be1f7e1 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -17,6 +17,10 @@
package com.android.server.wm;
import static android.Manifest.permission.READ_FRAME_BUFFER;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
@@ -49,13 +53,16 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
/**
* Server side implementation for the interface for organizing windows
@@ -256,34 +263,46 @@
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
for (int i = 0, n = hops.size(); i < n; ++i) {
final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
- final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- if (wc == null || !wc.isAttached()) {
- Slog.e(TAG, "Attempt to operate on detached container: " + wc);
- continue;
- }
- if (syncId >= 0) {
- addToSyncSet(syncId, wc);
- }
- if (transition != null) {
- transition.collect(wc);
- if (hop.isReparent()) {
- if (wc.getParent() != null) {
- // Collect the current parent. It's visibility may change as a result
- // of this reparenting.
- transition.collect(wc.getParent());
+ switch (hop.getType()) {
+ case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT:
+ final Task task = WindowContainer.fromBinder(hop.getContainer()).asTask();
+ task.getDisplayArea().setLaunchRootTask(task,
+ hop.getWindowingModes(), hop.getActivityTypes());
+ break;
+ case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
+ effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
+ break;
+ case HIERARCHY_OP_TYPE_REORDER:
+ case HIERARCHY_OP_TYPE_REPARENT:
+ final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on detached container: " + wc);
+ continue;
}
- if (hop.getNewParent() != null) {
- final WindowContainer parentWc =
- WindowContainer.fromBinder(hop.getNewParent());
- if (parentWc == null) {
- Slog.e(TAG, "Can't resolve parent window from token");
- continue;
+ if (syncId >= 0) {
+ addToSyncSet(syncId, wc);
+ }
+ if (transition != null) {
+ transition.collect(wc);
+ if (hop.isReparent()) {
+ if (wc.getParent() != null) {
+ // Collect the current parent. It's visibility may change as
+ // a result of this reparenting.
+ transition.collect(wc.getParent());
+ }
+ if (hop.getNewParent() != null) {
+ final WindowContainer parentWc =
+ WindowContainer.fromBinder(hop.getNewParent());
+ if (parentWc == null) {
+ Slog.e(TAG, "Can't resolve parent window from token");
+ continue;
+ }
+ transition.collect(parentWc);
+ }
}
- transition.collect(parentWc);
}
- }
+ effects |= sanitizeAndApplyHierarchyOp(wc, hop);
}
- effects |= sanitizeAndApplyHierarchyOp(wc, hop);
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
// this after hierarchy ops so we have the final organized state.
@@ -492,6 +511,85 @@
return TRANSACT_EFFECTS_LIFECYCLE;
}
+ private int reparentChildrenTasksHierarchyOp(WindowContainerTransaction.HierarchyOp hop,
+ @Nullable Transition transition, int syncId) {
+ WindowContainer currentParent = hop.getContainer() != null
+ ? WindowContainer.fromBinder(hop.getContainer()) : null;
+ WindowContainer newParent = hop.getNewParent() != null
+ ? WindowContainer.fromBinder(hop.getNewParent()) : null;
+ if (currentParent == null && newParent == null) {
+ throw new IllegalArgumentException("reparentChildrenTasksHierarchyOp: " + hop);
+ } else if (currentParent == null) {
+ currentParent = newParent.asTask().getDisplayContent().getDefaultTaskDisplayArea();
+ } else if (newParent == null) {
+ newParent = currentParent.asTask().getDisplayContent().getDefaultTaskDisplayArea();
+ }
+
+ if (currentParent == newParent) {
+ Slog.e(TAG, "reparentChildrenTasksHierarchyOp parent not changing: " + hop);
+ return 0;
+ }
+ if (!currentParent.isAttached()) {
+ Slog.e(TAG, "reparentChildrenTasksHierarchyOp currentParent detached="
+ + currentParent + " hop=" + hop);
+ return 0;
+ }
+ if (!newParent.isAttached()) {
+ Slog.e(TAG, "reparentChildrenTasksHierarchyOp newParent detached="
+ + newParent + " hop=" + hop);
+ return 0;
+ }
+
+ final boolean newParentInMultiWindow = newParent.inMultiWindowMode();
+ final WindowContainer finalCurrentParent = currentParent;
+ Slog.i(TAG, "reparentChildrenTasksHierarchyOp"
+ + " currentParent=" + currentParent + " newParent=" + newParent + " hop=" + hop);
+
+ // We want to collect the tasks first before re-parenting to avoid array shifting on us.
+ final ArrayList<Task> tasksToReparent = new ArrayList<>();
+
+ currentParent.forAllTasks((Consumer<Task>) (task) -> {
+ Slog.i(TAG, " Processing task=" + task);
+ if (task.mCreatedByOrganizer
+ || task.getParent() != finalCurrentParent) {
+ // We only care about non-organized task that are direct children of the thing we
+ // are reparenting from.
+ return;
+ }
+
+ if (newParentInMultiWindow && !task.isResizeable()) {
+ Slog.e(TAG, "reparentChildrenTasksHierarchyOp non-resizeable task=" + task);
+ }
+
+ if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType())) return;
+ if (!ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) return;
+
+ tasksToReparent.add(task);
+ }, !hop.getToTop());
+
+ final int count = tasksToReparent.size();
+ for (int i = 0; i < count; ++i) {
+ final Task task = tasksToReparent.get(i);
+ if (syncId >= 0) {
+ addToSyncSet(syncId, task);
+ }
+ if (transition != null) transition.collect(task);
+
+ if (newParent instanceof TaskDisplayArea) {
+ // For now, reparenting to display area is different from other reparents...
+ task.reparent((TaskDisplayArea) newParent, hop.getToTop());
+ } else {
+ task.reparent((Task) newParent,
+ hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
+ false /*moveParents*/, "processChildrenTaskReparentHierarchyOp");
+ }
+ }
+
+ if (transition != null) transition.collect(newParent);
+
+ return TRANSACT_EFFECTS_LIFECYCLE;
+ }
+
private void sanitizeWindowContainer(WindowContainer wc) {
if (!(wc instanceof Task) && !(wc instanceof DisplayArea)) {
throw new RuntimeException("Invalid token in task or displayArea transaction");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 21aa6bf..fc96b69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -156,8 +156,10 @@
organizer.setMoveToSecondaryOnEnter(false);
// Create primary splitscreen stack.
- final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask(
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task primarySplitScreen = new TaskBuilder(mAtm.mTaskSupervisor)
+ .setParentTask(organizer.mPrimary)
+ .setOnTop(true)
+ .build();
// Assert windowing mode.
assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode());
@@ -205,14 +207,15 @@
@Test
public void testSplitScreenMoveToBack() {
TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
- // Set up split-screen with primary on top and secondary containing the home task below
- // another stack.
+ // Explicitly reparent task to primary split root to enter split mode, in which implies
+ // primary on top and secondary containing the home task below another stack.
final Task primaryTask = mDefaultTaskDisplayArea.createRootTask(
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task secondaryTask = mDefaultTaskDisplayArea.createRootTask(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task homeRoot = mDefaultTaskDisplayArea.getRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
- final Task secondaryTask = mDefaultTaskDisplayArea.createRootTask(
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ primaryTask.reparent(organizer.mPrimary, POSITION_TOP);
mDefaultTaskDisplayArea.positionChildAt(POSITION_TOP, organizer.mPrimary,
false /* includingParents */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index fee848b..4bfc837 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -485,8 +485,10 @@
final ActivityRecord splitSecondActivity =
new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord splitPrimaryActivity = new TaskBuilder(mSupervisor)
- .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).setCreateActivity(true)
- .build().getTopMostActivity();
+ .setParentTask(splitOrg.mPrimary)
+ .setCreateActivity(true)
+ .build()
+ .getTopMostActivity();
splitPrimaryActivity.mVisibleRequested = splitSecondActivity.mVisibleRequested = true;
assertEquals(splitOrg.mPrimary, splitPrimaryActivity.getRootTask());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 31e2dce..8b93372 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -17,6 +17,8 @@
package com.android.server.wm;
import static android.app.AppOpsManager.OP_NONE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -1107,6 +1109,17 @@
// moves everything to secondary. Most tests expect this since sysui usually does it.
boolean mMoveToSecondaryOnEnter = true;
int mDisplayId;
+ private static final int[] CONTROLLED_ACTIVITY_TYPES = {
+ ACTIVITY_TYPE_STANDARD,
+ ACTIVITY_TYPE_HOME,
+ ACTIVITY_TYPE_RECENTS,
+ ACTIVITY_TYPE_UNDEFINED
+ };
+ private static final int[] CONTROLLED_WINDOWING_MODES = {
+ WINDOWING_MODE_FULLSCREEN,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ WINDOWING_MODE_UNDEFINED
+ };
TestSplitOrganizer(ActivityTaskManagerService service, DisplayContent display) {
mService = service;
mDisplayId = display.mDisplayId;
@@ -1151,9 +1164,9 @@
if (!mMoveToSecondaryOnEnter) {
return;
}
- mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
- mSecondary.mRemoteToken.toWindowContainerToken());
DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
+ dc.getDefaultTaskDisplayArea().setLaunchRootTask(
+ mSecondary, CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES);
dc.forAllRootTasks(rootTask -> {
if (!WindowConfiguration.isSplitScreenWindowingMode(rootTask.getWindowingMode())) {
rootTask.reparent(mSecondary, POSITION_BOTTOM);