Convert invalid crop to display bounds for captureDisplay
If the crop value passed in the args for captureDisplay is invalid, use
the display bounds instead.
Test: WindowManagerServiceTests#testCaptureDisplay
Bug: 242714168
Change-Id: Iebe42fd35c5f49b6e711699aa1b986a556a5a5f8
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 6b9fceb7..067946e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -970,6 +970,10 @@
*/
boolean isLetterboxBackgroundMultiColored();
+ /**
+ * Captures the entire display specified by the displayId using the args provided. If the args
+ * are null or if the sourceCrop is invalid or null, the entire display bounds will be captured.
+ */
oneway void captureDisplay(int displayId, in @nullable ScreenCapture.CaptureArgs captureArgs,
in ScreenCapture.ScreenCaptureListener listener);
}
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index c010f22..b8f39a9 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -255,14 +255,14 @@
* @hide
*/
public static class CaptureArgs implements Parcelable {
- private final int mPixelFormat;
- private final Rect mSourceCrop = new Rect();
- private final float mFrameScaleX;
- private final float mFrameScaleY;
- private final boolean mCaptureSecureLayers;
- private final boolean mAllowProtected;
- private final long mUid;
- private final boolean mGrayscale;
+ public final int mPixelFormat;
+ public final Rect mSourceCrop = new Rect();
+ public final float mFrameScaleX;
+ public final float mFrameScaleY;
+ public final boolean mCaptureSecureLayers;
+ public final boolean mAllowProtected;
+ public final long mUid;
+ public final boolean mGrayscale;
private CaptureArgs(CaptureArgs.Builder<? extends CaptureArgs.Builder<?>> builder) {
mPixelFormat = builder.mPixelFormat;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9722bb6..49e7a0c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -9286,6 +9286,12 @@
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
+ ScreenCapture.captureLayers(getCaptureArgs(displayId, captureArgs), listener);
+ }
+
+ @VisibleForTesting
+ ScreenCapture.LayerCaptureArgs getCaptureArgs(int displayId,
+ @Nullable ScreenCapture.CaptureArgs captureArgs) {
final SurfaceControl displaySurfaceControl;
synchronized (mGlobalLock) {
DisplayContent displayContent = mRoot.getDisplayContent(displayId);
@@ -9297,18 +9303,20 @@
displaySurfaceControl = displayContent.getSurfaceControl();
if (captureArgs == null) {
+ captureArgs = new ScreenCapture.CaptureArgs.Builder<>()
+ .build();
+ }
+
+ if (captureArgs.mSourceCrop.isEmpty()) {
displayContent.getBounds(mTmpRect);
mTmpRect.offsetTo(0, 0);
- captureArgs = new ScreenCapture.CaptureArgs.Builder<>()
- .setSourceCrop(mTmpRect)
- .build();
+ } else {
+ mTmpRect.set(captureArgs.mSourceCrop);
}
}
- ScreenCapture.LayerCaptureArgs args =
- new ScreenCapture.LayerCaptureArgs.Builder(displaySurfaceControl, captureArgs)
+ return new ScreenCapture.LayerCaptureArgs.Builder(displaySurfaceControl, captureArgs)
+ .setSourceCrop(mTmpRect)
.build();
-
- ScreenCapture.captureLayers(args, listener);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 46b4b76..8b63904 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -41,6 +41,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
@@ -68,6 +69,7 @@
import android.view.View;
import android.view.WindowManager;
import android.window.ClientWindowFrames;
+import android.window.ScreenCapture;
import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
@@ -423,6 +425,45 @@
LETTERBOX_BACKGROUND_SOLID_COLOR)).isFalse();
}
+ @Test
+ public void testCaptureDisplay() {
+ Rect displayBounds = new Rect(0, 0, 100, 200);
+ spyOn(mDisplayContent);
+ when(mDisplayContent.getBounds()).thenReturn(displayBounds);
+
+ // Null captureArgs
+ ScreenCapture.LayerCaptureArgs resultingArgs =
+ mWm.getCaptureArgs(DEFAULT_DISPLAY, null /* captureArgs */);
+ assertEquals(displayBounds, resultingArgs.mSourceCrop);
+
+ // Non null captureArgs, didn't set rect
+ ScreenCapture.CaptureArgs captureArgs = new ScreenCapture.CaptureArgs.Builder<>().build();
+ resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, captureArgs);
+ assertEquals(displayBounds, resultingArgs.mSourceCrop);
+
+ // Non null captureArgs, invalid rect
+ captureArgs = new ScreenCapture.CaptureArgs.Builder<>()
+ .setSourceCrop(new Rect(0, 0, -1, -1))
+ .build();
+ resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, captureArgs);
+ assertEquals(displayBounds, resultingArgs.mSourceCrop);
+
+ // Non null captureArgs, null rect
+ captureArgs = new ScreenCapture.CaptureArgs.Builder<>()
+ .setSourceCrop(null)
+ .build();
+ resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, captureArgs);
+ assertEquals(displayBounds, resultingArgs.mSourceCrop);
+
+ // Non null captureArgs, valid rect
+ Rect validRect = new Rect(0, 0, 10, 50);
+ captureArgs = new ScreenCapture.CaptureArgs.Builder<>()
+ .setSourceCrop(validRect)
+ .build();
+ resultingArgs = mWm.getCaptureArgs(DEFAULT_DISPLAY, captureArgs);
+ assertEquals(validRect, resultingArgs.mSourceCrop);
+ }
+
private void setupActivityWithLaunchCookie(IBinder launchCookie, WindowContainerToken wct) {
final WindowContainer.RemoteToken remoteToken = mock(WindowContainer.RemoteToken.class);
when(remoteToken.toWindowContainerToken()).thenReturn(wct);