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);