diff options
4 files changed, 108 insertions, 61 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 521ffa50f869..1bf070f4bf3c 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2536,23 +2536,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pauseKeyDispatchingLocked(); - // We are finishing the top focused activity and its stack has nothing to be focused so - // the next focusable stack should be focused. - if (mayAdjustTop - && (stack.topRunningActivity() == null || !stack.isTopActivityFocusable())) { - if (shouldAdjustGlobalFocus) { - // Move the entire hierarchy to top with updating global top resumed activity - // and focused application if needed. - stack.adjustFocusToNextFocusableStack("finish-top"); - } else { - // Only move the next stack to top in its task container. - final TaskDisplayArea taskDisplayArea = stack.getDisplayArea(); - next = taskDisplayArea.topRunningActivity(); - if (next != null) { - taskDisplayArea.positionStackAtTop(next.getRootTask(), - false /* includingParents */, "finish-display-top"); - } - } + // We are finishing the top focused activity and its task has nothing to be focused so + // the next focusable task should be focused. + if (mayAdjustTop && ((ActivityStack) task).topRunningActivity(true /* focusableOnly */) + == null) { + task.adjustFocusToNextFocusableTask("finish-top", false /* allowFocusSelf */, + shouldAdjustGlobalFocus); } finishActivityResults(resultCode, resultData); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 5968eede0a27..265b5e26720e 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -856,7 +856,8 @@ class ActivityStack extends Task { /** Resume next focusable stack after reparenting to another display. */ void postReparent() { - adjustFocusToNextFocusableStack("reparent", true /* allowFocusSelf */); + adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */, + true /* moveParentsToTop */); mRootWindowContainer.resumeFocusedStacksTopActivities(); // Update visibility of activities before notifying WM. This way it won't try to resize // windows that are no longer visible. @@ -2282,7 +2283,7 @@ class ActivityStack extends Task { final String reason = "noMoreActivities"; if (!isActivityTypeHome()) { - final ActivityStack nextFocusedStack = adjustFocusToNextFocusableStack(reason); + final ActivityStack nextFocusedStack = adjustFocusToNextFocusableTask(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 @@ -2491,48 +2492,6 @@ class ActivityStack extends Task { } /** - * 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 ActivityStack adjustFocusToNextFocusableStack(String reason, boolean allowFocusSelf) { - final ActivityStack stack = - mRootWindowContainer.getNextFocusableStack(this, !allowFocusSelf); - final String myReason = reason + " adjustFocusToNextFocusableStack"; - if (stack == null) { - return null; - } - - final ActivityRecord top = stack.topRunningActivity(); - - if (stack.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) { - // 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. - stack.getDisplayArea().moveHomeActivityToTop(reason); - return stack; - } - - stack.moveToFront(myReason); - // Top display focused stack is changed, update top resumed activity if needed. - if (stack.mResumedActivity != null) { - mStackSupervisor.updateTopResumedActivityIfNeeded(); - // Set focused app directly because if the next focused activity is already resumed - // (e.g. the next top activity is on a different display), there won't have activity - // state change to update it. - mAtmService.setResumedActivityUncheckLocked(stack.mResumedActivity, reason); - } - return stack; - } - - /** * Finish the topmost activity that belongs to the crashed app. We may also finish the activity * that requested launch of the crashed one to prevent launch-crash loop. * @param app The app that crashed. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 1ffa01c2bd66..7d43d0014853 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2572,6 +2572,80 @@ class Task extends WindowContainer<WindowContainer> { return currentCount[0]; } + /** + * Find next proper focusable stack and make it focused. + * @return The stack that now got the focus, {@code null} if none found. + */ + ActivityStack adjustFocusToNextFocusableTask(String reason) { + return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */, + true /* moveParentsToTop */); + } + + /** Return the next focusable task by looking from the siblings and parent tasks */ + private Task getNextFocusableTask(boolean allowFocusSelf) { + final WindowContainer parent = getParent(); + if (parent == null) { + return null; + } + + final Task focusableTask = parent.getTask((task) -> (allowFocusSelf || task != this) + && ((ActivityStack) task).isFocusableAndVisible()); + if (focusableTask == null && parent.asTask() != null) { + return parent.asTask().getNextFocusableTask(allowFocusSelf); + } else { + return focusableTask; + } + } + + /** + * Find next proper focusable task and make it focused. + * @param reason The reason of making the adjustment. + * @param allowFocusSelf Is the focus allowed to remain on the same task. + * @param moveParentsToTop Whether to move parents to top while making the task focused. + * @return The root task that now got the focus, {@code null} if none found. + */ + ActivityStack adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, + boolean moveParentsToTop) { + ActivityStack focusableTask = (ActivityStack) getNextFocusableTask(allowFocusSelf); + if (focusableTask == null) { + focusableTask = mRootWindowContainer.getNextFocusableStack((ActivityStack) this, + !allowFocusSelf); + } + if (focusableTask == null) { + return null; + } + + final String myReason = reason + " adjustFocusToNextFocusableStack"; + final ActivityRecord top = focusableTask.topRunningActivity(); + final ActivityStack rootTask = (ActivityStack) focusableTask.getRootTask(); + if (focusableTask.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) { + // 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. + focusableTask.getDisplayArea().moveHomeActivityToTop(myReason); + return rootTask; + } + + if (!moveParentsToTop) { + // Only move the next stack to top in its task container. + WindowContainer parent = focusableTask.getParent(); + parent.positionChildAt(POSITION_TOP, focusableTask, false /* includingParents */); + return rootTask; + } + + // Move the entire hierarchy to top with updating global top resumed activity + // and focused application if needed. + focusableTask.moveToFront(myReason); + // Top display focused stack is changed, update top resumed activity if needed. + if (rootTask.mResumedActivity != null) { + mStackSupervisor.updateTopResumedActivityIfNeeded(); + // Set focused app directly because if the next focused activity is already resumed + // (e.g. the next top activity is on a different display), there won't have activity + // state change to update it. + mAtmService.setResumedActivityUncheckLocked(rootTask.mResumedActivity, reason); + } + return rootTask; + } + /** Calculate the minimum possible position for a task that can be shown to the user. * The minimum position will be above all other tasks that can't be shown. * @param minPosition The minimum position the caller is suggesting. diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 5bbb4d9e712c..6a28918eab00 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -752,6 +752,31 @@ public class ActivityRecordTests extends ActivityTestsBase { } /** + * Verify that when finishing the top focused activity while root task was created by organizer, + * the stack order will be changed by adjusting focus. + */ + @Test + public void testFinishActivityIfPossible_adjustStackOrderOrganizedRoot() { + // Make mStack be a the root task that created by task organizer + mStack.mCreatedByOrganizer = true; + + // Have two tasks (topRootableTask and mTask) as the children of mStack. + ActivityRecord topActivity = new ActivityBuilder(mActivity.mAtmService) + .setCreateTask(true) + .setStack(mStack) + .build(); + ActivityStack topRootableTask = (ActivityStack) topActivity.getTask(); + topRootableTask.moveToFront("test"); + assertTrue(mStack.isTopStackInDisplayArea()); + + // Finish top activity and verify the next focusable rootable task has adjusted to top. + topActivity.setState(RESUMED, "test"); + topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test", + false /* oomAdj */); + assertEquals(mTask, mStack.getTopMostTask()); + } + + /** * Verify that resumed activity is paused due to finish request. */ @Test |