From d2caa1f0acf79c65c144257f883b76fc80473591 Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Tue, 20 Sep 2022 19:13:33 +0000 Subject: [PATCH] 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 --- core/java/android/view/IWindowManager.aidl | 4 ++ core/java/android/window/ScreenCapture.java | 16 ++++---- .../server/wm/WindowManagerService.java | 22 ++++++---- .../server/wm/WindowManagerServiceTests.java | 41 +++++++++++++++++++ 4 files changed, 68 insertions(+), 15 deletions(-) diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 6b9fceb73ec14..067946e903616 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -970,6 +970,10 @@ interface IWindowManager */ 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 c010f2248dc54..b8f39a990cdda 100644 --- a/core/java/android/window/ScreenCapture.java +++ b/core/java/android/window/ScreenCapture.java @@ -255,14 +255,14 @@ public class ScreenCapture { * @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> 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 9722bb61f2c68..49e7a0c8c7458 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 46b4b76dc12fe..8b63904baf312 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.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_ 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.SurfaceControl; 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 @@ public class WindowManagerServiceTests extends WindowTestsBase { 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);