diff options
7 files changed, 100 insertions, 7 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index e817dd47e756..5b3a2fee4dd6 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -1267,6 +1267,15 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> positionChildAt(stack, Math.max(0, insertIndex)); } + void ensureActivitiesVisible(ActivityRecord starting, int configChanges, + boolean preserveWindows, boolean notifyClients) { + for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = getChildAt(stackNdx); + stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows, + notifyClients); + } + } + void moveHomeStackToFront(String reason) { if (mHomeStack != null) { mHomeStack.moveToFront(reason); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 38e8785b0692..ad76af695df3 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3401,6 +3401,16 @@ final class ActivityRecord extends ConfigurationContainer { stack.checkKeyguardVisibility(this, true /* shouldBeVisible */, true /* isTop */); } + /** + * Check if this activity is able to resume. For pre-Q apps, only the topmost activities of each + * process are allowed to be resumed. + * + * @return true if this activity can be resumed. + */ + boolean canResumeByCompat() { + return app == null || app.updateTopResumingActivityInProcessIfNeeded(this); + } + boolean getTurnScreenOnFlag() { return mTurnScreenOn; } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 16c44aa3220f..6fc201448f33 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2597,6 +2597,10 @@ class ActivityStack extends ConfigurationContainer { return false; } + if (!next.canResumeByCompat()) { + return false; + } + // If we are sleeping, and there is no resumed activity, and the top // activity is paused, well that is the state we want. if (shouldSleepOrShutDownActivities() diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index c8a150beecfa..c0fe6e937422 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -720,6 +720,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { r.setProcess(proc); + // Ensure activity is allowed to be resumed after process has set. + if (andResume && !r.canResumeByCompat()) { + andResume = false; + } + if (getKeyguardController().isKeyguardLocked()) { r.notifyUnknownVisibilityLaunched(); } diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 624fdc2e168e..ecab1f14e5e0 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -777,11 +777,8 @@ class RootActivityContainer extends ConfigurationContainer // First the front stacks. In case any are not fullscreen and are in front of home. 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); - stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows, - notifyClients); - } + display.ensureActivitiesVisible(starting, configChanges, preserveWindows, + notifyClients); } } finally { mStackSupervisor.getKeyguardController().endActivityVisibilityUpdate(); diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java index dd94af657039..4ff552ec3c91 100644 --- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java +++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java @@ -22,6 +22,8 @@ import static android.view.PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW; import static android.view.PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW; import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; + import android.graphics.Rect; import android.graphics.Region; import android.hardware.input.InputManager; @@ -86,6 +88,16 @@ public class TaskTapPointerEventListener implements PointerEventListener { if (parent != null && parent.getTopChild() != mDisplayContent) { parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent, true /* includingParents */); + // For compatibility, only the topmost activity is allowed to be resumed for + // pre-Q app. Ensure the topmost activities are resumed whenever a display is + // moved to top. + // TODO(b/123761773): Investigate whether we can move this into + // RootActivityContainer#updateTopResumedActivityIfNeeded(). Currently, it is + // risky to do so because it seems possible to resume activities as part of a + // larger transaction and it's too early to resume based on current order + // when performing updateTopResumedActivityIfNeeded(). + mDisplayContent.mAcitvityDisplay.ensureActivitiesVisible(null /* starting */, + 0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */); } } }; diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 37e2200ab68e..0fb900a6eaf4 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static android.os.Build.VERSION_CODES.Q; import static android.view.Display.INVALID_DISPLAY; import static com.android.server.am.ActivityManagerService.MY_PID; @@ -32,11 +33,11 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFI import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.ActivityTaskManagerService - .INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS; +import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS; import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; +import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityThread; import android.app.IApplicationThread; @@ -155,6 +156,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio private final ArrayList<ActivityRecord> mActivities = new ArrayList<>(); // any tasks this process had run root activities in private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<>(); + // The most recent top-most activity that was resumed in the process for pre-Q app. + private ActivityRecord mPreQTopResumedActivity = null; // Last configuration that was reported to the process. private final Configuration mLastReportedConfiguration; @@ -462,6 +465,59 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } + /** + * Update the top resuming activity in process for pre-Q apps, only the top-most visible + * activities are allowed to be resumed per process. + * @return {@code true} if the activity is allowed to be resumed by compatibility + * restrictions, which the activity was the topmost visible activity in process or the app is + * targeting after Q. + */ + boolean updateTopResumingActivityInProcessIfNeeded(@NonNull ActivityRecord activity) { + if (mInfo.targetSdkVersion >= Q || mPreQTopResumedActivity == activity) { + return true; + } + + final ActivityDisplay display = activity.getDisplay(); + if (display == null) { + // No need to update if the activity hasn't attach to any display. + return false; + } + + boolean canUpdate = false; + final ActivityDisplay topDisplay = + mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null; + // Update the topmost activity if current top activity was not on any display or no + // longer visible. + if (topDisplay == null || !mPreQTopResumedActivity.visible) { + canUpdate = true; + } + + // Update the topmost activity if the current top activity wasn't on top of the other one. + if (!canUpdate && topDisplay.mDisplayContent.compareTo(display.mDisplayContent) < 0) { + canUpdate = true; + } + + // Compare the z-order of ActivityStacks if both activities landed on same display. + if (display == topDisplay + && mPreQTopResumedActivity.getActivityStack().mTaskStack.compareTo( + activity.getActivityStack().mTaskStack) <= 0) { + canUpdate = true; + } + + if (canUpdate) { + // Make sure the previous top activity in the process no longer be resumed. + if (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isState(RESUMED)) { + final ActivityStack stack = mPreQTopResumedActivity.getActivityStack(); + if (stack != null) { + stack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, + null /* resuming */, false /* pauseImmediately */); + } + } + mPreQTopResumedActivity = activity; + } + return canUpdate; + } + public void stopFreezingActivities() { synchronized (mAtm.mGlobalLock) { int i = mActivities.size(); |