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

Commit 30e441de authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Support for setting stack windowing mode

We currently create a in stack in the windowing mode we want anytime we
want to change the windowing mode of a task which isn't optimal.
We now change the current stack windowing mode for some cases vs.
creating a new stack.

Test: go/wm-smoke
Bug: 64146578
Fixes: 68948655
Fixes: 65739235
Fixes: 29068935
Change-Id: I9fceb7d608e86610c1fb5ba59b15087a96e7401e
parent 0fbd9d16
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -736,7 +736,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
        // However, the window bounds include the insets, so we need to subtract them here to make
        // them identical.
        if (ssp.hasDockedTask()) {
            if (systemInsets.bottom < windowRect.height()) {
                // Only apply inset if it isn't going to cause the rect height to go negative.
                windowRect.bottom -= systemInsets.bottom;
            }
            systemInsets.bottom = 0;
        }
        calculateWindowStableInsets(systemInsets, windowRect, displayRect);
+56 −27
Original line number Diff line number Diff line
@@ -276,17 +276,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
        if (windowingMode == WINDOWING_MODE_PINNED) {
            return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
        }
        final T stack = (T) new ActivityStack(
        return (T) new ActivityStack(
                        this, stackId, mSupervisor, windowingMode, activityType, onTop);

        if (mDisplayId == DEFAULT_DISPLAY && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
            // Make sure recents stack exist when creating a dock stack as it normally needs to be
            // on the other side of the docked stack and we make visibility decisions based on that.
            // TODO: Not sure if this is needed after we change to calculate visibility based on
            // stack z-order vs. id.
            getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop);
        }
        return stack;
    }

    /**
@@ -365,6 +356,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
                        + " already exist on display=" + this + " stack=" + stack);
            }
            mSplitScreenPrimaryStack = stack;
            onSplitScreenModeActivated();
        }
    }

@@ -377,6 +369,42 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
            mPinnedStack = null;
        } else if (stack == mSplitScreenPrimaryStack) {
            mSplitScreenPrimaryStack = null;
            // Inform the reset of the system that split-screen mode was dismissed so things like
            // resizing all the other stacks can take place.
            onSplitScreenModeDismissed();
        }
    }

    private void onSplitScreenModeDismissed() {
        mSupervisor.mWindowManager.deferSurfaceLayout();
        try {
            // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
            for (int i = mStacks.size() - 1; i >= 0; --i) {
                final ActivityStack otherStack = mStacks.get(i);
                if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
                    continue;
                }
                otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
            }
        } finally {
            mSupervisor.mWindowManager.continueSurfaceLayout();
        }
    }

    private void onSplitScreenModeActivated() {
        mSupervisor.mWindowManager.deferSurfaceLayout();
        try {
            // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
            for (int i = mStacks.size() - 1; i >= 0; --i) {
                final ActivityStack otherStack = mStacks.get(i);
                if (otherStack == mSplitScreenPrimaryStack
                        || !otherStack.affectedBySplitScreenResize()) {
                    continue;
                }
                otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
            }
        } finally {
            mSupervisor.mWindowManager.continueSurfaceLayout();
        }
    }

@@ -475,22 +503,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
                supportsFreeform, supportsPip, activityType)) {
            return windowingMode;
        }
        // Return the display's windowing mode
        return getWindowingMode();
    }

    /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */
    int getTopVisibleStackActivityType(int excludeWindowingMode) {
        for (int i = mStacks.size() - 1; i >= 0; --i) {
            final ActivityStack stack = mStacks.get(i);
            if (stack.getWindowingMode() == excludeWindowingMode) {
                continue;
            }
            if (stack.shouldBeVisible(null /* starting */)) {
                return stack.getActivityType();
            }
        }
        return ACTIVITY_TYPE_UNDEFINED;
        // Try to use the display's windowing mode otherwise fallback to fullscreen.
        windowingMode = getWindowingMode();
        return windowingMode != WINDOWING_MODE_UNDEFINED
                ? windowingMode : WINDOWING_MODE_FULLSCREEN;
    }

    /**
@@ -599,7 +615,20 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
    }

    public void dump(PrintWriter pw, String prefix) {
        pw.println(prefix + "displayId=" + mDisplayId + " mStacks=" + mStacks);
        pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
        final String myPrefix = prefix + " ";
        if (mHomeStack != null) {
            pw.println(myPrefix + "mHomeStack=" + mHomeStack);
        }
        if (mRecentsStack != null) {
            pw.println(myPrefix + "mRecentsStack=" + mRecentsStack);
        }
        if (mPinnedStack != null) {
            pw.println(myPrefix + "mPinnedStack=" + mPinnedStack);
        }
        if (mSplitScreenPrimaryStack != null) {
            pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack);
        }
    }

    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+65 −76
Original line number Diff line number Diff line
@@ -4755,7 +4755,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            throws RemoteException {
        Slog.i(TAG, "Activity tried to startVoiceInteraction");
        synchronized (this) {
            ActivityRecord activity = getFocusedStack().topActivity();
            ActivityRecord activity = getFocusedStack().getTopActivity();
            if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
                throw new SecurityException("Only focused activity can call startVoiceInteraction");
            }
@@ -10431,13 +10431,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                            "exitFreeformMode: You can only go fullscreen from freeform.");
                }
                final ActivityStack fullscreenStack = stack.getDisplay().getOrCreateStack(
                        WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP);
                if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r);
                // TODO: Should just change windowing mode vs. re-parenting...
                r.getTask().reparent(fullscreenStack, ON_TOP,
                        REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "exitFreeformMode");
                stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
@@ -10446,6 +10440,11 @@ public class ActivityManagerService extends IActivityManager.Stub
    @Override
    public void setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) {
        if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
            setTaskWindowingModeSplitScreenPrimary(taskId, SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
                    toTop, ANIMATE, null /* initialBounds */);
            return;
        }
        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
        synchronized (this) {
            final long ident = Binder.clearCallingIdentity();
@@ -10458,56 +10457,16 @@ public class ActivityManagerService extends IActivityManager.Stub
                if (DEBUG_STACK) Slog.d(TAG_STACK, "setTaskWindowingMode: moving task=" + taskId
                        + " to windowingMode=" + windowingMode + " toTop=" + toTop);
                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                    mWindowManager.setDockedStackCreateState(SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
                            null /* initialBounds */);
                }
                if (!task.isActivityTypeStandardOrUndefined()) {
                    throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move task "
                            + taskId + " to non-standard windowin mode=" + windowingMode);
                    throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
                            + " non-standard task " + taskId + " to windowing mode="
                            + windowingMode);
                }
                final ActivityDisplay display = task.getStack().getDisplay();
                final ActivityStack stack = display.getOrCreateStack(windowingMode,
                        task.getStack().getActivityType(), toTop);
                // TODO: We should just change the windowing mode for the task vs. creating and
                // moving it to a stack.
                task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
                        "moveTaskToStack");
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }
    @Override
    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
        synchronized (this) {
            long ident = Binder.clearCallingIdentity();
            try {
                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
                if (task == null) {
                    Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId);
                    return;
                }
                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
                        + " to stackId=" + stackId + " toTop=" + toTop);
                final ActivityStack stack = mStackSupervisor.getStack(stackId);
                if (stack == null) {
                    throw new IllegalStateException(
                            "moveTaskToStack: No stack for stackId=" + stackId);
                }
                if (!stack.isActivityTypeStandardOrUndefined()) {
                    throw new IllegalArgumentException("moveTaskToStack: Attempt to move task "
                            + taskId + " to stack " + stackId);
                }
                if (stack.inSplitScreenPrimaryWindowingMode()) {
                    mWindowManager.setDockedStackCreateState(
                            SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
                }
                // TODO: Use ActivityStack.setWindowingMode instead of re-parenting.
                task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
                        "moveTaskToStack");
            } finally {
@@ -10517,7 +10476,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    }
    /**
     * Moves the input task to the primary-split-screen stack.
     * Moves the specified task to the primary-split-screen stack.
     *
     * @param taskId Id of task to move.
     * @param createMode The mode the primary split screen stack should be created in if it doesn't
@@ -10526,7 +10485,7 @@ public class ActivityManagerService extends IActivityManager.Stub
     *                   and
     *                   {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
     * @param toTop If the task and stack should be moved to the top.
     * @param animate Whether we should play an animation for the moving the task
     * @param animate Whether we should play an animation for the moving the task.
     * @param initialBounds If the primary stack gets created, it will use these bounds for the
     *                      stack. Pass {@code null} to use default bounds.
     */
@@ -10546,22 +10505,55 @@ public class ActivityManagerService extends IActivityManager.Stub
                if (DEBUG_STACK) Slog.d(TAG_STACK,
                        "setTaskWindowingModeSplitScreenPrimary: moving task=" + taskId
                        + " to createMode=" + createMode + " toTop=" + toTop);
                if (!task.isActivityTypeStandardOrUndefined()) {
                    throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
                            + " non-standard task " + taskId + " to split-screen windowing mode");
                }
                mWindowManager.setDockedStackCreateState(createMode, initialBounds);
                final int windowingMode = task.getWindowingMode();
                final ActivityStack stack = task.getStack();
                if (toTop) {
                    stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
                }
                stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate);
                return windowingMode != task.getWindowingMode();
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }
                final ActivityDisplay display = task.getStack().getDisplay();
                final ActivityStack stack = display.getOrCreateStack(
                        WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, task.getStack().getActivityType(),
                        toTop);
                // Defer resuming until we move the home stack to the front below
                // TODO: Should just change windowing mode vs. re-parenting...
                final boolean moved = task.reparent(stack, toTop,
                        REPARENT_KEEP_STACK_AT_FRONT, animate, !DEFER_RESUME,
                        "setTaskWindowingModeSplitScreenPrimary");
                if (moved) {
                    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    @Override
    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
        synchronized (this) {
            long ident = Binder.clearCallingIdentity();
            try {
                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
                if (task == null) {
                    Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId);
                    return;
                }
                return moved;
                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
                        + " to stackId=" + stackId + " toTop=" + toTop);
                final ActivityStack stack = mStackSupervisor.getStack(stackId);
                if (stack == null) {
                    throw new IllegalStateException(
                            "moveTaskToStack: No stack for stackId=" + stackId);
                }
                if (!stack.isActivityTypeStandardOrUndefined()) {
                    throw new IllegalArgumentException("moveTaskToStack: Attempt to move task "
                            + taskId + " to stack " + stackId);
                }
                if (stack.inSplitScreenPrimaryWindowingMode()) {
                    mWindowManager.setDockedStackCreateState(
                            SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
                }
                task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
                        "moveTaskToStack");
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
@@ -10584,14 +10576,11 @@ public class ActivityManagerService extends IActivityManager.Stub
                    Slog.w(TAG, "dismissSplitScreenMode: primary split-screen stack not found.");
                    return;
                }
                if (toTop) {
                    mStackSupervisor.resizeStackLocked(stack, null /* destBounds */,
                            null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
                            true /* preserveWindows */, true /* allowResizeInDockedMode */,
                            !DEFER_RESUME);
                } else {
                    mStackSupervisor.moveTasksToFullscreenStackLocked(stack, false /* onTop */);
                    stack.moveToFront("dismissSplitScreenMode");
                }
                stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
@@ -12947,7 +12936,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                return false;
            }
            final ActivityRecord activity = focusedStack.topActivity();
            final ActivityRecord activity = focusedStack.getTopActivity();
            if (activity == null) {
                return false;
            }
@@ -12964,7 +12953,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        try {
            synchronized (this) {
                ActivityRecord caller = ActivityRecord.forTokenLocked(token);
                ActivityRecord top = getFocusedStack().topActivity();
                ActivityRecord top = getFocusedStack().getTopActivity();
                if (top != caller) {
                    Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
                            + " is not current top " + top);
@@ -13007,7 +12996,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                "enqueueAssistContext()");
        synchronized (this) {
            ActivityRecord activity = getFocusedStack().topActivity();
            ActivityRecord activity = getFocusedStack().getTopActivity();
            if (activity == null) {
                Slog.w(TAG, "getAssistContextExtras failed: no top activity");
                return null;
+138 −19

File changed.

Preview size limit exceeded, changes collapsed.

+7 −7
Original line number Diff line number Diff line
@@ -2945,6 +2945,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
     * Returns the reparent target stack, creating the stack if necessary.  This call also enforces
     * the various checks on tasks that are going to be reparented from one stack to another.
     */
    // TODO: Look into changing users to this method to ActivityDisplay.resolveWindowingMode()
    ActivityStack getReparentTargetStack(TaskRecord task, ActivityStack stack, boolean toTop) {
        final ActivityStack prevStack = task.getStack();
        final int stackId = stack.mStackId;
@@ -2971,8 +2972,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                    + " reparent task=" + task + " to stackId=" + stackId);
        }

        // Ensure that we aren't trying to move into a freeform stack without freeform
        // support
        // Ensure that we aren't trying to move into a freeform stack without freeform support
        if (stack.getWindowingMode() == WINDOWING_MODE_FREEFORM
                && !mService.mSupportsFreeformWindowManagement) {
            throw new IllegalArgumentException("Device doesn't support freeform, can not reparent"
@@ -3376,7 +3376,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D

        // When launching tasks behind, update the last active time of the top task after the new
        // task has been shown briefly
        final ActivityRecord top = stack.topActivity();
        final ActivityRecord top = stack.getTopActivity();
        if (top != null) {
            top.getTask().touchActiveTime();
        }
@@ -4200,10 +4200,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            }
        }

        final ActivityRecord topActivity = task.getTopActivity();
        if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
            // Display a warning toast that we tried to put a non-dockable task in the docked
            // stack.
            // Display a warning toast that we tried to put an app that doesn't support split-screen
            // in split-screen.
            mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();

            // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
@@ -4217,6 +4216,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            return;
        }

        final ActivityRecord topActivity = task.getTopActivity();
        if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
            && !topActivity.noDisplay) {
            final String packageName = topActivity.appInfo.packageName;
@@ -4552,7 +4552,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                final ActivityStack stack = display.getChildAt(j);
                // Get top activity from a visible stack and add it to the list.
                if (stack.shouldBeVisible(null /* starting */)) {
                    final ActivityRecord top = stack.topActivity();
                    final ActivityRecord top = stack.getTopActivity();
                    if (top != null) {
                        if (stack == mFocusedStack) {
                            topActivityTokens.add(0, top.appToken);
Loading