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

Commit ab132eeb authored by Andrii Kulian's avatar Andrii Kulian
Browse files

Per-display resumed activities

Allow each display to have its own resumed activity. The focus is
defined by Z-order of displays reported from WindowManager.

Bug: 111541062
Test: ActivityManagerMultiDisplayTests
Change-Id: I347dcfcd1e34f4db985b7d9a649b0a1e6b730eee
parent fab85f0f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -62,6 +62,8 @@ message ActivityStackSupervisorProto {
    optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
    repeated ActivityDisplayProto displays = 2;
    optional KeyguardControllerProto keyguard_controller = 3;
    // TODO(b/111541062): Focused stack and resumed activity are now per-display. Topmost instances
    // can be obtained from top display and these fields can be removed.
    optional int32 focused_stack_id = 4;
    optional .com.android.server.wm.IdentifierProto resumed_activity = 5;
    // Whether or not the home activity is the recents activity. This is needed for the CTS tests to
@@ -77,6 +79,8 @@ message ActivityDisplayProto {
    optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
    optional int32 id = 2;
    repeated ActivityStackProto stacks = 3;
    optional int32 focused_stack_id = 4;
    optional .com.android.server.wm.IdentifierProto resumed_activity = 5;
}

message ActivityStackProto {
+79 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.am;

import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -31,13 +32,18 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
import static com.android.server.am.ActivityDisplayProto.ID;
import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
import static com.android.server.am.ActivityDisplayProto.STACKS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.TAG_STATES;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
@@ -350,6 +356,45 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
        return null;
    }

    ActivityStack getNextFocusableStack() {
        return getNextFocusableStack(null /* currentFocus */, false /* ignoreCurrent */);
    }

    ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
        final int currentWindowingMode = currentFocus != null
                ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;

        ActivityStack candidate = null;
        for (int i = mStacks.size() - 1; i >= 0; --i) {
            final ActivityStack stack = mStacks.get(i);
            if (ignoreCurrent && stack == currentFocus) {
                continue;
            }
            if (!stack.isFocusable() || !stack.shouldBeVisible(null)) {
                continue;
            }

            if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                    && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
                // If the currently focused stack is in split-screen secondary we save off the
                // top primary split-screen stack as a candidate for focus because we might
                // prefer focus to move to an other stack to avoid primary split-screen stack
                // overlapping with a fullscreen stack when a fullscreen stack is higher in z
                // than the next split-screen stack. Assistant stack, I am looking at you...
                // We only move the focus to the primary-split screen stack if there isn't a
                // better alternative.
                candidate = stack;
                continue;
            }
            if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
                // Use the candidate stack since we are now at the secondary split-screen.
                return candidate;
            }
            return stack;
        }
        return candidate;
    }

    ActivityRecord getResumedActivity() {
        final ActivityStack focusedStack = getFocusedStack();
        if (focusedStack == null) {
@@ -371,6 +416,30 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
        return resumedActivity;
    }

    /**
     * Pause all activities in either all of the stacks or just the back stacks.
     * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
     * @param resuming The resuming activity.
     * @param dontWait The resuming activity isn't going to wait for all activities to be paused
     *                 before resuming.
     * @return true if any activity was paused as a result of this call.
     */
    boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
        boolean someActivityPaused = false;
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            // TODO(b/111541062): Check if resumed activity on this display instead
            if (!mSupervisor.isTopDisplayFocusedStack(stack)
                    && stack.getResumedActivity() != null) {
                if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
                        " mResumedActivity=" + stack.getResumedActivity());
                someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
                        dontWait);
            }
        }
        return someActivityPaused;
    }

    /**
     * Removes stacks in the input windowing modes from the system if they are of activity type
     * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
@@ -898,6 +967,16 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
        final long token = proto.start(fieldId);
        super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
        proto.write(ID, mDisplayId);
        final ActivityStack focusedStack = getFocusedStack();
        if (focusedStack != null) {
            proto.write(FOCUSED_STACK_ID, focusedStack.mStackId);
            final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
            if (focusedActivity != null) {
                focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
            }
        } else {
            proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
        }
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            stack.writeToProto(proto, STACKS);
+4 −4
Original line number Diff line number Diff line
@@ -4380,7 +4380,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        mWindowManager.deferSurfaceLayout();
        try {
            if (!restarting && hasVisibleActivities
                    && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
                    && !mStackSupervisor.resumeFocusedStacksTopActivitiesLocked()) {
                // If there was nothing to resume, and we are not already restarting this process, but
                // there is a visible activity that is hosted by the process...  then make sure all
                // visible activities are running, taking care of restarting this process.
@@ -5468,7 +5468,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        // Clean-up disabled activities.
        if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
                packageName, disabledClasses, true, false, userId) && mBooted) {
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
            mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
            mStackSupervisor.scheduleIdleLocked();
        }
@@ -5642,7 +5642,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                }
            }
            if (mBooted) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
                mStackSupervisor.scheduleIdleLocked();
            }
        }
@@ -10198,7 +10198,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
            mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
            mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
            BinderInternal.nSetBinderProxyCountWatermarks(6000,5500);
+2 −2
Original line number Diff line number Diff line
@@ -1941,7 +1941,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
            } else {
                if (deferRelaunchUntilPaused) {
                    stack.destroyActivityLocked(this, true /* removeFromApp */, "stop-config");
                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                    mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
                } else {
                    mStackSupervisor.updatePreviousProcessLocked(this);
                }
@@ -2362,7 +2362,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
            frozenBeforeDestroy = true;
            if (!service.updateDisplayOverrideConfigurationLocked(config, this,
                    false /* deferResume */, displayId)) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
            }
        }
        service.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
+38 −43
Original line number Diff line number Diff line
@@ -497,7 +497,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            if (DEBUG_STACK) Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:"
                    + reason);
            setResumedActivity(record, reason + " - onActivityStateChanged");
            if (record == mStackSupervisor.getTopResumedActivity()) {
                // TODO(b/111541062): Support tracking multiple resumed activities
                mService.setResumedActivityUncheckLocked(record, reason);
            }
            mStackSupervisor.mRecentTasks.add(record.getTask());
        }
    }
@@ -663,7 +666,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai

        if (!deferEnsuringVisibility) {
            mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
            mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
        }
    }

@@ -696,7 +699,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
        postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
        adjustFocusToNextFocusableStack("reparent", true /* allowFocusSelf */);
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
        mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
        // Update visibility of activities before notifying WM. This way it won't try to resize
        // windows that are no longer visible.
        mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
@@ -1445,7 +1448,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        if (prev == null) {
            if (resuming == null) {
                Slog.wtf(TAG, "Trying to pause when nothing is resumed");
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
            }
            return false;
        }
@@ -1525,7 +1528,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            // pause, so just treat it as being paused now.
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
            if (resuming == null) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
            }
            return false;
        }
@@ -1619,7 +1622,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        if (resumeNext) {
            final ActivityStack topStack = mStackSupervisor.getTopDisplayFocusedStack();
            if (!topStack.shouldSleepOrShutDownActivities()) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
                mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(topStack, prev, null);
            } else {
                checkReadyForSleep();
                ActivityRecord top = topStack.topRunningActivityLocked();
@@ -1628,7 +1631,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                    // something. Also if the top activity on the stack is not the just paused
                    // activity, we need to go ahead and resume it to ensure we complete an
                    // in-flight app switch.
                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                    mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
                }
            }
        }
@@ -2307,7 +2310,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
     *
     * NOTE: It is not safe to call this method directly as it can cause an activity in a
     *       non-focused stack to be resumed.
     *       Use {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked} to resume the
     *       Use {@link ActivityStackSupervisor#resumeFocusedStacksTopActivitiesLocked} to resume the
     *       right activity for the current system state.
     */
    @GuardedBy("mService")
@@ -2470,7 +2473,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0
                && !lastResumedCanPip;

        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
        boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
@@ -2659,7 +2662,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                // the screen based on the new activity order.
                boolean notUpdated = true;

                if (mStackSupervisor.isTopDisplayFocusedStack(this)) {
                if (isFocusedStackOnDisplay()) {
                    // We have special rotation behavior when here is some active activity that
                    // requests specific orientation or Keyguard is locked. Make sure all activity
                    // visibilities are set correctly as well as the transition is updated if needed
@@ -2791,12 +2794,13 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai

    private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev,
            ActivityOptions options, String reason) {
        if (adjustFocusToNextFocusableStack(reason)) {
        final ActivityStack nextFocusedStack = adjustFocusToNextFocusableStack(reason);
        if (nextFocusedStack != null) {
            // Try to move focus to the next visible stack with a running activity if this
            // stack is not covering the entire screen or is on a secondary display (with no home
            // stack).
            return mStackSupervisor.resumeFocusedStackTopActivityLocked(
                    mStackSupervisor.getTopDisplayFocusedStack(), prev, null);
            return mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(nextFocusedStack, prev,
                    null /* targetOptions */);
        }

        // Let's just start up the Launcher...
@@ -2809,20 +2813,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                mStackSupervisor.resumeHomeStackTask(prev, reason);
    }

    private TaskRecord getNextTask(TaskRecord targetTask) {
        final int index = mTaskHistory.indexOf(targetTask);
        if (index >= 0) {
            final int numTasks = mTaskHistory.size();
            for (int i = index + 1; i < numTasks; ++i) {
                TaskRecord task = mTaskHistory.get(i);
                if (task.userId == targetTask.userId) {
                    return task;
                }
            }
        }
        return null;
    }

    /** Returns the position the input task should be placed in this stack. */
    int getAdjustedPositionForTask(TaskRecord task, int suggestedPosition,
            ActivityRecord starting) {
@@ -3437,7 +3427,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        }

        // Move focus to next focusable stack if possible.
        if (adjustFocusToNextFocusableStack(myReason)) {
        if (adjustFocusToNextFocusableStack(myReason) != null) {
            return;
        }

@@ -3445,21 +3435,25 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        mStackSupervisor.moveHomeStackTaskToTop(myReason);
    }

    /** Find next proper focusable stack and make it focused. */
    boolean adjustFocusToNextFocusableStack(String reason) {
    /**
     * Find next proper focusable stack and make it focused.
     * @return The stack that now got the focus, {@code null} if none found.
     */
    ActivityStack adjustFocusToNextFocusableStack(String reason) {
        return adjustFocusToNextFocusableStack(reason, false /* allowFocusSelf */);
    }

    /**
     * Find next proper focusable stack and make it focused.
     * @param allowFocusSelf Is the focus allowed to remain on the same stack.
     * @return The stack that now got the focus, {@code null} if none found.
     */
    private boolean adjustFocusToNextFocusableStack(String reason, boolean allowFocusSelf) {
    private ActivityStack adjustFocusToNextFocusableStack(String reason, boolean allowFocusSelf) {
        final ActivityStack stack =
                mStackSupervisor.getNextFocusableStackLocked(this, !allowFocusSelf);
        final String myReason = reason + " adjustFocusToNextFocusableStack";
        if (stack == null) {
            return false;
            return null;
        }

        final ActivityRecord top = stack.topRunningActivityLocked();
@@ -3467,11 +3461,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        if (stack.isActivityTypeHome() && (top == null || !top.visible)) {
            // If we will be focusing on the home stack next and its current top activity isn't
            // visible, then use the move the home stack task to top to make the activity visible.
            return mStackSupervisor.moveHomeStackTaskToTop(reason);
            mStackSupervisor.moveHomeStackTaskToTop(reason);
            return stack;
        }

        stack.moveToFront(myReason);
        return true;
        return stack;
    }

    final void stopActivityLocked(ActivityRecord r) {
@@ -3877,7 +3872,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                        false /* markFrozenIfConfigChanged */, true /* deferResume */);
            }
            if (activityRemoved) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
            }
            if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
                    "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
@@ -3890,7 +3885,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
        mStackSupervisor.mFinishingActivities.add(r);
        r.resumeKeyDispatchingLocked();
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
        mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
        return r;
    }

@@ -4236,7 +4231,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            }
        }
        if (activityRemoved) {
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
            mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
        }
    }

@@ -4431,7 +4426,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            }
        }

        mStackSupervisor.resumeFocusedStackTopActivityLocked();
        mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
    }

    private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
@@ -4664,7 +4659,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                topActivity.supportsEnterPipOnTaskSwitch = true;
            }

            mStackSupervisor.resumeFocusedStackTopActivityLocked();
            mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
            EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);

            mService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.taskId);
@@ -4735,7 +4730,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            return true;
        }

        mStackSupervisor.resumeFocusedStackTopActivityLocked();
        mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
        return true;
    }

@@ -4782,7 +4777,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        if (updatedConfig) {
            // Ensure the resumed state of the focus activity if we updated the configuration of
            // any activity.
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
            mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
        }
    }

@@ -5182,7 +5177,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            if (isOnHomeDisplay() && mode != REMOVE_TASK_MODE_MOVING_TO_TOP
                    && mStackSupervisor.isTopDisplayFocusedStack(this)) {
                String myReason = reason + " leftTaskHistoryEmpty";
                if (!inMultiWindowMode() || !adjustFocusToNextFocusableStack(myReason)) {
                if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) {
                    mStackSupervisor.moveHomeStackToFront(myReason);
                }
            }
@@ -5287,7 +5282,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        // The task might have already been running and its visibility needs to be synchronized with
        // the visibility of the stack / windows.
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
        mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
    }

    private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) {
Loading