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

Commit a72448e8 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Move last focused stack from global to per-display"

parents e1a83fef bbb63c26
Loading
Loading
Loading
Loading
+59 −4
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
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.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.am.ActivityStackSupervisor.TAG_STATES;
import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
@@ -120,6 +121,13 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
     */
    private ActivityStack mPreferredTopFocusableStack;

    /**
     * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
     * stack has been resumed. If stacks are changing position this will hold the old stack until
     * the new stack becomes resumed after which it will be set to current focused stack.
     */
    private ActivityStack mLastFocusedStack;

    // Cached reference to some special stacks we tend to get a lot so we don't need to loop
    // through the list to find them.
    private ActivityStack mHomeStack = null;
@@ -182,20 +190,33 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
    }

    void positionChildAtTop(ActivityStack stack, boolean includingParents) {
        positionChildAt(stack, mStacks.size(), includingParents);
        positionChildAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
    }

    void positionChildAtTop(ActivityStack stack, boolean includingParents,
            String updateLastFocusedStackReason) {
        positionChildAt(stack, mStacks.size(), includingParents, updateLastFocusedStackReason);
    }

    void positionChildAtBottom(ActivityStack stack) {
        positionChildAt(stack, 0, false /* includingParents */);
        positionChildAtBottom(stack, null /* updateLastFocusedStackReason */);
    }

    void positionChildAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
        positionChildAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
    }

    private void positionChildAt(ActivityStack stack, int position) {
        positionChildAt(stack, position, false /* includingParents */);
        positionChildAt(stack, position, false /* includingParents */,
                null /* updateLastFocusedStackReason */);
    }

    private void positionChildAt(ActivityStack stack, int position, boolean includingParents) {
    private void positionChildAt(ActivityStack stack, int position, boolean includingParents,
            String updateLastFocusedStackReason) {
        // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
        //       the position internally, also update the logic here
        final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
                ? getFocusedStack() : null;
        final boolean wasContained = mStacks.remove(stack);
        final int insertPosition = getTopInsertPosition(stack, position);
        mStacks.add(insertPosition, stack);
@@ -211,6 +232,17 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
            mPreferredTopFocusableStack = null;
        }

        if (updateLastFocusedStackReason != null) {
            final ActivityStack currentFocusedStack = getFocusedStack();
            if (currentFocusedStack != prevFocusedStack) {
                mLastFocusedStack = prevFocusedStack;
                EventLogTags.writeAmFocusedStack(mSupervisor.mCurrentUser, mDisplayId,
                        currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(),
                        mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(),
                        updateLastFocusedStackReason);
            }
        }

        // Since positionChildAt() is called during the creation process of pinned stacks,
        // ActivityStack#getWindowContainerController() can be null. In this special case,
        // since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
@@ -458,6 +490,26 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
        return resumedActivity;
    }

    ActivityStack getLastFocusedStack() {
        return mLastFocusedStack;
    }

    boolean allResumedActivitiesComplete() {
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityRecord r = mStacks.get(stackNdx).getResumedActivity();
            if (r != null && !r.isState(RESUMED)) {
                return false;
            }
        }
        final ActivityStack currentFocusedStack = getFocusedStack();
        if (DEBUG_STACK) {
            Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
                    + mLastFocusedStack + " to=" + currentFocusedStack);
        }
        mLastFocusedStack = currentFocusedStack;
        return true;
    }

    /**
     * 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().
@@ -1138,6 +1190,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
        if (mPreferredTopFocusableStack != null) {
            pw.println(myPrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
        }
        if (mLastFocusedStack != null) {
            pw.println(myPrefix + "mLastFocusedStack=" + mLastFocusedStack);
        }
    }

    public void dumpStacks(PrintWriter pw) {
+16 −19
Original line number Diff line number Diff line
@@ -1105,12 +1105,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            display.moveHomeStackToFront(reason + " returnToHome");
        }

        display.positionChildAtTop(this, true /* includingParents */);
        mStackSupervisor.setFocusStackUnchecked(reason, this);
        if (task != null) {
        final boolean movingTask = task != null;
        display.positionChildAtTop(this, !movingTask /* includingParents */, reason);
        if (movingTask) {
            // This also moves the entire hierarchy branch to top, including parents
            insertTaskAtTop(task, null);
            return;
            insertTaskAtTop(task, null /* starting */);
        }
    }

@@ -1131,13 +1130,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            setWindowingMode(WINDOWING_MODE_UNDEFINED);
        }

        getDisplay().positionChildAtBottom(this);
        mStackSupervisor.setFocusStackUnchecked(reason, getDisplay().getTopStack());
        getDisplay().positionChildAtBottom(this, reason);
        if (task != null) {
            // TODO(b/111541062): We probably don't want to change display z-order to bottom just
            // because one of its stacks moved to bottom.
            insertTaskAtBottom(task);
            return;
        }
    }

@@ -2431,10 +2428,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
        }

        next.delayedResume = false;
        final ActivityDisplay display = getDisplay();

        // If the top activity is the resumed one, nothing to do.
        if (mResumedActivity == next && next.isState(RESUMED)
                && mStackSupervisor.allResumedActivitiesComplete()) {
                && display.allResumedActivitiesComplete()) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            executeAppTransition(options);
@@ -2500,7 +2498,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai

        boolean lastResumedCanPip = false;
        ActivityRecord lastResumed = null;
        final ActivityStack lastFocusedStack = mStackSupervisor.getTopDisplayLastFocusedStack();
        final ActivityStack lastFocusedStack = display.getLastFocusedStack();
        if (lastFocusedStack != null && lastFocusedStack != this) {
            // So, why aren't we using prev here??? See the param comment on the method. prev doesn't
            // represent the last resumed activity. However, the last focus stack does if it isn't null.
@@ -2545,7 +2543,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            }
            return true;
        } else if (mResumedActivity == next && next.isState(RESUMED)
                && mStackSupervisor.allResumedActivitiesComplete()) {
                && display.allResumedActivitiesComplete()) {
            // It is possible for the activity to be resumed when we paused back stacks above if the
            // next activity doesn't have to wait for pause to complete.
            // So, nothing else to-do except:
@@ -2661,7 +2659,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai

        mStackSupervisor.mNoAnimActivities.clear();

        ActivityStack lastStack = mStackSupervisor.getTopDisplayLastFocusedStack();
        if (next.attachedToProcess()) {
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
                    + " stopped=" + next.stopped + " visible=" + next.visible);
@@ -2673,10 +2670,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            // Launcher is already visible in this case. If we don't add it to opening
            // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
            // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
            final boolean lastActivityTranslucent = lastStack != null
                    && (lastStack.inMultiWindowMode()
                    || (lastStack.mLastPausedActivity != null
                    && !lastStack.mLastPausedActivity.fullscreen));
            final boolean lastActivityTranslucent = lastFocusedStack != null
                    && (lastFocusedStack.inMultiWindowMode()
                    || (lastFocusedStack.mLastPausedActivity != null
                    && !lastFocusedStack.mLastPausedActivity.fullscreen));

            // The contained logic must be synchronized, since we are both changing the visibility
            // and updating the {@link Configuration}. {@link ActivityRecord#setVisibility} will
@@ -2693,7 +2690,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                next.startLaunchTickingLocked();

                ActivityRecord lastResumedActivity =
                        lastStack == null ? null :lastStack.mResumedActivity;
                        lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity;
                final ActivityState lastState = next.getState();

                mService.updateCpuStats();
@@ -2798,8 +2795,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                    Slog.i(TAG, "Restarting because process died: " + next);
                    if (!next.hasBeenLaunched) {
                        next.hasBeenLaunched = true;
                    } else  if (SHOW_APP_STARTING_PREVIEW && lastStack != null
                            && lastStack.isTopStackOnDisplay()) {
                    } else  if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null
                            && lastFocusedStack.isTopStackOnDisplay()) {
                        next.showStartingWindow(null /* prev */, false /* newTask */,
                                false /* taskSwitch */);
                    }
+2 −65
Original line number Diff line number Diff line
@@ -338,11 +338,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
    /** The current user */
    int mCurrentUser;

    /** If this is the same as mFocusedStack then the activity on the top of the focused stack has
     * been resumed. If stacks are changing position this will hold the old stack until the new
     * stack becomes resumed after which it will be set to mFocusedStack. */
    private ActivityStack mLastFocusedStack;

    /** List of activities that are waiting for a new activity to become visible before completing
     * whatever operation they are supposed to do. */
    // TODO: Remove mActivitiesWaitingForVisibleActivity list and just remove activity from
@@ -693,8 +688,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D

        final ActivityDisplay defaultDisplay = getDefaultDisplay();

        mLastFocusedStack = defaultDisplay.getOrCreateStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
        defaultDisplay.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
        positionChildAt(defaultDisplay, ActivityDisplay.POSITION_TOP);
    }

@@ -762,43 +756,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        return container.getWindowConfiguration().canReceiveKeys() || alwaysFocusable;
    }

    ActivityStack getTopDisplayLastFocusedStack() {
        return mLastFocusedStack;
    }

    boolean isTopDisplayFocusedStack(ActivityStack stack) {
        return stack != null && stack == getTopDisplayFocusedStack();
    }

    /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */
    void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
        if (!focusCandidate.isFocusable()) {
            // The focus candidate isn't focusable. Move focus to the top stack that is focusable.
            focusCandidate = getNextFocusableStackLocked(focusCandidate, false /* ignoreCurrent */);
            if (focusCandidate == null) {
                Slog.w(TAG,
                        "setFocusStackUnchecked: No focusable stack found, focus home as default");
                focusCandidate = getDefaultDisplay().getHomeStack();
            }
        }

        final ActivityStack currentFocusedStack = getTopDisplayFocusedStack();
        if (currentFocusedStack != focusCandidate) {
            mLastFocusedStack = currentFocusedStack;
            // TODO(b/111541062): Update event log to include focus movements on all displays
            EventLogTags.writeAmFocusedStack(
                    mCurrentUser, focusCandidate == null ? -1 : focusCandidate.getStackId(),
                    mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
        }

        final ActivityRecord r = topRunningActivityLocked();
        if (mService.isBooting() || !mService.isBooted()) {
            if (r != null && r.idle) {
                checkFinishBootingLocked();
            }
        }
    }

    void moveRecentsStackToFront(String reason) {
        final ActivityStack recentsStack = getDefaultDisplay().getStack(
                WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
@@ -1092,28 +1053,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        return true;
    }

    boolean allResumedActivitiesComplete() {
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = display.getChildAt(stackNdx);
                if (isTopDisplayFocusedStack(stack)) {
                    final ActivityRecord r = stack.getResumedActivity();
                    if (r != null && !r.isState(RESUMED)) {
                        return false;
                    }
                }
            }
        }
        // TODO: Not sure if this should check if all Paused are complete too.
        final ActivityStack focusedStack = getTopDisplayFocusedStack();
        if (DEBUG_STACK) Slog.d(TAG_STACK,
                "allResumedActivitiesComplete: mLastFocusedStack changing from="
                        + mLastFocusedStack + " to=" + focusedStack);
        mLastFocusedStack = focusedStack;
        return true;
    }

    private boolean allResumedActivitiesVisible() {
        boolean foundResumed = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -3674,7 +3613,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        if (isTopDisplayFocusedStack(stack)) {
            mService.updateUsageStats(r, true);
        }
        if (allResumedActivitiesComplete()) {
        if (stack.getDisplay().allResumedActivitiesComplete()) {
            ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            mWindowManager.executeAppTransition();
            return true;
@@ -3985,8 +3924,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        pw.print(prefix);
        pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack());
        pw.print(prefix);
        pw.println("mLastFocusedStack=" + mLastFocusedStack);
        pw.print(prefix);
        pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
        pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
        for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
+1 −1
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ option java_package com.android.server.am
30043 am_set_resumed_activity (User|1|5),(Component Name|3),(Reason|3)

# Stack focus
30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
30044 am_focused_stack (User|1|5),(Display Id|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)

# Running pre boot receiver
30045 am_pre_boot (User|1|5),(Package|3)
+19 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;

import static com.android.server.am.ActivityStackSupervisor.ON_TOP;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import android.platform.test.annotations.Presubmit;
@@ -52,6 +53,24 @@ public class ActivityDisplayTests extends ActivityTestsBase {
        setupActivityTaskManagerService();
    }

    @Test
    public void testLastFocusedStackIsUpdatedWhenMovingStack() {
        // Create a stack at bottom.
        final ActivityDisplay display = mSupervisor.getDefaultDisplay();
        final ActivityStack stack = display.createStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, !ON_TOP);
        final ActivityStack prevFocusedStack = display.getFocusedStack();

        stack.moveToFront("moveStackToFront");
        // After moving the stack to front, the previous focused should be the last focused.
        assertTrue(stack.isFocusedStackOnDisplay());
        assertEquals(prevFocusedStack, display.getLastFocusedStack());

        stack.moveToBack("moveStackToBack", null /* task */);
        // After moving the stack to back, the stack should be the last focused.
        assertEquals(stack, display.getLastFocusedStack());
    }

    /**
     * This test simulates the picture-in-picture menu activity launches an activity to fullscreen
     * stack. The fullscreen stack should be the top focused for resuming correctly.