diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 46b5f3ab38f9b..977906052ec00 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -1150,8 +1150,9 @@ class RootActivityContainer extends ConfigurationContainer resumedOnDisplay |= result; continue; } - if (topRunningActivity.isState(RESUMED)) { - // Kick off any lingering app transitions form the MoveTaskToFront operation. + if (display.isTopStack(stack) && topRunningActivity.isState(RESUMED)) { + // Kick off any lingering app transitions form the MoveTaskToFront operation, + // but only consider the top task and stack on that display. stack.executeAppTransition(targetOptions); } else { resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 94def2bb78465..f58559f124381 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -62,6 +62,7 @@ import android.util.Pair; import androidx.test.filters.MediumTest; import com.android.internal.app.ResolverActivity; +import com.android.server.wm.ActivityStack.ActivityState; import org.junit.Before; import org.junit.Test; @@ -394,6 +395,52 @@ public class RootActivityContainerTests extends ActivityTestsBase { eq(activity), eq(null /* targetOptions */)); } + /** + * Verify that a lingering transition is being executed in case the activity to be resumed is + * already resumed + */ + @Test + public void testResumeActivityLingeringTransition() { + // Create a stack at top. + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); + final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, false /* onTop */)); + final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); + final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); + activity.setState(ActivityState.RESUMED, "test"); + + // Assume the stack is at the topmost position + assertTrue(targetStack.isTopStackOnDisplay()); + + // Use the stack as target to resume. + mRootActivityContainer.resumeFocusedStacksTopActivities(); + + // Verify the lingering app transition is being executed because it's already resumed + verify(targetStack, times(1)).executeAppTransition(any()); + } + + @Test + public void testResumeActivityLingeringTransition_notExecuted() { + // Create a stack at bottom. + final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay(); + final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, false /* onTop */)); + final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); + final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); + activity.setState(ActivityState.RESUMED, "test"); + display.positionChildAtBottom(targetStack); + + // Assume the stack is at the topmost position + assertFalse(targetStack.isTopStackOnDisplay()); + doReturn(targetStack).when(mRootActivityContainer).getTopDisplayFocusedStack(); + + // Use the stack as target to resume. + mRootActivityContainer.resumeFocusedStacksTopActivities(); + + // Verify the lingering app transition is being executed because it's already resumed + verify(targetStack, never()).executeAppTransition(any()); + } + /** * Tests that home activities can be started on the displays that supports system decorations. */