diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index f75ce250c8e2d..6087fb3050326 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1559,12 +1559,13 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL return STACK_INVISIBLE; } - final ActivityStack focusedStack = mStackSupervisor.getFocusedStack(); - final int focusedStackId = focusedStack.mStackId; + // Check position and visibility of this stack relative to the front stack on its display. + final ActivityStack topStack = getTopStackOnDisplay(); + final int topStackId = topStack.mStackId; if (StackId.isBackdropToTranslucentActivity(mStackId) - && hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(focusedStackId) - && !focusedStack.topActivity().fullscreen) { + && hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(topStackId) + && !topStack.topActivity().fullscreen) { // The fullscreen or assistant stack should be visible if it has a visible behind // activity behind the home or recents stack that is translucent. return STACK_VISIBLE_ACTIVITY_BEHIND; @@ -1574,39 +1575,39 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL // Docked stack is always visible, except in the case where the top running activity // task in the focus stack doesn't support any form of resizing but we show it for the // home task even though it's not resizable. - final ActivityRecord r = focusedStack.topRunningActivityLocked(); + final ActivityRecord r = topStack.topRunningActivityLocked(); final TaskRecord task = r != null ? r.task : null; return task == null || task.supportsSplitScreen() || task.isHomeTask() ? STACK_VISIBLE : STACK_INVISIBLE; } - // Find the first stack behind focused stack that actually got something visible. - int stackBehindFocusedIndex = mStacks.indexOf(focusedStack) - 1; - while (stackBehindFocusedIndex >= 0 && - mStacks.get(stackBehindFocusedIndex).topRunningActivityLocked() == null) { - stackBehindFocusedIndex--; + // Find the first stack behind front stack that actually got something visible. + int stackBehindTopIndex = mStacks.indexOf(topStack) - 1; + while (stackBehindTopIndex >= 0 && + mStacks.get(stackBehindTopIndex).topRunningActivityLocked() == null) { + stackBehindTopIndex--; } - if ((focusedStackId == DOCKED_STACK_ID || focusedStackId == PINNED_STACK_ID) - && stackIndex == stackBehindFocusedIndex) { + if ((topStackId == DOCKED_STACK_ID || topStackId == PINNED_STACK_ID) + && stackIndex == stackBehindTopIndex) { // Stacks directly behind the docked or pinned stack are always visible. return STACK_VISIBLE; } - final int stackBehindFocusedId = (stackBehindFocusedIndex >= 0) - ? mStacks.get(stackBehindFocusedIndex).mStackId : INVALID_STACK_ID; + final int stackBehindTopId = (stackBehindTopIndex >= 0) + ? mStacks.get(stackBehindTopIndex).mStackId : INVALID_STACK_ID; - if (StackId.isBackdropToTranslucentActivity(focusedStackId) - && focusedStack.isStackTranslucent(starting, stackBehindFocusedId)) { + if (StackId.isBackdropToTranslucentActivity(topStackId) + && topStack.isStackTranslucent(starting, stackBehindTopId)) { // Stacks behind the fullscreen or assistant stack with a translucent activity are // always visible so they can act as a backdrop to the translucent activity. // For example, dialog activities - if (stackIndex == stackBehindFocusedIndex) { + if (stackIndex == stackBehindTopIndex) { return STACK_VISIBLE; } - if (stackBehindFocusedIndex >= 0) { - if ((stackBehindFocusedId == DOCKED_STACK_ID - || stackBehindFocusedId == PINNED_STACK_ID) - && stackIndex == (stackBehindFocusedIndex - 1)) { + if (stackBehindTopIndex >= 0) { + if ((stackBehindTopId == DOCKED_STACK_ID + || stackBehindTopId == PINNED_STACK_ID) + && stackIndex == (stackBehindTopIndex - 1)) { // The stack behind the docked or pinned stack is also visible so we can have a // complete backdrop to the translucent activity when the docked stack is up. return STACK_VISIBLE; @@ -4271,8 +4272,8 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL AppTimeTracker timeTracker, String reason) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); - final ActivityRecord focusedTopActivity = mStackSupervisor.getFocusedStack() != null - ? mStackSupervisor.getFocusedStack().topActivity() : null; + final ActivityStack topStack = getTopStackOnDisplay(); + final ActivityRecord topActivity = topStack != null ? topStack.topActivity() : null; final int numTasks = mTaskHistory.size(); final int index = mTaskHistory.indexOf(tr); if (numTasks == 0 || index < 0) { @@ -4297,7 +4298,7 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL insertTaskAtTop(tr, null); // Don't refocus if invisible to current user - ActivityRecord top = tr.getTopActivity(); + final ActivityRecord top = tr.getTopActivity(); if (top == null || !top.okToShowLocked()) { addRecentActivityLocked(top); ActivityOptions.abort(options); @@ -4305,7 +4306,7 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL } // Set focus to the top running activity of this stack. - ActivityRecord r = topRunningActivityLocked(); + final ActivityRecord r = topRunningActivityLocked(); mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, reason); if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr); @@ -4320,8 +4321,8 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL } // If a new task is moved to the front, then mark the existing top activity as supporting // picture-in-picture while paused - if (focusedTopActivity != null) { - focusedTopActivity.supportsPictureInPictureWhilePausing = true; + if (topActivity != null) { + topActivity.supportsPictureInPictureWhilePausing = true; } mStackSupervisor.resumeFocusedStackTopActivityLocked(); @@ -4447,6 +4448,15 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL return true; } + /** + * Get the topmost stack on the current display. It may be different from focused stack, because + * focus may be on another display. + */ + private ActivityStack getTopStackOnDisplay() { + final ArrayList stacks = mActivityContainer.mActivityDisplay.mStacks; + return stacks.isEmpty() ? null : stacks.get(stacks.size() - 1); + } + static void logStartActivity(int tag, ActivityRecord r, TaskRecord task) { final Uri data = r.intent.getData(); final String strData = data != null ? data.toSafeString() : null; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 9d95804cd2126..4b1dcca75fb37 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -181,6 +181,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Set; public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener { @@ -2772,7 +2773,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D stack.prepareFreezingTaskBounds(); // Make sure the task has the appropriate bounds/size for the stack it is in. - if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) { + if (stackId == FULLSCREEN_WORKSPACE_STACK_ID + && !Objects.equals(task.mBounds, stack.mBounds)) { kept = task.resize(stack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow, deferResume); } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) { @@ -2895,6 +2897,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mService.mTaskChangeNotificationController.notifyActivityPinned(); } + /** Move activity with its stack to front and make the stack focused. */ boolean moveFocusableActivityStackToFrontLocked(ActivityRecord r, String reason) { if (r == null || !r.isFocusable()) { if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, @@ -4905,24 +4908,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * @return a list of activities which are the top ones in each visible stack. The first * entry will be the focused activity. */ - public List getTopVisibleActivities() { - // TODO(multi-display): Get rid of DEFAULT_DISPLAY here. Used in - // VoiceInteractionManagerServiceImpl#showSessionLocked. - final ActivityDisplay display = mActivityDisplays.get(DEFAULT_DISPLAY); - if (display == null) { - return Collections.EMPTY_LIST; - } - ArrayList topActivityTokens = new ArrayList<>(); - final ArrayList stacks = display.mStacks; - for (int i = stacks.size() - 1; i >= 0; i--) { - ActivityStack stack = stacks.get(i); - if (stack.getStackVisibilityLocked(null) == ActivityStack.STACK_VISIBLE) { - ActivityRecord top = stack.topActivity(); - if (top != null) { - if (stack == mFocusedStack) { - topActivityTokens.add(0, top.appToken); - } else { - topActivityTokens.add(top.appToken); + List getTopVisibleActivities() { + final ArrayList topActivityTokens = new ArrayList<>(); + // Traverse all displays. + for (int i = mActivityDisplays.size(); i >= 0; i--) { + final ActivityDisplay display = mActivityDisplays.valueAt(i); + // Traverse all stacks on a display. + for (int j = display.mStacks.size() - 1; j >= 0; j--) { + final ActivityStack stack = display.mStacks.get(j); + // Get top activity from a visible stack and add it to the list. + if (stack.getStackVisibilityLocked(null /* starting */) + == ActivityStack.STACK_VISIBLE) { + final ActivityRecord top = stack.topActivity(); + if (top != null) { + if (stack == mFocusedStack) { + topActivityTokens.add(0, top.appToken); + } else { + topActivityTokens.add(top.appToken); + } } } }