summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Louis Chang <louischang@google.com> 2020-04-10 17:39:35 +0800
committer Louis Chang <louischang@google.com> 2020-04-17 17:23:17 +0800
commit6434be4cb4b0af8ca2084480560e83e7e47c1d1e (patch)
tree7ad560766b08f2f389038a1be18f3e6fbf8da6e5
parent9f11dd4b649af1b984824eda53a9d0d6227f1257 (diff)
Adjusting focus starting from sibling rootable app tasks
The next rootable app task was not moved to front while another rootable app task which did not have running activities was on top. The task focus was not adjusted properly because the focus was adjusted between root tasks only. In that case, the next task info was delayed to dispatch to organizer until the finishing activity on top was destroyed. Bug: 152408408 Test: atest ActivityRecordTests Change-Id: I4ce5bf4ee3a48155654cc300eb51da5e2262962e
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java23
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java47
-rw-r--r--services/core/java/com/android/server/wm/Task.java74
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java25
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