summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java79
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java38
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
4 files changed, 95 insertions, 45 deletions
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ddef339caa5d..f7c3cea2eed6 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1390,24 +1390,6 @@ final class ActivityStack extends ConfigurationContainer {
return null;
}
- ActivityStack getNextFocusableStackLocked() {
- ArrayList<ActivityStack> stacks = mStacks;
- final ActivityRecord parent = mActivityContainer.mParentActivity;
- if (parent != null) {
- stacks = parent.getStack().mStacks;
- }
- if (stacks != null) {
- for (int i = stacks.size() - 1; i >= 0; --i) {
- ActivityStack stack = stacks.get(i);
- if (stack != this && stack.isFocusable()
- && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
- return stack;
- }
- }
- }
- return null;
- }
-
/** Returns true if the stack contains a fullscreen task. */
private boolean hasFullscreenTask() {
for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
@@ -2098,9 +2080,15 @@ final class ActivityStack extends ConfigurationContainer {
return false;
}
- ActivityRecord parent = mActivityContainer.mParentActivity;
- if ((parent != null && parent.state != ActivityState.RESUMED) ||
- !mActivityContainer.isAttachedLocked()) {
+ // Find the topmost activity in this stack that is not finishing.
+ final ActivityRecord next = topRunningActivityLocked();
+
+ final boolean hasRunningActivity = next != null;
+
+ final ActivityRecord parent = mActivityContainer.mParentActivity;
+ final boolean isParentNotResumed = parent != null && parent.state != ActivityState.RESUMED;
+ if (hasRunningActivity
+ && (isParentNotResumed || !mActivityContainer.isAttachedLocked())) {
// Do not resume this stack if its parent is not resumed.
// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false;
@@ -2108,33 +2096,14 @@ final class ActivityStack extends ConfigurationContainer {
mStackSupervisor.cancelInitializingActivities();
- // Find the first activity that is not finishing.
- final ActivityRecord next = topRunningActivityLocked();
-
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
- final TaskRecord prevTask = prev != null ? prev.task : null;
- if (next == null) {
- // There are no more activities!
- final String reason = "noMoreActivities";
- if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
- // Try to move focus to the next visible stack with a running activity if this
- // stack is not covering the entire screen.
- return mStackSupervisor.resumeFocusedStackTopActivityLocked(
- mStackSupervisor.getFocusedStack(), prev, null);
- }
-
- // Let's just start up the Launcher...
- ActivityOptions.abort(options);
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeTopActivityLocked: No more activities go home");
- if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
- // Only resume home if on home display
- return isOnHomeDisplay() &&
- mStackSupervisor.resumeHomeStackTask(prev, reason);
+ if (!hasRunningActivity) {
+ // There are no activities left in the stack, let's look somewhere else.
+ return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");
}
next.delayedResume = false;
@@ -2152,6 +2121,7 @@ final class ActivityStack extends ConfigurationContainer {
}
final TaskRecord nextTask = next.task;
+ final TaskRecord prevTask = prev != null ? prev.task : null;
if (prevTask != null && prevTask.getStack() == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2527,6 +2497,27 @@ final class ActivityStack extends ConfigurationContainer {
return true;
}
+ private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev,
+ ActivityOptions options, String reason) {
+ if ((!mFullscreen || !isOnHomeDisplay())
+ && adjustFocusToNextFocusableStackLocked(reason)) {
+ // 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
+ // stack).
+ return mStackSupervisor.resumeFocusedStackTopActivityLocked(
+ mStackSupervisor.getFocusedStack(), prev, null);
+ }
+
+ // Let's just start up the Launcher...
+ ActivityOptions.abort(options);
+ if (DEBUG_STATES) Slog.d(TAG_STATES,
+ "resumeTopActivityInNextFocusableStack: " + reason + ", go home");
+ if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+ // Only resume home if on home display
+ return isOnHomeDisplay() &&
+ mStackSupervisor.resumeHomeStackTask(prev, reason);
+ }
+
private TaskRecord getNextTask(TaskRecord targetTask) {
final int index = mTaskHistory.indexOf(targetTask);
if (index >= 0) {
@@ -3151,7 +3142,7 @@ final class ActivityStack extends ConfigurationContainer {
}
private boolean adjustFocusToNextFocusableStackLocked(String reason) {
- final ActivityStack stack = getNextFocusableStackLocked();
+ final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(this);
final String myReason = reason + " adjustFocusToNextFocusableStack";
if (stack == null) {
return false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8ab3ac39dd5b..5def3403dc56 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -455,6 +455,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
/**
+ * Temp storage for display ids sorted in focus order.
+ * Maps position to id. Using {@link SparseIntArray} instead of {@link ArrayList} because
+ * it's more efficient, as the number of displays is usually small.
+ */
+ private SparseIntArray mTmpOrderedDisplayIds = new SparseIntArray();
+
+ /**
* Used to keep track whether app visibilities got changed since the last pause. Useful to
* determine whether to invoke the task stack change listener after pausing.
*/
@@ -637,7 +644,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
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 = focusCandidate.getNextFocusableStackLocked();
+ focusCandidate = getNextFocusableStackLocked(focusCandidate);
}
if (focusCandidate != mFocusedStack) {
@@ -2019,6 +2026,35 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return mActivityDisplays.valueAt(DEFAULT_DISPLAY).mStacks;
}
+ /**
+ * Get next focusable stack in the system. This will search across displays and stacks
+ * in last-focused order for a focusable and visible stack, different from the target stack.
+ *
+ * @param currentFocus The stack that previously had focus and thus needs to be ignored when
+ * searching for next candidate.
+ * @return Next focusable {@link ActivityStack}, null if not found.
+ */
+ ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
+ mWindowManager.getDisplaysInFocusOrder(mTmpOrderedDisplayIds);
+
+ for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
+ final int displayId = mTmpOrderedDisplayIds.get(i);
+ final List<ActivityStack> stacks = mActivityDisplays.get(displayId).mStacks;
+ if (stacks == null) {
+ continue;
+ }
+ for (int j = stacks.size() - 1; j >= 0; --j) {
+ final ActivityStack stack = stacks.get(j);
+ if (stack != currentFocus && stack.isFocusable()
+ && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
+ return stack;
+ }
+ }
+ }
+
+ return null;
+ }
+
ActivityRecord getHomeActivity() {
return getHomeActivityForUser(mCurrentUser);
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 349740b0bd38..dc06d129c5bb 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -166,6 +166,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
}
/**
+ * Get an array with display ids ordered by focus priority - last items should be given
+ * focus first. Sparse array just maps position to displayId.
+ */
+ void getDisplaysInFocusOrder(SparseIntArray displaysInFocusOrder) {
+ displaysInFocusOrder.clear();
+
+ final int size = mChildren.size();
+ for (int i = 0; i < size; ++i) {
+ displaysInFocusOrder.put(i, mChildren.get(i).getDisplayId());
+ }
+ }
+
+ /**
* Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
* there is a Display for the displayId.
*
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d5aa01b6a0b7..38cb54320a1b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6638,6 +6638,16 @@ public class WindowManagerService extends IWindowManager.Stub
displayInfo.overscanRight, displayInfo.overscanBottom);
}
+ /**
+ * Get an array with display ids ordered by focus priority - last items should be given
+ * focus first. Sparse array just maps position to displayId.
+ */
+ public void getDisplaysInFocusOrder(SparseIntArray displaysInFocusOrder) {
+ synchronized(mWindowMap) {
+ mRoot.getDisplaysInFocusOrder(displaysInFocusOrder);
+ }
+ }
+
@Override
public void setOverscan(int displayId, int left, int top, int right, int bottom) {
if (mContext.checkCallingOrSelfPermission(