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

Commit ab5de37d authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Made creation of multiple stacks more intentional.

Previous it was unintentional due to the following fixes:
- Made ACTIVITY_TYPE_UNDEFINED compatible with stacks of
ACTIVITY_TYPE_STANDARD. Any request to create an undefined stack type
ends up creates a standard type, so it makes sense for them to be
compatible.
- Made standard types of WINDOWING_MODE_UNDEFINED compatible with the
display's windowing mode. Any request to cerate a stack in an undefined
windowing mode end up creating a stack in the display's windowing mode.
- Added 'dumspys activity containers' for dumping the activity
hierarchy.
Now it is more intentional where we always create a stack for specific
stack activity types and windowing modes when getOrCreateStack is
called.

Bug: 67747409
Bug: 64146578
Test: go/wm-test
Test: Existing tests pass

Change-Id: I85935e8681113a0c06dfc15ef9891e3f91b98a02
parent f3193c6e
Loading
Loading
Loading
Loading
+34 −15
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ 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_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -168,9 +169,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
        } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
            return (T) mSplitScreenPrimaryStack;
        }

        for (int i = mStacks.size() - 1; i >= 0; --i) {
            final ActivityStack stack = mStacks.get(i);
            // TODO: Should undefined windowing and activity type be compatible with standard type?
            if (stack.isCompatible(windowingMode, activityType)) {
                return (T) stack;
            }
@@ -178,16 +179,29 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
        return null;
    }

    private boolean alwaysCreateStack(int windowingMode, int activityType) {
        // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
        // modes so that we can manage visual ordering and return types correctly.
        return activityType == ACTIVITY_TYPE_STANDARD
                && (windowingMode == WINDOWING_MODE_FULLSCREEN
                || windowingMode == WINDOWING_MODE_FREEFORM
                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
    }

    /**
     * Returns an existing stack compatible with the windowing mode and activity type or creates one
     * if a compatible stack doesn't exist.
     * @see #getStack(int, int)
     * @see #createStack(int, int, boolean)
     */
    <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
            boolean onTop) {
        if (!alwaysCreateStack(windowingMode, activityType)) {
            T stack = getStack(windowingMode, activityType);
            if (stack != null) {
                return stack;
            }
        }
        return createStack(windowingMode, activityType, onTop);
    }

@@ -238,17 +252,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
            }
        }

        final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
        if (!inSplitScreenMode
                && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
            // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
            // trying to launch in split-screen secondary.
            windowingMode = WINDOWING_MODE_FULLSCREEN;
        } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
                && WindowConfiguration.supportSplitScreenWindowingMode(
                        windowingMode, activityType)) {
            windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
        }
        windowingMode = updateWindowingModeForSplitScreenIfNeeded(windowingMode, activityType);

        final int stackId = mSupervisor.getNextStackId();

@@ -420,6 +424,21 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
        return mPinnedStack != null;
    }

    int updateWindowingModeForSplitScreenIfNeeded(int windowingMode, int activityType) {
        final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
        if (!inSplitScreenMode
                && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
            // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
            // trying to launch in split-screen secondary.
            return WINDOWING_MODE_FULLSCREEN;
        } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
                && WindowConfiguration.supportSplitScreenWindowingMode(
                windowingMode, activityType)) {
            return WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
        }
        return windowingMode;
    }

    @Override
    public String toString() {
        return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
+21 −1
Original line number Diff line number Diff line
@@ -4877,7 +4877,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (this) {
                return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions);
                return mStackSupervisor.startActivityFromRecents(taskId, bOptions);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
@@ -14890,6 +14890,10 @@ public class ActivityManagerService extends IActivityManager.Stub
                synchronized (this) {
                    dumpActivityStarterLocked(pw, dumpPackage);
                }
            } else if ("containers".equals(cmd)) {
                synchronized (this) {
                    dumpActivityContainersLocked(pw);
                }
            } else if ("recents".equals(cmd) || "r".equals(cmd)) {
                synchronized (this) {
                    if (mRecentTasks != null) {
@@ -15132,6 +15136,11 @@ public class ActivityManagerService extends IActivityManager.Stub
                if (dumpAll) {
                    pw.println("-------------------------------------------------------------------------------");
                }
                dumpActivityContainersLocked(pw);
                pw.println();
                if (dumpAll) {
                    pw.println("-------------------------------------------------------------------------------");
                }
                dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                if (mAssociations.size() > 0) {
                    pw.println();
@@ -15204,6 +15213,11 @@ public class ActivityManagerService extends IActivityManager.Stub
                if (dumpAll) {
                    pw.println("-------------------------------------------------------------------------------");
                }
                dumpActivityContainersLocked(pw);
                pw.println();
                if (dumpAll) {
                    pw.println("-------------------------------------------------------------------------------");
                }
                dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
                if (mAssociations.size() > 0) {
                    pw.println();
@@ -15236,6 +15250,12 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
    }
    private void dumpActivityContainersLocked(PrintWriter pw) {
        pw.println("ACTIVITY MANAGER STARTER (dumpsys activity containers)");
        mStackSupervisor.dumpChildrenNames(pw, " ");
        pw.println(" ");
    }
    private void dumpActivityStarterLocked(PrintWriter pw, String dumpPackage) {
        pw.println("ACTIVITY MANAGER STARTER (dumpsys activity starter)");
        mActivityStarter.dump(pw, "", dumpPackage);
+23 −0
Original line number Diff line number Diff line
@@ -480,6 +480,29 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        }
    }

    @Override
    public boolean isCompatible(int windowingMode, int activityType) {
        // TODO: Should we just move this to ConfigurationContainer?
        if (activityType == ACTIVITY_TYPE_UNDEFINED) {
            // Undefined activity types end up in a standard stack once the stack is created on a
            // display, so they should be considered compatible.
            activityType = ACTIVITY_TYPE_STANDARD;
        }
        final ActivityDisplay display = getDisplay();
        if (display != null) {
            if (activityType == ACTIVITY_TYPE_STANDARD
                    && windowingMode == WINDOWING_MODE_UNDEFINED) {
                // Standard activity types will mostly take on the windowing mode of the display if
                // one isn't specified, so look-up a compatible stack based on the display's
                // windowing mode.
                windowingMode = display.getWindowingMode();
            }
            windowingMode =
                    display.updateWindowingModeForSplitScreenIfNeeded(windowingMode, activityType);
        }
        return super.isCompatible(windowingMode, activityType);
    }

    /** Adds the stack to specified display and calls WindowManager to do the same. */
    void reparent(ActivityDisplay activityDisplay, boolean onTop) {
        removeFromDisplay();
+40 −46
Original line number Diff line number Diff line
@@ -706,7 +706,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
    }

    TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode) {
        return anyTaskForIdLocked(id, matchMode, null);
        return anyTaskForIdLocked(id, matchMode, null, !ON_TOP);
    }

    /**
@@ -714,11 +714,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
     * @param id Id of the task we would like returned.
     * @param matchMode The mode to match the given task id in.
     * @param aOptions The activity options to use for restoration. Can be null.
     * @param onTop If the stack for the task should be the topmost on the display.
     */
    TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode,
            @Nullable ActivityOptions aOptions) {
        // If there is a stack id set, ensure that we are attempting to actually restore a task
        // TODO: Don't really know if this is needed...
            @Nullable ActivityOptions aOptions, boolean onTop) {
        // If options are set, ensure that we are attempting to actually restore a task
        if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
            throw new IllegalArgumentException("Should not specify activity options for non-restore"
                    + " lookup");
@@ -730,9 +730,21 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = display.getChildAt(stackNdx);
                final TaskRecord task = stack.taskForIdLocked(id);
                if (task != null) {
                    return task;
                if (task == null) {
                    continue;
                }
                if (aOptions != null) {
                    // Resolve the stack the task should be placed in now based on options
                    // and reparent if needed.
                    final ActivityStack launchStack = getLaunchStack(null, aOptions, task, onTop);
                    if (launchStack != null && stack != launchStack) {
                        final int reparentMode = onTop
                                ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE;
                        task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME,
                                "anyTaskForIdLocked");
                    }
                }
                return task;
            }
        }

@@ -759,7 +771,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        }

        // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
        if (!restoreRecentTaskLocked(task, aOptions)) {
        if (!restoreRecentTaskLocked(task, aOptions, onTop)) {
            if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
                    "Couldn't restore task id=" + id + " found in recents");
            return null;
@@ -2248,11 +2260,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            }
        }

        if (isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
        if (windowingMode != WINDOWING_MODE_UNDEFINED
                && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
                supportsFreeform, supportsPip, activityType)) {
            return windowingMode;
        }
        return WINDOWING_MODE_FULLSCREEN;
        // Return root/systems windowing mode
        return getWindowingMode();
    }

    int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@@ -2266,7 +2280,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        if (activityType != ACTIVITY_TYPE_UNDEFINED) {
            return activityType;
        }
        return options != null ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED;
        if (options != null) {
            activityType = options.getLaunchActivityType();
        }
        return activityType != ACTIVITY_TYPE_UNDEFINED ? activityType : ACTIVITY_TYPE_STANDARD;
    }

    <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
@@ -2304,7 +2321,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            // Temporarily set the task id to invalid in case in re-entry.
            options.setLaunchTaskId(INVALID_TASK_ID);
            final TaskRecord task = anyTaskForIdLocked(taskId,
                    MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options);
                    MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
            options.setLaunchTaskId(taskId);
            if (task != null) {
                return task.getStack();
@@ -2330,14 +2347,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            }
            final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
            if (display != null) {
                for (int i = display.getChildCount() - 1; i >= 0; --i) {
                    stack = (T) display.getChildAt(i);
                    if (stack.isCompatible(windowingMode, activityType)) {
                stack = display.getOrCreateStack(windowingMode, activityType, onTop);
                if (stack != null) {
                    return stack;
                }
            }
                // TODO: We should create the stack we want on the display at this point.
            }
        }

        // Give preference to the stack and display of the input task and activity if they match the
@@ -2365,18 +2379,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            display = getDefaultDisplay();
        }

        stack = display.getOrCreateStack(windowingMode, activityType, onTop);
        if (stack != null) {
            return stack;
        }

        // Whatever...return some default for now.
        if (candidateTask != null && candidateTask.mBounds != null
                && mService.mSupportsFreeformWindowManagement) {
            windowingMode = WINDOWING_MODE_FREEFORM;
        } else {
            windowingMode = WINDOWING_MODE_FULLSCREEN;
        }
        return display.getOrCreateStack(windowingMode, activityType, onTop);
    }

@@ -2967,10 +2969,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
     *
     * @param task The recent task to be restored.
     * @param aOptions The activity options to use for restoration.
     * @param onTop If the stack for the task should be the topmost on the display.
     * @return true if the task has been restored successfully.
     */
    boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions) {
        final ActivityStack stack = getLaunchStack(null, aOptions, task, !ON_TOP);
    boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions, boolean onTop) {
        final ActivityStack stack = getLaunchStack(null, aOptions, task, onTop);
        final ActivityStack currentStack = task.getStack();
        if (currentStack != null) {
            // Task has already been restored once. See if we need to do anything more
@@ -2983,9 +2986,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
        }

        stack.addTask(task, !ON_TOP, "restoreRecentTask");
        stack.addTask(task, onTop, "restoreRecentTask");
        // TODO: move call for creation here and other place into Stack.addTask()
        task.createWindowContainer(!ON_TOP, true /* showForAllUsers */);
        task.createWindowContainer(onTop, true /* showForAllUsers */);
        if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
                "Added restored task=" + task + " to stack=" + stack);
        final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -4567,7 +4570,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        task.setTaskDockedResizing(true);
    }

    final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
    int startActivityFromRecents(int taskId, Bundle bOptions) {
        final TaskRecord task;
        final int callingUid;
        final String callingPackage;
@@ -4582,7 +4585,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            windowingMode = activityOptions.getLaunchWindowingMode();
        }
        if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
            throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
            throw new IllegalArgumentException("startActivityFromRecents: Task "
                    + taskId + " can't be launch in the home/recents stack.");
        }

@@ -4600,21 +4603,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            }

            task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE,
                    activityOptions);
                    activityOptions, ON_TOP);
            if (task == null) {
                continueUpdateBounds(ACTIVITY_TYPE_RECENTS);
                mWindowManager.executeAppTransition();
                throw new IllegalArgumentException(
                        "startActivityFromRecentsInner: Task " + taskId + " not found.");
            }

            // Since we don't have an actual source record here, we assume that the currently
            // focused activity was the source.
            final ActivityStack stack = getLaunchStack(null, activityOptions, task, ON_TOP);

            if (stack != null && task.getStack() != stack) {
                task.reparent(stack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
                        "startActivityFromRecents");
                        "startActivityFromRecents: Task " + taskId + " not found.");
            }

            // If the user must confirm credentials (e.g. when first launching a work app and the
+2 −2
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ class AppTaskImpl extends IAppTask.Stub {
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (this) {
                mService.mStackSupervisor.startActivityFromRecentsInner(mTaskId, null);
                mService.mStackSupervisor.startActivityFromRecents(mTaskId, null);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
Loading