From b8f0bb9a382f0f4665853c58560298fd2a742bd9 Mon Sep 17 00:00:00 2001 From: Vladimir Komsiyski Date: Mon, 24 Jul 2023 14:49:18 +0200 Subject: Respect the absence of FLAG_ROTATES_WITH_CONTENT. When creating virtual displays without this flag, they should not rotate when the content changes its requested orientation, but instead should apply letterbox or pillarbox transformation. Bug: 292473307 Test: atest DisplayRotationTests Test: atest LogicalDisplayTest Test: atest DisplayManagerServiceTest Change-Id: Ie12d5e93626ebc298ab71e8634e4e50bb70d49da (cherry picked from commit 19c59050ee91b46db622405d5eef2e89f2367fe1) Merged-In: Ie12d5e93626ebc298ab71e8634e4e50bb70d49da --- core/java/android/view/Display.java | 8 +++++ .../com/android/server/display/LogicalDisplay.java | 3 ++ .../java/com/android/server/wm/DisplayContent.java | 7 +++++ .../com/android/server/wm/DisplayRotation.java | 3 +- .../server/display/DisplayManagerServiceTest.java | 35 ++++++++++++++++++++++ .../android/server/display/LogicalDisplayTest.java | 13 ++++++-- .../android/server/wm/DisplayRotationTests.java | 9 ++++++ 7 files changed, 75 insertions(+), 3 deletions(-) diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 4b96d74b5687..0b2b6ce33666 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -374,6 +374,14 @@ public final class Display { */ public static final int FLAG_REAR = 1 << 13; + /** + * Display flag: Indicates that the orientation of this display is not fixed and is coupled to + * the orientation of its content. + * + * @hide + */ + public static final int FLAG_ROTATES_WITH_CONTENT = 1 << 14; + /** * Display flag: Indicates that the contents of the display should not be scaled * to fit the physical screen dimensions. Used for development only to emulate diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 4edc8bc3eceb..9c271ff54d6b 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -441,6 +441,9 @@ final class LogicalDisplay { if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_ALWAYS_UNLOCKED; } + if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) { + mBaseDisplayInfo.flags |= Display.FLAG_ROTATES_WITH_CONTENT; + } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_TOUCH_FEEDBACK_DISABLED; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 2309e5891a30..e1af16a0f035 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -6492,6 +6492,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return (mDisplayInfo.flags & Display.FLAG_ALWAYS_UNLOCKED) != 0; } + /** + * @return whether the physical display has a fixed orientation and cannot be rotated. + */ + boolean isDisplayOrientationFixed() { + return (mDisplayInfo.flags & Display.FLAG_ROTATES_WITH_CONTENT) == 0; + } + /** * @return whether AOD is showing on this display */ diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index b681c198538f..1cb21bf1b2bd 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -431,7 +431,8 @@ public class DisplayRotation { final boolean isTv = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_LEANBACK); mDefaultFixedToUserRotation = - (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode()) + (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode() + || mDisplayContent.isDisplayOrientationFixed()) // For debug purposes the next line turns this feature off with: // $ adb shell setprop config.override_forced_orient true // $ adb shell wm size reset diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index d16c9c59bb1b..50cf1696ba83 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -476,6 +476,41 @@ public class DisplayManagerServiceTest { assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0); } + @Test + public void testCreateVirtualRotatesWithContent() throws RemoteException { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + registerDefaultDisplays(displayManager); + + // This is effectively the DisplayManager service published to ServiceManager. + DisplayManagerService.BinderService bs = displayManager.new BinderService(); + + String uniqueId = "uniqueId --- Rotates with Content Test"; + int width = 600; + int height = 800; + int dpi = 320; + int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT; + + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( + VIRTUAL_DISPLAY_NAME, width, height, dpi); + builder.setFlags(flags); + builder.setUniqueId(uniqueId); + int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken, + /* projection= */ null, PACKAGE_NAME); + verify(mMockProjectionService, never()).setContentRecordingSession(any(), + nullable(IMediaProjection.class)); + + displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); + + // flush the handler + displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0); + + DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); + assertNotNull(ddi); + assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0); + } + @Test public void testCreateVirtualDisplayOwnFocus() throws RemoteException { DisplayManagerService displayManager = diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java index 20654797a5d2..c0128ae38a28 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java @@ -69,7 +69,6 @@ public class LogicalDisplayTest { mDisplayDeviceInfo.copyFrom(new DisplayDeviceInfo()); mDisplayDeviceInfo.width = DISPLAY_WIDTH; mDisplayDeviceInfo.height = DISPLAY_HEIGHT; - mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; mDisplayDeviceInfo.modeId = MODE_ID; mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, @@ -112,8 +111,18 @@ public class LogicalDisplayTest { mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); - expectedPosition.set(40, -20); DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = DISPLAY_WIDTH; + displayInfo.logicalHeight = DISPLAY_HEIGHT; + // Rotation doesn't matter when the FLAG_ROTATES_WITH_CONTENT is absent. + displayInfo.rotation = Surface.ROTATION_90; + mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo); + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); + + expectedPosition.set(40, -20); + mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; + mLogicalDisplay.updateLocked(mDeviceRepo); displayInfo.logicalWidth = DISPLAY_HEIGHT; displayInfo.logicalHeight = DISPLAY_WIDTH; displayInfo.rotation = Surface.ROTATION_90; diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 2a8f0ffc4d49..e3167c9c9cb9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -1148,6 +1148,15 @@ public class DisplayRotationTests { + " fixed to user rotation.", mTarget.isFixedToUserRotation()); } + @Test + public void testIsFixedToUserRotation_displayContentOrientationFixed() throws Exception { + mBuilder.build(); + when(mMockDisplayContent.isDisplayOrientationFixed()).thenReturn(true); + + assertFalse("Display rotation should respect app requested orientation if" + + " the display has fixed orientation.", mTarget.isFixedToUserRotation()); + } + private void moveTimeForward(long timeMillis) { sCurrentUptimeMillis += timeMillis; sClock.fastForward(timeMillis); -- cgit v1.2.3-59-g8ed1b