Loading services/core/java/com/android/server/wm/ActivityRecord.java +6 −17 Original line number Diff line number Diff line Loading @@ -2543,23 +2543,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); Loading services/core/java/com/android/server/wm/ActivityStack.java +3 −44 Original line number Diff line number Diff line Loading @@ -847,7 +847,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. Loading Loading @@ -2069,7 +2070,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 Loading Loading @@ -2277,48 +2278,6 @@ class ActivityStack extends Task { return taskTop; } /** * 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. Loading services/core/java/com/android/server/wm/Task.java +74 −0 Original line number Diff line number Diff line Loading @@ -2579,6 +2579,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. Loading services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +25 −0 Original line number Diff line number Diff line Loading @@ -751,6 +751,31 @@ public class ActivityRecordTests extends ActivityTestsBase { assertTrue(stack1.isTopStackInDisplayArea()); } /** * 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. */ Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +6 −17 Original line number Diff line number Diff line Loading @@ -2543,23 +2543,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); Loading
services/core/java/com/android/server/wm/ActivityStack.java +3 −44 Original line number Diff line number Diff line Loading @@ -847,7 +847,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. Loading Loading @@ -2069,7 +2070,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 Loading Loading @@ -2277,48 +2278,6 @@ class ActivityStack extends Task { return taskTop; } /** * 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. Loading
services/core/java/com/android/server/wm/Task.java +74 −0 Original line number Diff line number Diff line Loading @@ -2579,6 +2579,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. Loading
services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +25 −0 Original line number Diff line number Diff line Loading @@ -751,6 +751,31 @@ public class ActivityRecordTests extends ActivityTestsBase { assertTrue(stack1.isTopStackInDisplayArea()); } /** * 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. */ Loading