diff options
4 files changed, 93 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 00b2a58dbe8f..7f03778ab1c7 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -819,6 +819,22 @@ class ActivityStack extends Task { mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); mRootWindowContainer.resumeFocusedStacksTopActivities(); + + final boolean pinnedToFullscreen = currentMode == WINDOWING_MODE_PINNED + && windowingMode == WINDOWING_MODE_FULLSCREEN; + if (pinnedToFullscreen && topActivity != null && !isForceHidden()) { + mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(true); + try { + // Report orientation as soon as possible so that the display can freeze earlier if + // the display orientation will be changed. Because the surface bounds of activity + // may have been set to fullscreen but the activity hasn't redrawn its content yet, + // the rotation animation needs to capture snapshot earlier to avoid animating from + // an intermediate state. + topActivity.reportDescendantOrientationChangeIfNeeded(); + } finally { + mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(false); + } + } } @Override diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 8903776469db..59181a64f423 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1481,6 +1481,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // has it own policy for bounds, the activity bounds based on parent is unknown. return false; } + if (mPinnedStackControllerLocked.isPipActiveOrWindowingModeChanging()) { + // Use normal rotation animation because seamless PiP rotation is not supported yet. + return false; + } setFixedRotationLaunchingApp(r, rotation); return true; diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index 56312aa1b0b8..52ada472f0aa 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -23,7 +23,6 @@ import android.app.RemoteAction; import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.content.res.Resources; -import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.util.DisplayMetrics; @@ -33,8 +32,6 @@ import android.view.DisplayInfo; import android.view.IPinnedStackController; import android.view.IPinnedStackListener; -import com.android.server.UiThread; - import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -61,7 +58,6 @@ class PinnedStackController { private final WindowManagerService mService; private final DisplayContent mDisplayContent; - private final Handler mHandler = UiThread.getHandler(); private IPinnedStackListener mPinnedStackListener; private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler = @@ -69,6 +65,9 @@ class PinnedStackController { private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback(); + /** Whether the PiP is entering or leaving. */ + private boolean mIsPipWindowingModeChanging; + private boolean mIsImeShowing; private int mImeHeight; @@ -161,6 +160,20 @@ class PinnedStackController { Float.compare(aspectRatio, mMaxAspectRatio) <= 0; } + /** Returns {@code true} if the PiP is on screen or is changing windowing mode. */ + boolean isPipActiveOrWindowingModeChanging() { + if (mIsPipWindowingModeChanging) { + return true; + } + final Task pinnedTask = mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask(); + return pinnedTask != null && pinnedTask.hasChild(); + } + + /** Sets whether a visible stack is changing from or to pinned mode. */ + void setPipWindowingModeChanging(boolean isPipWindowingModeChanging) { + mIsPipWindowingModeChanging = isPipWindowingModeChanging; + } + /** * Activity is hidden (either stopped or removed), resets the last saved snap fraction * so that the default bounds will be returned for the next session. 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 7197ce9c22aa..4ad7dff87072 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -16,7 +16,10 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -73,6 +76,8 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import android.annotation.SuppressLint; @@ -1168,6 +1173,57 @@ public class DisplayContentTests extends WindowTestsBase { } @Test + public void testNoFixedRotationWithPip() { + mWm.mIsFixedRotationTransformEnabled = true; + // Make resume-top really update the activity state. + doReturn(false).when(mWm.mAtmService).isBooting(); + doReturn(true).when(mWm.mAtmService).isBooted(); + // Speed up the test by a few seconds. + mWm.mAtmService.deferWindowLayout(); + doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); + + final DisplayContent displayContent = mWm.mRoot.getDefaultDisplay(); + final Configuration displayConfig = displayContent.getConfiguration(); + final ActivityRecord pinnedActivity = createActivityRecord(displayContent, + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); + final Task pinnedTask = pinnedActivity.getRootTask(); + final ActivityRecord homeActivity = WindowTestUtils.createTestActivityRecord( + displayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()); + if (displayConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { + homeActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT); + pinnedActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); + } else { + homeActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); + pinnedActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT); + } + final int homeConfigOrientation = homeActivity.getRequestedConfigurationOrientation(); + final int pinnedConfigOrientation = pinnedActivity.getRequestedConfigurationOrientation(); + + assertEquals(homeConfigOrientation, displayConfig.orientation); + + clearInvocations(mWm); + // Leave PiP to fullscreen. The orientation can be updated from + // ActivityRecord#reportDescendantOrientationChangeIfNeeded. + pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + homeActivity.setState(ActivityStack.ActivityState.STOPPED, "test"); + + assertFalse(displayContent.hasTopFixedRotationLaunchingApp()); + verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); + assertEquals(pinnedConfigOrientation, displayConfig.orientation); + assertFalse(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging()); + + clearInvocations(mWm); + // Enter PiP from fullscreen. The orientation can be updated from + // ensure-visibility/resume-focused-stack -> ActivityRecord#makeActiveIfNeeded -> resume. + pinnedTask.setWindowingMode(WINDOWING_MODE_PINNED); + + assertFalse(displayContent.hasTopFixedRotationLaunchingApp()); + verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); + assertEquals(homeConfigOrientation, displayConfig.orientation); + assertTrue(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging()); + } + + @Test public void testRemoteRotation() { DisplayContent dc = createNewDisplay(); |