Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a840176 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Fix moveToBack behavior in organizer-created root tasks" into rvc-dev...

Merge "Fix moveToBack behavior in organizer-created root tasks" into rvc-dev am: bc65eb2f am: 3b2e4c8a am: 8cd263bf

Change-Id: I2d649d801b20f0d3683cf7ce37b9cefba2035424
parents 3a4aebae 8cd263bf
Loading
Loading
Loading
Loading
+37 −11
Original line number Original line Diff line number Diff line
@@ -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 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.
     * @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()) {
        if (!isAttached()) {
            return;
            return;
        }
        }

        final TaskDisplayArea displayArea = getDisplayArea();
        getDisplayArea().positionStackAtBottom(this, reason);
        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) {
            if (task != null && task != this) {
                positionChildAtBottom(task);
                positionChildAtBottom(task);
            }
            }

            return;
        /**
        }
         * The intent behind moving a primary split screen stack to the back is usually to hide
        if (task == null || task == this) {
         * behind the home stack. Exit split screen in this case.
            return;
         */
        }
        if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
        // This is a created-by-organizer task. In this case, let the organizer deal with this
            setWindowingMode(WINDOWING_MODE_UNDEFINED);
        // 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");
        }
        }
    }
    }


+52 −8
Original line number Original line Diff line number Diff line
@@ -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.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
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.TaskDisplayArea.getStackAbove;
import static com.android.server.wm.WindowContainer.POSITION_TOP;


import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertThat;


@@ -140,9 +141,12 @@ public class ActivityStackTests extends ActivityTestsBase {
    }
    }


    @Test
    @Test
    public void testPrimarySplitScreenRestoresWhenMovedToBack() {
    public void testPrimarySplitScreenMoveToBack() {
        // Create primary splitscreen stack. This will create secondary stacks and places the
        TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
        // existing fullscreen stack on the bottom.
        // 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(
        final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);


@@ -165,12 +169,14 @@ public class ActivityStackTests extends ActivityTestsBase {
    }
    }


    @Test
    @Test
    public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() {
    public void testMoveToPrimarySplitScreenThenMoveToBack() {
        TestSplitOrganizer organizer = new TestSplitOrganizer(mService);
        // This time, start with a fullscreen activitystack
        // This time, start with a fullscreen activitystack
        final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
        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.
        // Assert windowing mode.
        assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode());
        assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode());
@@ -180,13 +186,51 @@ public class ActivityStackTests extends ActivityTestsBase {
                null /* task */);
                null /* task */);


        // Assert that stack is at the bottom.
        // 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)
        // Ensure that the override mode is restored to what it was (fullscreen)
        assertEquals(WINDOWING_MODE_FULLSCREEN,
        assertEquals(WINDOWING_MODE_UNDEFINED,
                primarySplitScreen.getRequestedOverrideWindowingMode());
                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
    @Test
    public void testStackInheritsDisplayWindowingMode() {
    public void testStackInheritsDisplayWindowingMode() {
        final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
        final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
+0 −63
Original line number Original line Diff line number Diff line
@@ -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_SWITCHES_CANCELED;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
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_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
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_SPLIT_SCREEN_SECONDARY;
@@ -64,10 +63,8 @@ import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;


import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
import android.app.IApplicationThread;
import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Intent;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo;
@@ -82,8 +79,6 @@ import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.IVoiceInteractionSession;
import android.view.Gravity;
import android.view.Gravity;
import android.window.ITaskOrganizer;
import android.window.WindowContainerToken;


import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;


@@ -1004,62 +999,4 @@ public class ActivityStarterTests extends ActivityTestsBase {


        verify(recentTasks, times(1)).add(any());
        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) {
        }
    };
}
}
+78 −0
Original line number Original line Diff line number Diff line
@@ -17,7 +17,10 @@
package com.android.server.wm;
package com.android.server.wm;


import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
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_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.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
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.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
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.ActivityOptions;
import android.app.IApplicationThread;
import android.app.IApplicationThread;
import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
@@ -43,6 +49,8 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.IVoiceInteractionSession;
import android.window.ITaskOrganizer;
import android.window.WindowContainerToken;


import com.android.server.AttributeCache;
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) {
        }
    };
}
}