Loading services/core/java/com/android/server/am/ActivityStack.java +35 −44 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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(); Loading Loading @@ -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) { Loading Loading @@ -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; Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +37 −1 Original line number Diff line number Diff line Loading @@ -454,6 +454,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. Loading Loading @@ -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) { Loading Loading @@ -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); } Loading services/core/java/com/android/server/wm/RootWindowContainer.java +13 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { return null; } /** * 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. Loading services/core/java/com/android/server/wm/WindowManagerService.java +10 −0 Original line number Diff line number Diff line Loading @@ -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( Loading Loading
services/core/java/com/android/server/am/ActivityStack.java +35 −44 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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(); Loading Loading @@ -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) { Loading Loading @@ -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; Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +37 −1 Original line number Diff line number Diff line Loading @@ -454,6 +454,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. Loading Loading @@ -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) { Loading Loading @@ -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); } Loading
services/core/java/com/android/server/wm/RootWindowContainer.java +13 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { return null; } /** * 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. Loading
services/core/java/com/android/server/wm/WindowManagerService.java +10 −0 Original line number Diff line number Diff line Loading @@ -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( Loading