From 8b5a441c4863dbd8a444b7e8551972f14e352b7a Mon Sep 17 00:00:00 2001 From: Issei Suzuki Date: Tue, 15 Jun 2021 14:00:37 +0200 Subject: [PATCH] Avoid applying closing animation for invisible activity. In case an invisible activity requests to become invisible, we don't apply app transition animation on it. We already have a logic to prevent this in ActivityRecord#setVisibility, but it cannot handle the following scenario. 1. Activity is initially invisible. 2. Activity requests to become visible. 3. Activity requests to become invisible (so this override the second step). So this change fills the gap. Test: atest ActivityRecordTests Bug: 184107777 Change-Id: I50a0f3a8ea49beb5c86fff0f6bb8c005db581a6d --- .../com/android/server/wm/ActivityRecord.java | 2 +- .../server/wm/ActivityRecordTests.java | 79 +++++++++++++++++++ .../android/server/wm/WindowTestsBase.java | 13 ++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index cb3afe4cb4170..bbd15121a2d5b 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -4685,7 +4685,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (visible) { displayContent.mOpeningApps.add(this); mEnteringAnimation = true; - } else { + } else if (mVisible) { displayContent.mClosingApps.add(this); mEnteringAnimation = false; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index b03a66ca22cad..0409a8c913e77 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2732,6 +2732,85 @@ public class ActivityRecordTests extends WindowTestsBase { > activity.getConfiguration().windowConfiguration.getAppBounds().height()); } + @Test + public void testSetVisibility_visibleToVisible() { + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setCreateTask(true).build(); + // By default, activity is visible. + assertTrue(activity.isVisible()); + assertTrue(activity.mVisibleRequested); + assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); + assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + + // Request the activity to be visible. Although the activity is already visible, app + // transition animation should be applied on this activity. This might be unnecessary, but + // until we verify no logic relies on this behavior, we'll keep this as is. + activity.setVisibility(true); + assertTrue(activity.isVisible()); + assertTrue(activity.mVisibleRequested); + assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); + assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + } + + @Test + public void testSetVisibility_visibleToInvisible() { + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setCreateTask(true).build(); + // By default, activity is visible. + assertTrue(activity.isVisible()); + assertTrue(activity.mVisibleRequested); + assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); + assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + + // Request the activity to be invisible. Since the visibility changes, app transition + // animation should be applied on this activity. + activity.setVisibility(false); + assertTrue(activity.isVisible()); + assertFalse(activity.mVisibleRequested); + assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity)); + assertTrue(activity.mDisplayContent.mClosingApps.contains(activity)); + } + + @Test + public void testSetVisibility_invisibleToVisible() { + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setCreateTask(true).setVisible(false).build(); + // Activiby is invisible. However ATMS requests it to become visible, since this is a top + // activity. + assertFalse(activity.isVisible()); + assertTrue(activity.mVisibleRequested); + assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); + assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + + // Request the activity to be visible. Since the visibility changes, app transition + // animation should be applied on this activity. + activity.setVisibility(true); + assertFalse(activity.isVisible()); + assertTrue(activity.mVisibleRequested); + assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); + assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + } + + @Test + public void testSetVisibility_invisibleToInvisible() { + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setCreateTask(true).setVisible(false).build(); + // Activiby is invisible. However ATMS requests it to become visible, since this is a top + // activity. + assertFalse(activity.isVisible()); + assertTrue(activity.mVisibleRequested); + assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); + assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + + // Request the activity to be invisible. Since the activity is already invisible, no app + // transition should be applied on this activity. + activity.setVisibility(false); + assertFalse(activity.isVisible()); + assertFalse(activity.mVisibleRequested); + assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity)); + assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); + } + private void assertHasStartingWindow(ActivityRecord atoken) { assertNotNull(atoken.mStartingSurface); assertNotNull(atoken.mStartingData); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 111449d2c1003..588089996d6c8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -805,6 +805,7 @@ class WindowTestsBase extends SystemServiceTestsBase { private Bundle mIntentExtras; private boolean mOnTop = false; private ActivityInfo.WindowLayout mWindowLayout; + private boolean mVisible = true; ActivityBuilder(ActivityTaskManagerService service) { mService = service; @@ -930,6 +931,11 @@ class WindowTestsBase extends SystemServiceTestsBase { return this; } + ActivityBuilder setVisible(boolean visible) { + mVisible = visible; + return this; + } + ActivityRecord build() { SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock); try { @@ -1012,9 +1018,10 @@ class WindowTestsBase extends SystemServiceTestsBase { // root tasks (e.g. home root task). mTask.moveToFront("createActivity"); } - // Make visible by default... - activity.mVisibleRequested = true; - activity.setVisible(true); + if (mVisible) { + activity.mVisibleRequested = true; + activity.setVisible(true); + } } final WindowProcessController wpc;