From 34acc1459b57870c155e5ff5658a7f158e432223 Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Tue, 24 Sep 2019 15:35:50 -0700 Subject: [PATCH] Simplify finishing flow for activities waiting for next one to resume The finishing code used to have custom logic that handled the case when an activity is paused in focused stack and needs to be added to the list of finishing activities instead of being destroyed immediately. This is needed to make sure that the next activity is resumed first before we stop and destroy the finishing one. It will eventually be destroyed when the next activity reports idle. This CLs instead unconditionally marks the activity as finishing and invokes RootActivityContainer#resumeFocusedStacksTopActivities(). If any activity is made resumed as a result of this call - then all we need to do is to wait for it to report idle. If no activity was made resumed - it means that we can go ahead and request destruction immediately. Bug: 137329632 Bug: 142125019 Test: WM CTS Change-Id: I28c08f06ce74502053d141a21ae81e1b99df7228 --- .../com/android/server/wm/ActivityRecord.java | 37 ++++++++++++------- .../server/wm/TestActivityDisplay.java | 7 ++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c54ccd4d68447..7bbdcb62ccbc6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1858,25 +1858,27 @@ final class ActivityRecord extends ConfigurationContainer { // implied that the current finishing activity should be added into stopping list rather // than destroy immediately. final boolean isNextNotYetVisible = next != null && (!next.nowVisible || !next.visible); - final ActivityStack stack = getActivityStack(); - final boolean notFocusedStack = stack != mRootActivityContainer.getTopDisplayFocusedStack(); + final boolean notGlobalFocusedStack = + getActivityStack() != mRootActivityContainer.getTopDisplayFocusedStack(); if (isVisible && isNextNotYetVisible) { + // Add this activity to the list of stopping activities. It will be processed and + // destroyed when the next activity reports idle. addToStopping(false /* scheduleIdle */, false /* idleDelayed */, "completeFinishing"); - if (DEBUG_STATES) { - Slog.v(TAG_STATES, "Moving to STOPPING: " + this + " (finish requested)"); - } setState(STOPPING, "completeFinishing"); - if (notFocusedStack) { + if (notGlobalFocusedStack) { + // Ensuring visibility and configuration only for non-focused stacks since this + // method call is relatively expensive and not necessary for focused stacks. mRootActivityContainer.ensureVisibilityAndConfig(next, getDisplayId(), false /* markFrozenIfConfigChanged */, true /* deferResume */); } - } else if (isVisible && isState(PAUSED) && getActivityStack().isFocusedStackOnDisplay() - && !inPinnedWindowingMode()) { - // TODO(b/137329632): Currently non-focused stack is handled differently. - addToFinishingAndWaitForIdle(); + } else if (addToFinishingAndWaitForIdle()) { + // We added this activity to the finishing list and something else is becoming resumed. + // The activity will complete finishing when the next activity reports idle. No need to + // do anything else here. } else { - // Not waiting for the next one to become visible - finish right away. + // Not waiting for the next one to become visible, and nothing else will be resumed in + // place of this activity - requesting destruction right away. activityRemoved = destroyIfPossible(reason); } @@ -1933,13 +1935,20 @@ final class ActivityRecord extends ConfigurationContainer { return activityRemoved; } + /** + * Add this activity to the list of finishing and trigger resuming of activities in focused + * stacks. + * @return {@code true} if some other activity is being resumed as a result of this call. + */ @VisibleForTesting - void addToFinishingAndWaitForIdle() { + boolean addToFinishingAndWaitForIdle() { if (DEBUG_STATES) Slog.v(TAG, "Enqueueing pending finish: " + this); setState(FINISHING, "addToFinishingAndWaitForIdle"); - mStackSupervisor.mFinishingActivities.add(this); + if (!mStackSupervisor.mFinishingActivities.contains(this)) { + mStackSupervisor.mFinishingActivities.add(this); + } resumeKeyDispatchingLocked(); - mRootActivityContainer.resumeFocusedStacksTopActivities(); + return mRootActivityContainer.resumeFocusedStacksTopActivities(); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java index 778f0ca3c7826..9c3ff654ddf01 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java @@ -22,8 +22,11 @@ import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static org.mockito.ArgumentMatchers.any; + import android.hardware.display.DisplayManagerGlobal; import android.view.Display; import android.view.DisplayInfo; @@ -85,6 +88,10 @@ class TestActivityDisplay extends ActivityDisplay { displayRotation.setRotation(rotation); return true; }).when(displayRotation).updateRotationUnchecked(anyBoolean()); + + final InputMonitor inputMonitor = mDisplayContent.getInputMonitor(); + spyOn(inputMonitor); + doNothing().when(inputMonitor).resumeDispatchingLw(any()); } @SuppressWarnings("TypeParameterUnusedInFormals")