summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2020-04-13 20:59:05 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-04-13 20:59:05 +0000
commitbc65eb2fb615f99b9e4fb80b9cd82b5c84f1555a (patch)
treeb6214132e7ca97f91ad28da479abe9d332d28b18
parentf9551ba4e1a07deba4e172844782e0a3a3acbfe7 (diff)
parent36b06cdbc4a81a1189153829ef55851aed3657c0 (diff)
Merge "Fix moveToBack behavior in organizer-created root tasks" into rvc-dev
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java48
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java60
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java63
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java78
4 files changed, 167 insertions, 82 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index bcad7586b918..3454e13d81de 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1049,6 +1049,9 @@ class ActivityStack extends Task {
}
/**
+ * This moves 'task' to the back of this task and also recursively moves this task to the back
+ * of its parents (if applicable).
+ *
* @param reason The reason for moving the stack to the back.
* @param task If non-null, the task will be moved to the bottom of the stack.
**/
@@ -1056,18 +1059,41 @@ class ActivityStack extends Task {
if (!isAttached()) {
return;
}
-
- getDisplayArea().positionStackAtBottom(this, reason);
- if (task != null && task != this) {
- positionChildAtBottom(task);
+ final TaskDisplayArea displayArea = getDisplayArea();
+ if (!mCreatedByOrganizer) {
+ // If this is just a normal task, so move to back of parent and then move 'task' to
+ // back of this.
+ final WindowContainer parent = getParent();
+ final Task parentTask = parent != null ? parent.asTask() : null;
+ if (parentTask != null) {
+ ((ActivityStack) parentTask).moveToBack(reason, this);
+ } else {
+ displayArea.positionStackAtBottom(this, reason);
+ }
+ if (task != null && task != this) {
+ positionChildAtBottom(task);
+ }
+ return;
}
-
- /**
- * The intent behind moving a primary split screen stack to the back is usually to hide
- * behind the home stack. Exit split screen in this case.
- */
- if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ if (task == null || task == this) {
+ return;
+ }
+ // This is a created-by-organizer task. In this case, let the organizer deal with this
+ // task's ordering. However, we still need to move 'task' to back. The intention is that
+ // this ends up behind the home-task so that it is made invisible; so, if the home task
+ // is not a child of this, reparent 'task' to the back of the home task's actual parent.
+ final ActivityStack home = displayArea.getOrCreateRootHomeTask();
+ final WindowContainer homeParent = home.getParent();
+ final Task homeParentTask = homeParent != null ? homeParent.asTask() : null;
+ if (homeParentTask == null) {
+ ((ActivityStack) task).reparent(displayArea, false /* onTop */);
+ } else if (homeParentTask == this) {
+ // Apparently reparent early-outs if same stack, so we have to explicitly reorder.
+ positionChildAtBottom(task);
+ } else {
+ task.reparent((ActivityStack) homeParentTask, false /* toTop */,
+ REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */, false /* deferResume */,
+ "moveToBack");
}
}
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 3d15401cdfb9..3bed05f383a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -46,6 +46,7 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_F
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
import static com.android.server.wm.TaskDisplayArea.getStackAbove;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.google.common.truth.Truth.assertThat;
@@ -140,9 +141,12 @@ public class ActivityStackTests extends ActivityTestsBase {
}
@Test
- public void testPrimarySplitScreenRestoresWhenMovedToBack() {
- // Create primary splitscreen stack. This will create secondary stacks and places the
- // existing fullscreen stack on the bottom.
+ public void testPrimarySplitScreenMoveToBack() {
+ TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
+ // We're testing an edge case here where we have primary + fullscreen rather than secondary.
+ organizer.setMoveToSecondaryOnEnter(false);
+
+ // Create primary splitscreen stack.
final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -165,12 +169,14 @@ public class ActivityStackTests extends ActivityTestsBase {
}
@Test
- public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() {
+ public void testMoveToPrimarySplitScreenThenMoveToBack() {
+ TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
// This time, start with a fullscreen activitystack
final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- primarySplitScreen.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ primarySplitScreen.reparent((ActivityStack) organizer.mPrimary, POSITION_TOP,
+ false /*moveParents*/, "test");
// Assert windowing mode.
assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode());
@@ -180,14 +186,52 @@ public class ActivityStackTests extends ActivityTestsBase {
null /* task */);
// Assert that stack is at the bottom.
- assertEquals(0, mDefaultTaskDisplayArea.getIndexOf(primarySplitScreen));
+ assertEquals(primarySplitScreen, organizer.mSecondary.getChildAt(0));
// Ensure that the override mode is restored to what it was (fullscreen)
- assertEquals(WINDOWING_MODE_FULLSCREEN,
+ assertEquals(WINDOWING_MODE_UNDEFINED,
primarySplitScreen.getRequestedOverrideWindowingMode());
}
@Test
+ public void testSplitScreenMoveToBack() {
+ TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
+ // Set up split-screen with primary on top and secondary containing the home task below
+ // another stack.
+ final ActivityStack primaryTask = mDefaultTaskDisplayArea.createStack(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack homeRoot = mDefaultTaskDisplayArea.getStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ final ActivityStack secondaryTask = mDefaultTaskDisplayArea.createStack(
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ mDefaultTaskDisplayArea.positionStackAtTop((ActivityStack) organizer.mPrimary,
+ false /* includingParents */);
+
+ // Move primary to back.
+ primaryTask.moveToBack("test", null /* task */);
+
+ // Assert that the primaryTask is now below home in its parent but primary is left alone.
+ assertEquals(0, organizer.mPrimary.getChildCount());
+ assertEquals(primaryTask, organizer.mSecondary.getChildAt(0));
+ assertEquals(1, organizer.mPrimary.compareTo(organizer.mSecondary));
+ assertEquals(1, homeRoot.compareTo(primaryTask));
+ assertEquals(homeRoot.getParent(), primaryTask.getParent());
+
+ // Make sure windowing modes are correct
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, organizer.mPrimary.getWindowingMode());
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, primaryTask.getWindowingMode());
+
+ // Move secondary to back via parent (should be equivalent)
+ ((ActivityStack) organizer.mSecondary).moveToBack("test", secondaryTask);
+
+ // Assert that it is now in back but still in secondary split
+ assertEquals(1, homeRoot.compareTo(primaryTask));
+ assertEquals(secondaryTask, organizer.mSecondary.getChildAt(0));
+ assertEquals(1, primaryTask.compareTo(secondaryTask));
+ assertEquals(homeRoot.getParent(), secondaryTask.getParent());
+ }
+
+ @Test
public void testStackInheritsDisplayWindowingMode() {
final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
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 bdba4b6c8ac8..97734ff32de2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -30,7 +30,6 @@ import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_SWITCHES_CANCELED;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
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_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -64,10 +63,8 @@ import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
-import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -82,8 +79,6 @@ import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession;
import android.view.Gravity;
-import android.window.ITaskOrganizer;
-import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
@@ -1004,62 +999,4 @@ public class ActivityStarterTests extends ActivityTestsBase {
verify(recentTasks, times(1)).add(any());
}
-
- static class TestSplitOrganizer extends ITaskOrganizer.Stub {
- final ActivityTaskManagerService mService;
- Task mPrimary;
- Task mSecondary;
- boolean mInSplit = false;
- int mDisplayId;
- TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
- mService = service;
- mDisplayId = displayId;
- mService.mTaskOrganizerController.registerTaskOrganizer(this,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- mService.mTaskOrganizerController.registerTaskOrganizer(this,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
- displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
- mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
- WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask(
- displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
- mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
- }
- @Override
- public void onTaskAppeared(ActivityManager.RunningTaskInfo info) {
- }
- @Override
- public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
- }
- @Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
- if (mInSplit) {
- return;
- }
- if (info.topActivityType != ACTIVITY_TYPE_UNDEFINED) {
- if (info.configuration.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- mInSplit = true;
- mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
- mSecondary.mRemoteToken.toWindowContainerToken());
- // move everything to secondary because test expects this but usually sysui
- // does it.
- DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
- for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- if (!WindowConfiguration.isSplitScreenWindowingMode(
- stack.getWindowingMode())) {
- stack.reparent(mSecondary, POSITION_BOTTOM);
- }
- }
- }
- }
- }
- }
- @Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
- }
- };
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 67d4769522b0..6ae8313e39dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -17,7 +17,10 @@
package com.android.server.wm;
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_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -30,9 +33,12 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -43,6 +49,8 @@ import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
+import android.window.ITaskOrganizer;
+import android.window.WindowContainerToken;
import com.android.server.AttributeCache;
@@ -505,4 +513,74 @@ class ActivityTestsBase extends SystemServiceTestsBase {
}
}
+
+ static class TestSplitOrganizer extends ITaskOrganizer.Stub {
+ final ActivityTaskManagerService mService;
+ Task mPrimary;
+ Task mSecondary;
+ boolean mInSplit = false;
+ // moves everything to secondary. Most tests expect this since sysui usually does it.
+ boolean mMoveToSecondaryOnEnter = true;
+ int mDisplayId;
+ TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
+ mService = service;
+ mDisplayId = displayId;
+ mService.mTaskOrganizerController.registerTaskOrganizer(this,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ mService.mTaskOrganizerController.registerTaskOrganizer(this,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
+ displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
+ mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
+ WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask(
+ displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
+ mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
+ }
+ TestSplitOrganizer(ActivityTaskManagerService service) {
+ this(service,
+ service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId);
+ }
+ public void setMoveToSecondaryOnEnter(boolean move) {
+ mMoveToSecondaryOnEnter = move;
+ }
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
+ public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ if (mInSplit) {
+ return;
+ }
+ if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) {
+ // Not populated
+ return;
+ }
+ if (info.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ return;
+ }
+ mInSplit = true;
+ if (!mMoveToSecondaryOnEnter) {
+ return;
+ }
+ mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
+ mSecondary.mRemoteToken.toWindowContainerToken());
+ DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
+ for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
+ final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
+ stack.reparent(mSecondary, POSITION_BOTTOM);
+ }
+ }
+ }
+ }
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ }
+ };
}