Merge "Move adjacent tasks forward together to ensure occluding state" into sc-v2-dev am: 642ead3a05

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16220664

Change-Id: I610b2e7d03bee916ff309afb98d84f3d4a992678
This commit is contained in:
TreeHugger Robot
2021-12-02 08:33:51 +00:00
committed by Automerger Merge Worker
12 changed files with 101 additions and 34 deletions

View File

@@ -3295,7 +3295,7 @@ package android.window {
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 setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken);
method @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken, boolean);
method @NonNull public android.window.WindowContainerTransaction setAdjacentTaskFragments(@NonNull android.os.IBinder, @Nullable android.os.IBinder, @Nullable android.window.WindowContainerTransaction.TaskFragmentAdjacentParams);
method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
method @NonNull public android.window.WindowContainerTransaction setBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);

View File

@@ -368,10 +368,12 @@ public final class WindowContainerTransaction implements Parcelable {
*/
@NonNull
public WindowContainerTransaction setAdjacentRoots(
@NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) {
@NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2,
boolean moveTogether) {
mHierarchyOps.add(HierarchyOp.createForAdjacentRoots(
root1.asBinder(),
root2.asBinder()));
root2.asBinder(),
moveTogether));
return this;
}
@@ -975,6 +977,9 @@ public final class WindowContainerTransaction implements Parcelable {
private boolean mReparentTopOnly;
// TODO(b/207185041): Remove this once having a single-top root for split screen.
private boolean mMoveAdjacentTogether;
@Nullable
private int[] mWindowingModes;
@@ -1033,10 +1038,13 @@ public final class WindowContainerTransaction implements Parcelable {
.build();
}
public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2) {
/** Create a hierarchy op for setting adjacent root tasks. */
public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2,
boolean moveTogether) {
return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS)
.setContainer(root1)
.setReparentContainer(root2)
.setMoveAdjacentTogether(moveTogether)
.build();
}
@@ -1070,6 +1078,7 @@ public final class WindowContainerTransaction implements Parcelable {
mReparent = copy.mReparent;
mToTop = copy.mToTop;
mReparentTopOnly = copy.mReparentTopOnly;
mMoveAdjacentTogether = copy.mMoveAdjacentTogether;
mWindowingModes = copy.mWindowingModes;
mActivityTypes = copy.mActivityTypes;
mLaunchOptions = copy.mLaunchOptions;
@@ -1084,6 +1093,7 @@ public final class WindowContainerTransaction implements Parcelable {
mReparent = in.readStrongBinder();
mToTop = in.readBoolean();
mReparentTopOnly = in.readBoolean();
mMoveAdjacentTogether = in.readBoolean();
mWindowingModes = in.createIntArray();
mActivityTypes = in.createIntArray();
mLaunchOptions = in.readBundle();
@@ -1128,6 +1138,10 @@ public final class WindowContainerTransaction implements Parcelable {
return mReparentTopOnly;
}
public boolean getMoveAdjacentTogether() {
return mMoveAdjacentTogether;
}
public int[] getWindowingModes() {
return mWindowingModes;
}
@@ -1175,7 +1189,8 @@ public final class WindowContainerTransaction implements Parcelable {
return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}";
case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
return "{SetAdjacentRoot: container=" + mContainer
+ " adjacentRoot=" + mReparent + "}";
+ " adjacentRoot=" + mReparent + " mMoveAdjacentTogether="
+ mMoveAdjacentTogether + "}";
case HIERARCHY_OP_TYPE_LAUNCH_TASK:
return "{LaunchTask: " + mLaunchOptions + "}";
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
@@ -1212,6 +1227,7 @@ public final class WindowContainerTransaction implements Parcelable {
dest.writeStrongBinder(mReparent);
dest.writeBoolean(mToTop);
dest.writeBoolean(mReparentTopOnly);
dest.writeBoolean(mMoveAdjacentTogether);
dest.writeIntArray(mWindowingModes);
dest.writeIntArray(mActivityTypes);
dest.writeBundle(mLaunchOptions);
@@ -1251,6 +1267,8 @@ public final class WindowContainerTransaction implements Parcelable {
private boolean mReparentTopOnly;
private boolean mMoveAdjacentTogether;
@Nullable
private int[] mWindowingModes;
@@ -1293,6 +1311,11 @@ public final class WindowContainerTransaction implements Parcelable {
return this;
}
Builder setMoveAdjacentTogether(boolean moveAdjacentTogether) {
mMoveAdjacentTogether = moveAdjacentTogether;
return this;
}
Builder setWindowingModes(@Nullable int[] windowingModes) {
mWindowingModes = windowingModes;
return this;
@@ -1336,6 +1359,7 @@ public final class WindowContainerTransaction implements Parcelable {
: null;
hierarchyOp.mToTop = mToTop;
hierarchyOp.mReparentTopOnly = mReparentTopOnly;
hierarchyOp.mMoveAdjacentTogether = mMoveAdjacentTogether;
hierarchyOp.mLaunchOptions = mLaunchOptions;
hierarchyOp.mActivityIntent = mActivityIntent;
hierarchyOp.mPendingIntent = mPendingIntent;

View File

@@ -793,7 +793,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mMainStageListener.mHasRootTask && mSideStageListener.mHasRootTask) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
// Make the stages adjacent to each other so they occlude what's behind them.
wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
true /* moveTogether */);
wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
mTaskOrganizer.applyTransaction(wct);
}

View File

@@ -634,7 +634,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mUseLegacySplit = mContext.getResources().getBoolean(R.bool.config_useLegacySplit);
final WindowContainerTransaction wct = new WindowContainerTransaction();
// Make the stages adjacent to each other so they occlude what's behind them.
wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token,
true /* moveTogether */);
// Only sets side stage as launch-adjacent-flag-root when the device is not using legacy
// split to prevent new split behavior confusing users.

View File

@@ -4650,23 +4650,14 @@ class Task extends TaskFragment {
moveToFront(reason, null);
}
/**
* @param reason The reason for moving the root task to the front.
* @param task If non-null, the task will be moved to the top of the root task.
*/
void moveToFront(String reason, Task task) {
if (!isAttached()) {
return;
}
final TaskDisplayArea taskDisplayArea = getDisplayArea();
if (inSplitScreenSecondaryWindowingMode()) {
// If the root task is in split-screen secondary mode, we need to make sure we move the
// primary split-screen root task forward in the case it is currently behind a
// fullscreen root task so both halves of the split-screen appear on-top and the
// fullscreen root task isn't cutting between them.
// TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.
final TaskDisplayArea taskDisplayArea = getDisplayArea();
final Task topFullScreenRootTask =
taskDisplayArea.getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
if (topFullScreenRootTask != null) {
@@ -4674,10 +4665,30 @@ class Task extends TaskFragment {
taskDisplayArea.getRootSplitScreenPrimaryTask();
if (primarySplitScreenRootTask != null
&& topFullScreenRootTask.compareTo(primarySplitScreenRootTask) > 0) {
primarySplitScreenRootTask.moveToFront(reason + " splitScreenToTop");
primarySplitScreenRootTask.moveToFrontInner(reason + " splitScreenToTop",
null /* task */);
}
}
} else if (mMoveAdjacentTogether && getAdjacentTaskFragment() != null) {
final Task adjacentTask = getAdjacentTaskFragment().asTask();
if (adjacentTask != null) {
adjacentTask.moveToFrontInner(reason + " adjacentTaskToTop", null /* task */);
}
}
moveToFrontInner(reason, task);
}
/**
* @param reason The reason for moving the root task to the front.
* @param task If non-null, the task will be moved to the top of the root task.
*/
@VisibleForTesting
void moveToFrontInner(String reason, Task task) {
if (!isAttached()) {
return;
}
final TaskDisplayArea taskDisplayArea = getDisplayArea();
if (!isActivityTypeHome() && returnsToHomeRootTask()) {
// Make sure the root home task is behind this root task since that is where we

View File

@@ -168,6 +168,14 @@ class TaskFragment extends WindowContainer<WindowContainer> {
@Nullable
private TaskFragment mAdjacentTaskFragment;
/**
* Whether to move adjacent task fragment together when re-positioning.
*
* @see #mAdjacentTaskFragment
*/
// TODO(b/207185041): Remove this once having a single-top root for split screen.
boolean mMoveAdjacentTogether;
/**
* Prevents duplicate calls to onTaskAppeared.
*/
@@ -313,14 +321,15 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return service.mWindowOrganizerController.getTaskFragment(token);
}
void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment, boolean moveTogether) {
if (mAdjacentTaskFragment == taskFragment) {
return;
}
resetAdjacentTaskFragment();
if (taskFragment != null) {
mAdjacentTaskFragment = taskFragment;
taskFragment.setAdjacentTaskFragment(this);
mMoveAdjacentTogether = moveTogether;
taskFragment.setAdjacentTaskFragment(this, moveTogether);
}
}
@@ -329,9 +338,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
mAdjacentTaskFragment.mAdjacentTaskFragment = null;
mAdjacentTaskFragment.mDelayLastActivityRemoval = false;
mAdjacentTaskFragment.mMoveAdjacentTogether = false;
}
mAdjacentTaskFragment = null;
mDelayLastActivityRemoval = false;
mMoveAdjacentTogether = false;
}
void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,

View File

@@ -665,7 +665,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
tf1.setAdjacentTaskFragment(tf2);
tf1.setAdjacentTaskFragment(tf2, false /* moveAdjacentTogether */);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
final Bundle bundle = hop.getLaunchOptions();
@@ -978,7 +978,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by"
+ " organizer root1=" + root1 + " root2=" + root2);
}
root1.setAdjacentTaskFragment(root2);
root1.setAdjacentTaskFragment(root2, hop.getMoveAdjacentTogether());
return TRANSACT_EFFECTS_LIFECYCLE;
}

View File

@@ -84,7 +84,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
adjacentRootTask.mCreatedByOrganizer = true;
final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
adjacentRootTask.setAdjacentTaskFragment(rootTask);
adjacentRootTask.setAdjacentTaskFragment(rootTask, false /* moveTogether */);
taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask);
Task actualRootTask = taskDisplayArea.getLaunchRootTask(
@@ -110,7 +110,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
final Task adjacentRootTask = createTask(
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
adjacentRootTask.mCreatedByOrganizer = true;
adjacentRootTask.setAdjacentTaskFragment(rootTask);
adjacentRootTask.setAdjacentTaskFragment(rootTask, false /* moveTogether */);
taskDisplayArea.setLaunchRootTask(rootTask,
new int[]{WINDOWING_MODE_MULTI_WINDOW}, new int[]{ACTIVITY_TYPE_STANDARD});
@@ -131,7 +131,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
adjacentRootTask.mCreatedByOrganizer = true;
final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
adjacentRootTask.setAdjacentTaskFragment(rootTask);
adjacentRootTask.setAdjacentTaskFragment(rootTask, false /* moveTogether */);
taskDisplayArea.setLaunchAdjacentFlagRootTask(adjacentRootTask);
final Task actualRootTask = taskDisplayArea.getLaunchRootTask(

View File

@@ -330,7 +330,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
// Throw exception if the transaction is trying to change a window that is not organized by
// the organizer.
mTransaction.setAdjacentRoots(mFragmentWindowToken, token2);
mTransaction.setAdjacentRoots(mFragmentWindowToken, token2, false /* moveTogether */);
assertThrows(SecurityException.class, () -> {
try {

View File

@@ -59,6 +59,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.clearInvocations;
@@ -1365,6 +1366,25 @@ public class TaskTests extends WindowTestsBase {
assertNotNull(activity.getTask().getDimmer());
}
@Test
public void testMoveToFront_moveAdjacentTask() {
final Task task1 =
createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
final Task task2 =
createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
spyOn(task2);
task1.setAdjacentTaskFragment(task2, false /* moveTogether */);
task1.moveToFront("" /* reason */);
verify(task2, never()).moveToFrontInner(anyString(), isNull());
// Reset adjacent tasks to move together.
task1.setAdjacentTaskFragment(null, false /* moveTogether */);
task1.setAdjacentTaskFragment(task2, true /* moveTogether */);
task1.moveToFront("" /* reason */);
verify(task2).moveToFrontInner(anyString(), isNull());
}
private Task getTestTask() {
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
return task.getBottomMostTask();

View File

@@ -554,7 +554,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
final RunningTaskInfo info2 = task2.getTaskInfo();
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setAdjacentRoots(info1.token, info2.token);
wct.setAdjacentRoots(info1.token, info2.token, false /* moveTogether */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertEquals(task1.getAdjacentTaskFragment(), task2);
assertEquals(task2.getAdjacentTaskFragment(), task1);
@@ -564,8 +564,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, task1);
task1.setAdjacentTaskFragment(null);
task2.setAdjacentTaskFragment(null);
task1.setAdjacentTaskFragment(null, false /* moveTogether */);
task2.setAdjacentTaskFragment(null, false /* moveTogether */);
wct = new WindowContainerTransaction();
wct.clearLaunchAdjacentFlagRoot(info1.token);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);

View File

@@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -490,8 +489,8 @@ public class ZOrderingTests extends WindowTestsBase {
createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
final WindowState splitWindow2 =
createAppWindow(splitScreenTask2, ACTIVITY_TYPE_STANDARD, "splitWindow2");
splitScreenTask1.setAdjacentTaskFragment(splitScreenTask2);
splitScreenTask2.setAdjacentTaskFragment(splitScreenTask1);
splitScreenTask1.setAdjacentTaskFragment(splitScreenTask2, true /* moveTogether */);
splitScreenTask2.setAdjacentTaskFragment(splitScreenTask1, true /* moveTogether */);
final Task aboveTask =
createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -529,8 +528,8 @@ public class ZOrderingTests extends WindowTestsBase {
createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
final WindowState splitWindow2 =
createAppWindow(splitScreenTask2, ACTIVITY_TYPE_STANDARD, "splitWindow2");
splitScreenTask1.setAdjacentTaskFragment(splitScreenTask2);
splitScreenTask2.setAdjacentTaskFragment(splitScreenTask1);
splitScreenTask1.setAdjacentTaskFragment(splitScreenTask2, true /* moveTogether */);
splitScreenTask2.setAdjacentTaskFragment(splitScreenTask1, true /* moveTogether */);
mDisplayContent.assignChildLayers(mTransaction);