diff options
| author | 2018-10-03 12:28:29 +0800 | |
|---|---|---|
| committer | 2018-10-05 13:24:21 +0800 | |
| commit | bbb63c26b1a9f3dec69f12dc2f588f02adf4423a (patch) | |
| tree | beecf6ca5cbfb999b2af51062d2e9e49b68a3f17 | |
| parent | b49951053543ad337194177fb44c465ce6cfe273 (diff) | |
Move last focused stack from global to per-display
- Update last focused stack when moving stack to front or back by
comparing updated focused stack with ideal previous one.
- Print event log am_focused_stack by display.
- Remove setFocusStackUnchecked because it is no longer used to set
current focus.
- Change allResumedActivitiesComplete to per-display for checking
whether to execute transition (originally it is global but still
only check for the top focused).
- Remove checking of finish booting (added in commit f3ea23ad9b)
when moving order of stack. That intended to fix a corner case
when home is idle but it is not the topmost. Currently the case
won't happen because now:
1. The restored empty tasks from recent will be put on bottom.
2. The checking in activityIdleInternalLocked uses
isTopDisplayFocusedStack that will not be affected by empty
(non-focusable or invisible) stacks on top.
Bug: 117198947
Test: atest ActivityDisplayTests
Change-Id: I5dcce337b4b6e33807b7a6729720cebd062356e2
5 files changed, 97 insertions, 89 deletions
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index fcb717ed51f0..a648b09abda5 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -43,6 +43,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.ActivityStack.ActivityState.RESUMED; import static com.android.server.am.ActivityStackSupervisor.FindTaskResult; import static com.android.server.am.ActivityStackSupervisor.TAG_STATES; import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS; @@ -120,6 +121,13 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> */ private ActivityStack mPreferredTopFocusableStack; + /** + * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused + * stack has been resumed. If stacks are changing position this will hold the old stack until + * the new stack becomes resumed after which it will be set to current focused stack. + */ + private ActivityStack mLastFocusedStack; + // Cached reference to some special stacks we tend to get a lot so we don't need to loop // through the list to find them. private ActivityStack mHomeStack = null; @@ -182,20 +190,33 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> } void positionChildAtTop(ActivityStack stack, boolean includingParents) { - positionChildAt(stack, mStacks.size(), includingParents); + positionChildAtTop(stack, includingParents, null /* updateLastFocusedStackReason */); + } + + void positionChildAtTop(ActivityStack stack, boolean includingParents, + String updateLastFocusedStackReason) { + positionChildAt(stack, mStacks.size(), includingParents, updateLastFocusedStackReason); } void positionChildAtBottom(ActivityStack stack) { - positionChildAt(stack, 0, false /* includingParents */); + positionChildAtBottom(stack, null /* updateLastFocusedStackReason */); + } + + void positionChildAtBottom(ActivityStack stack, String updateLastFocusedStackReason) { + positionChildAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason); } private void positionChildAt(ActivityStack stack, int position) { - positionChildAt(stack, position, false /* includingParents */); + positionChildAt(stack, position, false /* includingParents */, + null /* updateLastFocusedStackReason */); } - private void positionChildAt(ActivityStack stack, int position, boolean includingParents) { + private void positionChildAt(ActivityStack stack, int position, boolean includingParents, + String updateLastFocusedStackReason) { // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust // the position internally, also update the logic here + final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null + ? getFocusedStack() : null; final boolean wasContained = mStacks.remove(stack); final int insertPosition = getTopInsertPosition(stack, position); mStacks.add(insertPosition, stack); @@ -211,6 +232,17 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> mPreferredTopFocusableStack = null; } + if (updateLastFocusedStackReason != null) { + final ActivityStack currentFocusedStack = getFocusedStack(); + if (currentFocusedStack != prevFocusedStack) { + mLastFocusedStack = prevFocusedStack; + EventLogTags.writeAmFocusedStack(mSupervisor.mCurrentUser, mDisplayId, + currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(), + mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), + updateLastFocusedStackReason); + } + } + // Since positionChildAt() is called during the creation process of pinned stacks, // ActivityStack#getWindowContainerController() can be null. In this special case, // since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(), @@ -458,6 +490,26 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> return resumedActivity; } + ActivityStack getLastFocusedStack() { + return mLastFocusedStack; + } + + boolean allResumedActivitiesComplete() { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord r = mStacks.get(stackNdx).getResumedActivity(); + if (r != null && !r.isState(RESUMED)) { + return false; + } + } + final ActivityStack currentFocusedStack = getFocusedStack(); + if (DEBUG_STACK) { + Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from=" + + mLastFocusedStack + " to=" + currentFocusedStack); + } + mLastFocusedStack = currentFocusedStack; + return true; + } + /** * Pause all activities in either all of the stacks or just the back stacks. * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving(). @@ -1138,6 +1190,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (mPreferredTopFocusableStack != null) { pw.println(myPrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack); } + if (mLastFocusedStack != null) { + pw.println(myPrefix + "mLastFocusedStack=" + mLastFocusedStack); + } } public void dumpStacks(PrintWriter pw) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index ea807adc7d4f..ebfaf0fe9a7e 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1105,12 +1105,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai display.moveHomeStackToFront(reason + " returnToHome"); } - display.positionChildAtTop(this, true /* includingParents */); - mStackSupervisor.setFocusStackUnchecked(reason, this); - if (task != null) { + final boolean movingTask = task != null; + display.positionChildAtTop(this, !movingTask /* includingParents */, reason); + if (movingTask) { // This also moves the entire hierarchy branch to top, including parents - insertTaskAtTop(task, null); - return; + insertTaskAtTop(task, null /* starting */); } } @@ -1131,13 +1130,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai setWindowingMode(WINDOWING_MODE_UNDEFINED); } - getDisplay().positionChildAtBottom(this); - mStackSupervisor.setFocusStackUnchecked(reason, getDisplay().getTopStack()); + getDisplay().positionChildAtBottom(this, reason); if (task != null) { // TODO(b/111541062): We probably don't want to change display z-order to bottom just // because one of its stacks moved to bottom. insertTaskAtBottom(task); - return; } } @@ -2431,10 +2428,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } next.delayedResume = false; + final ActivityDisplay display = getDisplay(); // If the top activity is the resumed one, nothing to do. if (mResumedActivity == next && next.isState(RESUMED) - && mStackSupervisor.allResumedActivitiesComplete()) { + && display.allResumedActivitiesComplete()) { // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. executeAppTransition(options); @@ -2500,7 +2498,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai boolean lastResumedCanPip = false; ActivityRecord lastResumed = null; - final ActivityStack lastFocusedStack = mStackSupervisor.getTopDisplayLastFocusedStack(); + final ActivityStack lastFocusedStack = display.getLastFocusedStack(); if (lastFocusedStack != null && lastFocusedStack != this) { // So, why aren't we using prev here??? See the param comment on the method. prev doesn't // represent the last resumed activity. However, the last focus stack does if it isn't null. @@ -2545,7 +2543,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } return true; } else if (mResumedActivity == next && next.isState(RESUMED) - && mStackSupervisor.allResumedActivitiesComplete()) { + && display.allResumedActivitiesComplete()) { // It is possible for the activity to be resumed when we paused back stacks above if the // next activity doesn't have to wait for pause to complete. // So, nothing else to-do except: @@ -2661,7 +2659,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mStackSupervisor.mNoAnimActivities.clear(); - ActivityStack lastStack = mStackSupervisor.getTopDisplayLastFocusedStack(); if (next.attachedToProcess()) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.stopped + " visible=" + next.visible); @@ -2673,10 +2670,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Launcher is already visible in this case. If we don't add it to opening // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation. - final boolean lastActivityTranslucent = lastStack != null - && (lastStack.inMultiWindowMode() - || (lastStack.mLastPausedActivity != null - && !lastStack.mLastPausedActivity.fullscreen)); + final boolean lastActivityTranslucent = lastFocusedStack != null + && (lastFocusedStack.inMultiWindowMode() + || (lastFocusedStack.mLastPausedActivity != null + && !lastFocusedStack.mLastPausedActivity.fullscreen)); // The contained logic must be synchronized, since we are both changing the visibility // and updating the {@link Configuration}. {@link ActivityRecord#setVisibility} will @@ -2693,7 +2690,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai next.startLaunchTickingLocked(); ActivityRecord lastResumedActivity = - lastStack == null ? null :lastStack.mResumedActivity; + lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity; final ActivityState lastState = next.getState(); mService.updateCpuStats(); @@ -2798,8 +2795,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; - } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null - && lastStack.isTopStackOnDisplay()) { + } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null + && lastFocusedStack.isTopStackOnDisplay()) { next.showStartingWindow(null /* prev */, false /* newTask */, false /* taskSwitch */); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index a968ae4e0201..b6863aa89309 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -337,11 +337,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** The current user */ int mCurrentUser; - /** If this is the same as mFocusedStack then the activity on the top of the focused stack has - * been resumed. If stacks are changing position this will hold the old stack until the new - * stack becomes resumed after which it will be set to mFocusedStack. */ - private ActivityStack mLastFocusedStack; - /** List of activities that are waiting for a new activity to become visible before completing * whatever operation they are supposed to do. */ // TODO: Remove mActivitiesWaitingForVisibleActivity list and just remove activity from @@ -692,8 +687,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityDisplay defaultDisplay = getDefaultDisplay(); - mLastFocusedStack = defaultDisplay.getOrCreateStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); + defaultDisplay.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); positionChildAt(defaultDisplay, ActivityDisplay.POSITION_TOP); } @@ -761,43 +755,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return container.getWindowConfiguration().canReceiveKeys() || alwaysFocusable; } - ActivityStack getTopDisplayLastFocusedStack() { - return mLastFocusedStack; - } - boolean isTopDisplayFocusedStack(ActivityStack stack) { return stack != null && stack == getTopDisplayFocusedStack(); } - /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */ - 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 = getNextFocusableStackLocked(focusCandidate, false /* ignoreCurrent */); - if (focusCandidate == null) { - Slog.w(TAG, - "setFocusStackUnchecked: No focusable stack found, focus home as default"); - focusCandidate = getDefaultDisplay().getHomeStack(); - } - } - - final ActivityStack currentFocusedStack = getTopDisplayFocusedStack(); - if (currentFocusedStack != focusCandidate) { - mLastFocusedStack = currentFocusedStack; - // TODO(b/111541062): Update event log to include focus movements on all displays - EventLogTags.writeAmFocusedStack( - mCurrentUser, focusCandidate == null ? -1 : focusCandidate.getStackId(), - mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason); - } - - final ActivityRecord r = topRunningActivityLocked(); - if (mService.isBooting() || !mService.isBooted()) { - if (r != null && r.idle) { - checkFinishBootingLocked(); - } - } - } - void moveRecentsStackToFront(String reason) { final ActivityStack recentsStack = getDefaultDisplay().getStack( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); @@ -1091,28 +1052,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return true; } - boolean allResumedActivitiesComplete() { - for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { - final ActivityDisplay display = mActivityDisplays.get(displayNdx); - for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getChildAt(stackNdx); - if (isTopDisplayFocusedStack(stack)) { - final ActivityRecord r = stack.getResumedActivity(); - if (r != null && !r.isState(RESUMED)) { - return false; - } - } - } - } - // TODO: Not sure if this should check if all Paused are complete too. - final ActivityStack focusedStack = getTopDisplayFocusedStack(); - if (DEBUG_STACK) Slog.d(TAG_STACK, - "allResumedActivitiesComplete: mLastFocusedStack changing from=" - + mLastFocusedStack + " to=" + focusedStack); - mLastFocusedStack = focusedStack; - return true; - } - private boolean allResumedActivitiesVisible() { boolean foundResumed = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { @@ -3673,7 +3612,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (isTopDisplayFocusedStack(stack)) { mService.updateUsageStats(r, true); } - if (allResumedActivitiesComplete()) { + if (stack.getDisplay().allResumedActivitiesComplete()) { ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); mWindowManager.executeAppTransition(); return true; @@ -3984,8 +3923,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D pw.print(prefix); pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack()); pw.print(prefix); - pw.println("mLastFocusedStack=" + mLastFocusedStack); - pw.print(prefix); pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser); pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 0ef2a0a90e13..09064f2fc441 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -91,7 +91,7 @@ option java_package com.android.server.am 30043 am_set_resumed_activity (User|1|5),(Component Name|3),(Reason|3) # Stack focus -30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3) +30044 am_focused_stack (User|1|5),(Display Id|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3) # Running pre boot receiver 30045 am_pre_boot (User|1|5),(Package|3) diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java index 44981b3a90cf..ea90ffd0792f 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java @@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; @@ -52,6 +53,24 @@ public class ActivityDisplayTests extends ActivityTestsBase { setupActivityTaskManagerService(); } + @Test + public void testLastFocusedStackIsUpdatedWhenMovingStack() { + // Create a stack at bottom. + final ActivityDisplay display = mSupervisor.getDefaultDisplay(); + final ActivityStack stack = display.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, !ON_TOP); + final ActivityStack prevFocusedStack = display.getFocusedStack(); + + stack.moveToFront("moveStackToFront"); + // After moving the stack to front, the previous focused should be the last focused. + assertTrue(stack.isFocusedStackOnDisplay()); + assertEquals(prevFocusedStack, display.getLastFocusedStack()); + + stack.moveToBack("moveStackToBack", null /* task */); + // After moving the stack to back, the stack should be the last focused. + assertEquals(stack, display.getLastFocusedStack()); + } + /** * This test simulates the picture-in-picture menu activity launches an activity to fullscreen * stack. The fullscreen stack should be the top focused for resuming correctly. |