summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java14
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java19
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java3
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java3
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java9
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig11
-rw-r--r--services/core/java/com/android/server/wm/ContentRecorder.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java31
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java59
10 files changed, 141 insertions, 18 deletions
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index a7748f4fae98..0ebb2a30685c 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -158,8 +158,6 @@ abstract class DisplayDevice {
@Nullable
public Point getDisplaySurfaceDefaultSizeLocked() {
DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked();
- final boolean isRotated = mCurrentOrientation == ROTATION_90
- || mCurrentOrientation == ROTATION_270;
var width = displayDeviceInfo.width;
var height = displayDeviceInfo.height;
if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.yDpi > 0
@@ -170,7 +168,7 @@ abstract class DisplayDevice {
width = (int) (width * displayDeviceInfo.yDpi / displayDeviceInfo.xDpi + 0.5);
}
}
- return isRotated ? new Point(height, width) : new Point(width, height);
+ return isRotatedLocked() ? new Point(height, width) : new Point(width, height);
}
/**
@@ -394,8 +392,7 @@ abstract class DisplayDevice {
viewport.physicalFrame.setEmpty();
}
- boolean isRotated = (mCurrentOrientation == Surface.ROTATION_90
- || mCurrentOrientation == ROTATION_270);
+ final boolean isRotated = isRotatedLocked();
DisplayDeviceInfo info = getDisplayDeviceInfoLocked();
viewport.deviceWidth = isRotated ? info.height : info.width;
viewport.deviceHeight = isRotated ? info.width : info.height;
@@ -425,6 +422,13 @@ abstract class DisplayDevice {
pw.println("mCurrentSurface=" + mCurrentSurface);
}
+ /**
+ * @return whether the orientation is {@link ROTATION_90} or {@link ROTATION_270}.
+ */
+ boolean isRotatedLocked() {
+ return mCurrentOrientation == ROTATION_90 || mCurrentOrientation == ROTATION_270;
+ }
+
private DisplayDeviceConfig loadDisplayDeviceConfig() {
return DisplayDeviceConfig.create(mContext, /* useConfigXml= */ false,
mDisplayAdapter.getFeatureFlags());
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 5eaaf3504e85..22e4bc502131 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -204,6 +204,13 @@ final class LogicalDisplay {
new SparseArray<>();
/**
+ * If enabled, will not check for {@link Display#FLAG_ROTATES_WITH_CONTENT} in LogicalDisplay
+ * and simply use the {@link DisplayInfo#rotation} supplied by WindowManager via
+ * {@link #setDisplayInfoOverrideFromWindowManagerLocked}
+ */
+ private boolean mAlwaysRotateDisplayDeviceEnabled;
+
+ /**
* If the aspect ratio of the resolution of the display does not match the physical aspect
* ratio of the display, then without this feature enabled, picture would appear stretched to
* the user. This is because applications assume that they are rendered on square pixels
@@ -220,11 +227,11 @@ final class LogicalDisplay {
private final boolean mIsAnisotropyCorrectionEnabled;
LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
- this(displayId, layerStack, primaryDisplayDevice, false);
+ this(displayId, layerStack, primaryDisplayDevice, false, false);
}
LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice,
- boolean isAnisotropyCorrectionEnabled) {
+ boolean isAnisotropyCorrectionEnabled, boolean isAlwaysRotateDisplayDeviceEnabled) {
mDisplayId = displayId;
mLayerStack = layerStack;
mPrimaryDisplayDevice = primaryDisplayDevice;
@@ -236,6 +243,7 @@ final class LogicalDisplay {
mPowerThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID;
mBaseDisplayInfo.thermalBrightnessThrottlingDataId = mThermalBrightnessThrottlingDataId;
mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled;
+ mAlwaysRotateDisplayDeviceEnabled = isAlwaysRotateDisplayDeviceEnabled;
}
public void setDevicePositionLocked(int position) {
@@ -672,7 +680,12 @@ final class LogicalDisplay {
// The orientation specifies how the physical coordinate system of the display
// is rotated when the contents of the logical display are rendered.
int orientation = Surface.ROTATION_0;
- if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
+
+ // FLAG_ROTATES_WITH_CONTENT is now handled in DisplayContent. When the flag
+ // mAlwaysRotateDisplayDeviceEnabled is removed, we should also remove this check for
+ // ROTATES_WITH_CONTENT here and always set the orientation.
+ if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0
+ || mAlwaysRotateDisplayDeviceEnabled) {
orientation = displayInfo.rotation;
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index e092fdae7cc7..21f90d4aeb94 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -1152,7 +1152,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice device, int displayId) {
final int layerStack = assignLayerStackLocked(displayId);
final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device,
- mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled());
+ mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled(),
+ mFlags.isAlwaysRotateDisplayDeviceEnabled());
display.updateLocked(mDisplayDeviceRepo);
final DisplayInfo info = display.getDisplayInfoLocked();
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index ec5ad7de11b3..bcdb442c3ad3 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -366,7 +366,8 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
if (mSurface == null) {
return null;
}
- return mSurface.getDefaultSize();
+ final Point surfaceSize = mSurface.getDefaultSize();
+ return isRotatedLocked() ? new Point(surfaceSize.y, surfaceSize.x) : surfaceSize;
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 15ee9372b46a..5f455db39dd4 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -116,6 +116,10 @@ public class DisplayManagerFlags {
Flags.FLAG_FAST_HDR_TRANSITIONS,
Flags::fastHdrTransitions);
+ private final FlagState mAlwaysRotateDisplayDevice = new FlagState(
+ Flags.FLAG_ALWAYS_ROTATE_DISPLAY_DEVICE,
+ Flags::alwaysRotateDisplayDevice);
+
private final FlagState mRefreshRateVotingTelemetry = new FlagState(
Flags.FLAG_REFRESH_RATE_VOTING_TELEMETRY,
Flags::refreshRateVotingTelemetry
@@ -260,6 +264,10 @@ public class DisplayManagerFlags {
return mFastHdrTransitions.isEnabled();
}
+ public boolean isAlwaysRotateDisplayDeviceEnabled() {
+ return mAlwaysRotateDisplayDevice.isEnabled();
+ }
+
public boolean isRefreshRateVotingTelemetryEnabled() {
return mRefreshRateVotingTelemetry.isEnabled();
}
@@ -298,6 +306,7 @@ public class DisplayManagerFlags {
pw.println(" " + mBrightnessWearBedtimeModeClamperFlagState);
pw.println(" " + mAutoBrightnessModesFlagState);
pw.println(" " + mFastHdrTransitions);
+ pw.println(" " + mAlwaysRotateDisplayDevice);
pw.println(" " + mRefreshRateVotingTelemetry);
pw.println(" " + mPixelAnisotropyCorrectionEnabled);
pw.println(" " + mSensorBasedBrightnessThrottling);
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 9bf36e4e605f..d2909b898704 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -178,6 +178,17 @@ flag {
}
flag {
+ name: "always_rotate_display_device"
+ namespace: "display_manager"
+ description: "Use rotation from WindowManager no matter whether FLAG_ROTATES_WITH_CONTENT is set or not"
+ bug: "302326003"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "refresh_rate_voting_telemetry"
namespace: "display_manager"
description: "Feature flag for enabling telemetry for refresh rate voting in DisplayManager"
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index b616d24cfebb..802051660c0e 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -157,6 +157,10 @@ final class ContentRecorder implements WindowContainerListener {
}
}
+ void onMirrorOutputSurfaceOrientationChanged() {
+ onConfigurationChanged(mLastOrientation, mLastWindowingMode);
+ }
+
/**
* Handle a configuration change on the display content, and resize recording if needed.
* @param lastOrientation the prior orientation of the configuration
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 837d08b33756..dc643453c8dd 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6835,6 +6835,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mContentRecorder;
}
+ void onMirrorOutputSurfaceOrientationChanged() {
+ if (mContentRecorder != null) {
+ mContentRecorder.onMirrorOutputSurfaceOrientationChanged();
+ }
+ }
+
/**
* Pause the recording session.
*/
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 384b91a07d4e..4a97128c27b6 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -19,6 +19,8 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.Display.TYPE_EXTERNAL;
+import static android.view.Display.TYPE_OVERLAY;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
@@ -915,6 +917,11 @@ public class DisplayRotation {
+ " for " + mDisplayContent);
userRotation = Surface.ROTATION_0;
}
+ final int userRotationOverride = getUserRotationOverride();
+ if (userRotationOverride != 0) {
+ userRotationMode = WindowManagerPolicy.USER_ROTATION_LOCKED;
+ userRotation = userRotationOverride;
+ }
mUserRotationMode = userRotationMode;
mUserRotation = userRotation;
}
@@ -965,6 +972,13 @@ public class DisplayRotation {
if (changed) {
mService.updateRotation(false /* alwaysSendConfiguration */,
false /* forceRelayout */);
+ // ContentRecorder.onConfigurationChanged and Device.setProjectionLocked are called
+ // during updateRotation above. But onConfigurationChanged is called before
+ // Device.setProjectionLocked, which means that the onConfigurationChanged will
+ // not have the new rotation when it calls getDisplaySurfaceDefaultSize.
+ // To make sure that mirroring takes the new rotation of the output surface
+ // into account we need to call onConfigurationChanged again.
+ mDisplayContent.onMirrorOutputSurfaceOrientationChanged();
}
}
@@ -1780,6 +1794,23 @@ public class DisplayRotation {
}
}
+ @Surface.Rotation
+ private int getUserRotationOverride() {
+ final int userRotationOverride = SystemProperties.getInt("persist.demo.userrotation",
+ Surface.ROTATION_0);
+ if (userRotationOverride == Surface.ROTATION_0) {
+ return userRotationOverride;
+ }
+
+ final var display = mDisplayContent.mDisplay;
+ if (display.getType() == TYPE_EXTERNAL || display.getType() == TYPE_OVERLAY) {
+ // TODO b/329442350 add chromecast virtual displays here
+ return userRotationOverride;
+ }
+
+ return Surface.ROTATION_0;
+ }
+
@VisibleForTesting
long uptimeMillis() {
return SystemClock.uptimeMillis();
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 549f0d74b67b..e798aa20f4bf 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -107,8 +107,7 @@ public class LogicalDisplayTest {
@Test
public void testLetterbox() {
- mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
- /*isAnisotropyCorrectionEnabled=*/ false);
+ mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice);
mDisplayDeviceInfo.xDpi = 0.5f;
mDisplayDeviceInfo.yDpi = 1.0f;
@@ -146,7 +145,8 @@ public class LogicalDisplayTest {
@Test
public void testNoLetterbox_anisotropyCorrection() {
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
- /*isAnisotropyCorrectionEnabled=*/ true);
+ /*isAnisotropyCorrectionEnabled=*/ true,
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
// In case of Anisotropy of pixels, then the content should be rescaled so it would adjust
// to using the whole screen. This is because display will rescale it back to fill the
@@ -173,7 +173,8 @@ public class LogicalDisplayTest {
@Test
public void testLetterbox_anisotropyCorrectionYDpi() {
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
- /*isAnisotropyCorrectionEnabled=*/ true);
+ /*isAnisotropyCorrectionEnabled=*/ true,
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.logicalWidth = DISPLAY_WIDTH;
@@ -191,8 +192,7 @@ public class LogicalDisplayTest {
@Test
public void testPillarbox() {
- mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
- /*isAnisotropyCorrectionEnabled=*/ false);
+ mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice);
mDisplayDeviceInfo.xDpi = 0.5f;
mDisplayDeviceInfo.yDpi = 1.0f;
@@ -230,7 +230,8 @@ public class LogicalDisplayTest {
@Test
public void testPillarbox_anisotropyCorrection() {
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
- /*isAnisotropyCorrectionEnabled=*/ true);
+ /*isAnisotropyCorrectionEnabled=*/ true,
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.logicalWidth = DISPLAY_WIDTH;
@@ -257,7 +258,8 @@ public class LogicalDisplayTest {
@Test
public void testNoPillarbox_anisotropyCorrectionYDpi() {
mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
- /*isAnisotropyCorrectionEnabled=*/ true);
+ /*isAnisotropyCorrectionEnabled=*/ true,
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
// In case of Anisotropy of pixels, then the content should be rescaled so it would adjust
// to using the whole screen. This is because display will rescale it back to fill the
@@ -315,6 +317,47 @@ public class LogicalDisplayTest {
}
@Test
+ public void testGetDisplayPositionAlwaysRotateDisplayEnabled() {
+ mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice,
+ /*isAnisotropyCorrectionEnabled=*/ true,
+ /*isAlwaysRotateDisplayDeviceEnabled=*/ true);
+ mLogicalDisplay.updateLocked(mDeviceRepo);
+ Point expectedPosition = new Point();
+
+ SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
+ assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
+
+ expectedPosition.set(20, 40);
+ mLogicalDisplay.setDisplayOffsetsLocked(20, 40);
+ mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
+ assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
+
+ DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = DISPLAY_WIDTH;
+ displayInfo.logicalHeight = DISPLAY_HEIGHT;
+ // Rotation sent from WindowManager is always taken into account by LogicalDisplay
+ // not matter whether FLAG_ROTATES_WITH_CONTENT is set or not.
+ // This is because WindowManager takes care of rotation and expects that LogicalDisplay
+ // will follow the rotation supplied by WindowManager
+ expectedPosition.set(115, -20);
+ 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;
+ mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo);
+ mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
+ assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
+ }
+
+ @Test
public void testDisplayInputFlags() {
DisplayDevice displayDevice = new DisplayDevice(mDisplayAdapter, mDisplayToken,
"unique_display_id", mContext) {