[MediaProjection] compare orientations of the same type
Attempted comparing orientations from different enums; manifested as wildly
incorrect transformations when handling a rotation & the virtual display
is resized.
Bug: 289976187
Test: atest WmTests:ContentRecorderTests
Test: manual check full display & single app capture with rotations
Change-Id: I10b03c5169a03b6540181b4bc4a3f47fa421f675
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 71e9263..b6c39c6 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -3055,6 +3055,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "643263584": {
+ "message": "Content Recording: Apply transformations of shift %d x %d, scale %f, crop %d x %d for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"644675193": {
"message": "Real start recents",
"level": "DEBUG",
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 5aa7c97..f0e4149 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -35,6 +35,7 @@
import android.os.ServiceManager;
import android.provider.DeviceConfig;
import android.view.ContentRecordingSession;
+import android.view.ContentRecordingSession.RecordContent;
import android.view.Display;
import android.view.SurfaceControl;
@@ -84,6 +85,7 @@
/**
* The last configuration orientation.
*/
+ @Configuration.Orientation
private int mLastOrientation = ORIENTATION_UNDEFINED;
ContentRecorder(@NonNull DisplayContent displayContent) {
@@ -156,7 +158,8 @@
// Retrieve the size of the region to record, and continue with the update
// if the bounds or orientation has changed.
final Rect recordedContentBounds = mRecordedWindowContainer.getBounds();
- int recordedContentOrientation = mRecordedWindowContainer.getOrientation();
+ @Configuration.Orientation int recordedContentOrientation =
+ mRecordedWindowContainer.getConfiguration().orientation;
if (!mLastRecordedBounds.equals(recordedContentBounds)
|| lastOrientation != recordedContentOrientation) {
Point surfaceSize = fetchSurfaceSizeIfPresent();
@@ -356,7 +359,7 @@
*/
@Nullable
private WindowContainer retrieveRecordedWindowContainer() {
- final int contentToRecord = mContentRecordingSession.getContentToRecord();
+ @RecordContent final int contentToRecord = mContentRecordingSession.getContentToRecord();
final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
switch (contentToRecord) {
case RECORD_CONTENT_DISPLAY:
@@ -472,6 +475,12 @@
shiftedY = (surfaceSize.y - scaledHeight) / 2;
}
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Content Recording: Apply transformations of shift %d x %d, scale %f, crop %d x "
+ + "%d for display %d",
+ shiftedX, shiftedY, scale, recordedContentBounds.width(),
+ recordedContentBounds.height(), mDisplayContent.getDisplayId());
+
transaction
// Crop the area to capture to exclude the 'extra' wallpaper that is used
// for parallax (b/189930234).
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index bbec091..aa2b935 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -76,6 +78,7 @@
@RunWith(WindowTestRunner.class)
public class ContentRecorderTests extends WindowTestsBase {
private static IBinder sTaskWindowContainerToken;
+ private DisplayContent mVirtualDisplayContent;
private Task mTask;
private final ContentRecordingSession mDisplaySession =
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
@@ -106,11 +109,11 @@
displayInfo.logicalWidth = sSurfaceSize.x;
displayInfo.logicalHeight = sSurfaceSize.y;
displayInfo.state = STATE_ON;
- final DisplayContent virtualDisplayContent = createNewDisplay(displayInfo);
- final int displayId = virtualDisplayContent.getDisplayId();
- mContentRecorder = new ContentRecorder(virtualDisplayContent,
+ mVirtualDisplayContent = createNewDisplay(displayInfo);
+ final int displayId = mVirtualDisplayContent.getDisplayId();
+ mContentRecorder = new ContentRecorder(mVirtualDisplayContent,
mMediaProjectionManagerWrapper);
- spyOn(virtualDisplayContent);
+ spyOn(mVirtualDisplayContent);
// GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
// record.
@@ -118,7 +121,7 @@
mDisplaySession.setDisplayToRecord(mDefaultDisplay.mDisplayId);
// GIVEN there is a window token associated with a task to record.
- sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+ sTaskWindowContainerToken = setUpTaskWindowContainerToken(mVirtualDisplayContent);
mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
mTaskSession.setVirtualDisplayId(displayId);
@@ -251,7 +254,11 @@
public void testOnConfigurationChanged_resizesSurface() {
mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
- mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
+ // Ensure a different orientation when we check if something has changed.
+ @Configuration.Orientation final int lastOrientation =
+ mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ mContentRecorder.onConfigurationChanged(lastOrientation);
verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
anyFloat());
@@ -260,12 +267,53 @@
}
@Test
+ public void testOnConfigurationChanged_resizesVirtualDisplay() {
+ final int newWidth = 55;
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ // The user rotates the device, so the host app resizes the virtual display for the capture.
+ resizeDisplay(mDisplayContent, newWidth, sSurfaceSize.y);
+ resizeDisplay(mVirtualDisplayContent, newWidth, sSurfaceSize.y);
+ mContentRecorder.onConfigurationChanged(mDisplayContent.getConfiguration().orientation);
+
+ verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
+ anyFloat());
+ verify(mTransaction, atLeast(2)).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
+ anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testOnConfigurationChanged_rotateVirtualDisplay() {
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ // Change a value that we shouldn't rely upon; it has the wrong type.
+ mVirtualDisplayContent.setOverrideOrientation(SCREEN_ORIENTATION_FULL_SENSOR);
+ mContentRecorder.onConfigurationChanged(
+ mVirtualDisplayContent.getConfiguration().orientation);
+
+ // No resize is issued, only the initial transformations when we started recording.
+ verify(mTransaction).setPosition(eq(mRecordedSurface), anyFloat(),
+ anyFloat());
+ verify(mTransaction).setMatrix(eq(mRecordedSurface), anyFloat(), anyFloat(),
+ anyFloat(), anyFloat());
+ }
+
+ @Test
public void testOnTaskOrientationConfigurationChanged_resizesSurface() {
mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
Configuration config = mTask.getConfiguration();
- config.orientation = ORIENTATION_PORTRAIT;
+ // Ensure a different orientation when we compare.
+ @Configuration.Orientation final int orientation =
+ config.orientation == ORIENTATION_PORTRAIT ? ORIENTATION_LANDSCAPE
+ : ORIENTATION_PORTRAIT;
+ final Rect lastBounds = config.windowConfiguration.getBounds();
+ config.orientation = orientation;
+ config.windowConfiguration.setBounds(
+ new Rect(0, 0, lastBounds.height(), lastBounds.width()));
mTask.onConfigurationChanged(config);
verify(mTransaction, atLeast(2)).setPosition(eq(mRecordedSurface), anyFloat(),
@@ -278,13 +326,15 @@
public void testOnTaskBoundsConfigurationChanged_notifiesCallback() {
mTask.getRootTask().setWindowingMode(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+ final int minWidth = 222;
+ final int minHeight = 777;
final int recordedWidth = 333;
final int recordedHeight = 999;
final ActivityInfo info = new ActivityInfo();
info.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */,
-1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */,
- Gravity.NO_GRAVITY, recordedWidth, recordedHeight);
+ Gravity.NO_GRAVITY, minWidth, minHeight);
mTask.setMinDimensions(info);
// WHEN a recording is ongoing.