diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 2ef98b59768f5..f1b110de37aca 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1513,6 +1513,13 @@ class DisplayContent extends WindowContainer { state.mIsTransforming = false; if (applyDisplayRotation != null) { applyDisplayRotation.run(); - } else { - // The display will not rotate to the rotation of this container, let's cancel them. - for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { - state.mAssociatedTokens.get(i).cancelFixedRotationTransform(); - } } // The state is cleared at the end, because it is used to indicate that other windows can // use seamless rotation when applying rotation to display. @@ -634,11 +629,15 @@ class WindowToken extends WindowContainer { final WindowToken token = state.mAssociatedTokens.get(i); token.mFixedRotationTransformState = null; token.notifyFixedRotationTransform(false /* enabled */); + if (applyDisplayRotation == null) { + // Notify cancellation because the display does not change rotation. + token.cancelFixedRotationTransform(); + } } } /** Notifies application side to enable or disable the rotation adjustment of display info. */ - private void notifyFixedRotationTransform(boolean enabled) { + void notifyFixedRotationTransform(boolean enabled) { FixedRotationAdjustments adjustments = null; // A token may contain windows of the same processes or different processes. The list is // used to avoid sending the same adjustments to a process multiple times. @@ -682,7 +681,6 @@ class WindowToken extends WindowContainer { // The window may be detached or detaching. return; } - notifyFixedRotationTransform(false /* enabled */); final int originalRotation = getWindowConfiguration().getRotation(); onConfigurationChanged(parent.getConfiguration()); onCancelFixedRotationTransform(originalRotation); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index d99606b704e48..b28220585c5c5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -88,6 +88,7 @@ import static org.mockito.Mockito.doCallRealMethod; import android.annotation.SuppressLint; import android.app.ActivityTaskManager; import android.app.WindowConfiguration; +import android.app.servertransaction.FixedRotationAdjustmentsItem; import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.Region; @@ -1345,6 +1346,36 @@ public class DisplayContentTests extends WindowTestsBase { assertFalse(recentsActivity.hasFixedRotationTransform()); } + @Test + public void testClearIntermediateFixedRotationAdjustments() throws RemoteException { + final ActivityRecord activity = new ActivityTestsBase.StackBuilder(mWm.mRoot) + .setDisplay(mDisplayContent).build().getTopMostActivity(); + mDisplayContent.setFixedRotationLaunchingApp(activity, + (mDisplayContent.getRotation() + 1) % 4); + // Create a window so FixedRotationAdjustmentsItem can be sent. + createWindow(null, TYPE_APPLICATION_STARTING, activity, "AppWin"); + final ActivityRecord activity2 = new ActivityTestsBase.StackBuilder(mWm.mRoot) + .setDisplay(mDisplayContent).build().getTopMostActivity(); + activity2.setVisible(false); + clearInvocations(mWm.mAtmService.getLifecycleManager()); + // The first activity has applied fixed rotation but the second activity becomes the top + // before the transition is done and it has the same rotation as display, so the dispatched + // rotation adjustment of first activity must be cleared. + mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(activity2, + false /* checkOpening */); + + final ArgumentCaptor adjustmentsCaptor = + ArgumentCaptor.forClass(FixedRotationAdjustmentsItem.class); + verify(mWm.mAtmService.getLifecycleManager(), atLeastOnce()).scheduleTransaction( + eq(activity.app.getThread()), adjustmentsCaptor.capture()); + // The transformation is kept for animation in real case. + assertTrue(activity.hasFixedRotationTransform()); + final FixedRotationAdjustmentsItem clearAdjustments = FixedRotationAdjustmentsItem.obtain( + activity.token, null /* fixedRotationAdjustments */); + // The captor may match other items. The first one must be the item to clear adjustments. + assertEquals(clearAdjustments, adjustmentsCaptor.getAllValues().get(0)); + } + @Test public void testRemoteRotation() { DisplayContent dc = createNewDisplay();