summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/UiAutomationConnection.java15
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java6
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java7
-rw-r--r--core/java/android/view/SurfaceControl.java527
-rw-r--r--core/java/android/window/ScreenCapture.java571
-rw-r--r--core/jni/Android.bp2
-rw-r--r--core/jni/AndroidRuntime.cpp4
-rw-r--r--core/jni/android_view_SurfaceControl.cpp276
-rw-r--r--core/jni/android_window_ScreenCapture.cpp315
-rw-r--r--core/jni/jni_common.cpp52
-rw-r--r--core/jni/jni_common.h26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java13
-rw-r--r--packages/Shell/src/com/android/shell/Screenshooter.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt9
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java2
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java5
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java21
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java13
-rw-r--r--services/core/java/com/android/server/wm/DisplayHashController.java8
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java15
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimationRunner.java9
-rw-r--r--services/core/java/com/android/server/wm/SurfaceFreezer.java17
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java5
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java21
-rw-r--r--services/core/java/com/android/server/wm/Transition.java9
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java11
-rw-r--r--services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java2
42 files changed, 1131 insertions, 926 deletions
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 8d57e32a763c..d17f2ba1b401 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -45,6 +45,7 @@ import android.view.WindowAnimationFrameStats;
import android.view.WindowContentFrameStats;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.IAccessibilityManager;
+import android.window.ScreenCapture;
import libcore.io.IoUtils;
@@ -220,13 +221,13 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
int width = crop.width();
int height = crop.height();
final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
- final SurfaceControl.DisplayCaptureArgs captureArgs =
- new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
+ final ScreenCapture.DisplayCaptureArgs captureArgs =
+ new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
.setSourceCrop(crop)
.setSize(width, height)
.build();
- final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- SurfaceControl.captureDisplay(captureArgs);
+ final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ ScreenCapture.captureDisplay(captureArgs);
return screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
} finally {
Binder.restoreCallingIdentity(identity);
@@ -242,11 +243,11 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
throwIfNotConnectedLocked();
}
- SurfaceControl.ScreenshotHardwareBuffer captureBuffer;
+ ScreenCapture.ScreenshotHardwareBuffer captureBuffer;
final long identity = Binder.clearCallingIdentity();
try {
- captureBuffer = SurfaceControl.captureLayers(
- new SurfaceControl.LayerCaptureArgs.Builder(surfaceControl)
+ captureBuffer = ScreenCapture.captureLayers(
+ new ScreenCapture.LayerCaptureArgs.Builder(surfaceControl)
.setChildrenOnly(false)
.build());
} finally {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 52cef0f1efd0..d57a272217e2 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -28,9 +28,9 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
-import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.window.DisplayWindowPolicyController;
+import android.window.ScreenCapture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -118,7 +118,7 @@ public abstract class DisplayManagerInternal {
* @param displayId The display id to take the screenshot of.
* @return The buffer or null if we have failed.
*/
- public abstract SurfaceControl.ScreenshotHardwareBuffer systemScreenshot(int displayId);
+ public abstract ScreenCapture.ScreenshotHardwareBuffer systemScreenshot(int displayId);
/**
* General screenshot functionality that excludes secure layers and applies appropriate
@@ -127,7 +127,7 @@ public abstract class DisplayManagerInternal {
* @param displayId The display id to take the screenshot of.
* @return The buffer or null if we have failed.
*/
- public abstract SurfaceControl.ScreenshotHardwareBuffer userScreenshot(int displayId);
+ public abstract ScreenCapture.ScreenshotHardwareBuffer userScreenshot(int displayId);
/**
* Returns information about the specified logical display.
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index be8c140e8770..e4c26e031738 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -93,6 +93,7 @@ import android.view.WindowLayout;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.window.ClientWindowFrames;
+import android.window.ScreenCapture;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.HandlerCaller;
@@ -1989,9 +1990,9 @@ public abstract class WallpaperService extends Service {
cleanUpScreenshotSurfaceControl();
}
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- SurfaceControl.captureLayers(
- new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ ScreenCapture.captureLayers(
+ new ScreenCapture.LayerCaptureArgs.Builder(mSurfaceControl)
// Needed because SurfaceFlinger#validateScreenshotPermissions
// uses this parameter to check whether a caller only attempts
// to screenshot itself when call doesn't come from the system.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index aef38eb2e2d2..f650cd2c3544 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -35,7 +35,6 @@ import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
@@ -80,9 +79,7 @@ import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
@@ -107,10 +104,7 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeRelease(long nativeObject);
private static native void nativeDisconnect(long nativeObject);
private static native void nativeUpdateDefaultBufferSize(long nativeObject, int width, int height);
- private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
- ScreenCaptureListener captureListener);
- private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
- ScreenCaptureListener captureListener);
+
private static native long nativeMirrorSurface(long mirrorOfObject);
private static native long nativeCreateTransaction();
private static native long nativeGetNativeTransactionFinalizer();
@@ -781,412 +775,6 @@ public final class SurfaceControl implements Parcelable {
public static final int METADATA_GAME_MODE = 8;
/**
- * A wrapper around HardwareBuffer that contains extra information about how to
- * interpret the screenshot HardwareBuffer.
- *
- * @hide
- */
- public static class ScreenshotHardwareBuffer {
- private final HardwareBuffer mHardwareBuffer;
- private final ColorSpace mColorSpace;
- private final boolean mContainsSecureLayers;
- private final boolean mContainsHdrLayers;
-
- public ScreenshotHardwareBuffer(HardwareBuffer hardwareBuffer, ColorSpace colorSpace,
- boolean containsSecureLayers, boolean containsHdrLayers) {
- mHardwareBuffer = hardwareBuffer;
- mColorSpace = colorSpace;
- mContainsSecureLayers = containsSecureLayers;
- mContainsHdrLayers = containsHdrLayers;
- }
-
- /**
- * Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
- * @param hardwareBuffer The existing HardwareBuffer object
- * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
- * @param containsSecureLayers Indicates whether this graphic buffer contains captured
- * contents of secure layers, in which case the screenshot
- * should not be persisted.
- * @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
- */
- private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
- int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
- ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
- return new ScreenshotHardwareBuffer(
- hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
- }
-
- public ColorSpace getColorSpace() {
- return mColorSpace;
- }
-
- public HardwareBuffer getHardwareBuffer() {
- return mHardwareBuffer;
- }
-
- public boolean containsSecureLayers() {
- return mContainsSecureLayers;
- }
- /**
- * Returns whether the screenshot contains at least one HDR layer.
- * This information may be useful for informing the display whether this screenshot
- * is allowed to be dimmed to SDR white.
- */
- public boolean containsHdrLayers() {
- return mContainsHdrLayers;
- }
-
- /**
- * Copy content of ScreenshotHardwareBuffer into a hardware bitmap and return it.
- * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap
- * into
- * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
- *
- * CAVEAT: This can be extremely slow; avoid use unless absolutely necessary; prefer to
- * directly
- * use the {@link HardwareBuffer} directly.
- *
- * @return Bitmap generated from the {@link HardwareBuffer}
- */
- public Bitmap asBitmap() {
- if (mHardwareBuffer == null) {
- Log.w(TAG, "Failed to take screenshot. Null screenshot object");
- return null;
- }
- return Bitmap.wrapHardwareBuffer(mHardwareBuffer, mColorSpace);
- }
- }
-
- /**
- * @hide
- */
- public interface ScreenCaptureListener {
- /**
- * The callback invoked when the screen capture is complete.
- * @param hardwareBuffer Data containing info about the screen capture.
- */
- void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer);
- }
-
- private static class SyncScreenCaptureListener implements ScreenCaptureListener {
- private static final int SCREENSHOT_WAIT_TIME_S = 1;
- private ScreenshotHardwareBuffer mScreenshotHardwareBuffer;
- private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
-
- @Override
- public void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer) {
- mScreenshotHardwareBuffer = hardwareBuffer;
- mCountDownLatch.countDown();
- }
-
- private ScreenshotHardwareBuffer waitForScreenshot() {
- try {
- mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
- } catch (Exception e) {
- Log.e(TAG, "Failed to wait for screen capture result", e);
- }
-
- return mScreenshotHardwareBuffer;
- }
- }
-
- /**
- * A common arguments class used for various screenshot requests. This contains arguments that
- * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
- * @hide
- */
- private abstract static class CaptureArgs {
- 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;
-
- private CaptureArgs(Builder<? extends Builder<?>> builder) {
- mPixelFormat = builder.mPixelFormat;
- mSourceCrop.set(builder.mSourceCrop);
- mFrameScaleX = builder.mFrameScaleX;
- mFrameScaleY = builder.mFrameScaleY;
- mCaptureSecureLayers = builder.mCaptureSecureLayers;
- mAllowProtected = builder.mAllowProtected;
- mUid = builder.mUid;
- mGrayscale = builder.mGrayscale;
- }
-
- /**
- * The Builder class used to construct {@link CaptureArgs}
- *
- * @param <T> A builder that extends {@link Builder}
- */
- abstract static class Builder<T extends Builder<T>> {
- private int mPixelFormat = PixelFormat.RGBA_8888;
- private final Rect mSourceCrop = new Rect();
- private float mFrameScaleX = 1;
- private float mFrameScaleY = 1;
- private boolean mCaptureSecureLayers;
- private boolean mAllowProtected;
- private long mUid = -1;
- private boolean mGrayscale;
-
- /**
- * The desired pixel format of the returned buffer.
- */
- public T setPixelFormat(int pixelFormat) {
- mPixelFormat = pixelFormat;
- return getThis();
- }
-
- /**
- * The portion of the screen to capture into the buffer. Caller may pass in
- * 'new Rect()' or null if no cropping is desired.
- */
- public T setSourceCrop(@Nullable Rect sourceCrop) {
- if (sourceCrop == null) {
- mSourceCrop.setEmpty();
- } else {
- mSourceCrop.set(sourceCrop);
- }
- return getThis();
- }
-
- /**
- * The desired scale of the returned buffer. The raw screen will be scaled up/down.
- */
- public T setFrameScale(float frameScale) {
- mFrameScaleX = frameScale;
- mFrameScaleY = frameScale;
- return getThis();
- }
-
- /**
- * The desired scale of the returned buffer, allowing separate values for x and y scale.
- * The raw screen will be scaled up/down.
- */
- public T setFrameScale(float frameScaleX, float frameScaleY) {
- mFrameScaleX = frameScaleX;
- mFrameScaleY = frameScaleY;
- return getThis();
- }
-
- /**
- * Whether to allow the screenshot of secure layers. Warning: This should only be done
- * if the content will be placed in a secure SurfaceControl.
- *
- * @see ScreenshotHardwareBuffer#containsSecureLayers()
- */
- public T setCaptureSecureLayers(boolean captureSecureLayers) {
- mCaptureSecureLayers = captureSecureLayers;
- return getThis();
- }
-
- /**
- * Whether to allow the screenshot of protected (DRM) content. Warning: The screenshot
- * cannot be read in unprotected space.
- *
- * @see HardwareBuffer#USAGE_PROTECTED_CONTENT
- */
- public T setAllowProtected(boolean allowProtected) {
- mAllowProtected = allowProtected;
- return getThis();
- }
-
- /**
- * Set the uid of the content that should be screenshot. The code will skip any surfaces
- * that don't belong to the specified uid.
- */
- public T setUid(long uid) {
- mUid = uid;
- return getThis();
- }
-
- /**
- * Set whether the screenshot should use grayscale or not.
- */
- public T setGrayscale(boolean grayscale) {
- mGrayscale = grayscale;
- return getThis();
- }
-
- /**
- * Each sub class should return itself to allow the builder to chain properly
- */
- abstract T getThis();
- }
- }
-
- /**
- * The arguments class used to make display capture requests.
- *
- * @see #nativeCaptureDisplay(DisplayCaptureArgs, ScreenCaptureListener)
- * @hide
- */
- public static class DisplayCaptureArgs extends CaptureArgs {
- private final IBinder mDisplayToken;
- private final int mWidth;
- private final int mHeight;
- private final boolean mUseIdentityTransform;
-
- private DisplayCaptureArgs(Builder builder) {
- super(builder);
- mDisplayToken = builder.mDisplayToken;
- mWidth = builder.mWidth;
- mHeight = builder.mHeight;
- mUseIdentityTransform = builder.mUseIdentityTransform;
- }
-
- /**
- * The Builder class used to construct {@link DisplayCaptureArgs}
- */
- public static class Builder extends CaptureArgs.Builder<Builder> {
- private IBinder mDisplayToken;
- private int mWidth;
- private int mHeight;
- private boolean mUseIdentityTransform;
-
- /**
- * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
- * remains valid.
- */
- public DisplayCaptureArgs build() {
- if (mDisplayToken == null) {
- throw new IllegalStateException(
- "Can't take screenshot with null display token");
- }
- return new DisplayCaptureArgs(this);
- }
-
- public Builder(IBinder displayToken) {
- setDisplayToken(displayToken);
- }
-
- /**
- * The display to take the screenshot of.
- */
- public Builder setDisplayToken(IBinder displayToken) {
- mDisplayToken = displayToken;
- return this;
- }
-
- /**
- * Set the desired size of the returned buffer. The raw screen will be scaled down to
- * this size
- *
- * @param width The desired width of the returned buffer. Caller may pass in 0 if no
- * scaling is desired.
- * @param height The desired height of the returned buffer. Caller may pass in 0 if no
- * scaling is desired.
- */
- public Builder setSize(int width, int height) {
- mWidth = width;
- mHeight = height;
- return this;
- }
-
- /**
- * Replace the rotation transform of the display with the identity transformation while
- * taking the screenshot. This ensures the screenshot is taken in the ROTATION_0
- * orientation. Set this value to false if the screenshot should be taken in the
- * current screen orientation.
- */
- public Builder setUseIdentityTransform(boolean useIdentityTransform) {
- mUseIdentityTransform = useIdentityTransform;
- return this;
- }
-
- @Override
- Builder getThis() {
- return this;
- }
- }
- }
-
- /**
- * The arguments class used to make layer capture requests.
- *
- * @see #nativeCaptureLayers(LayerCaptureArgs, ScreenCaptureListener)
- * @hide
- */
- public static class LayerCaptureArgs extends CaptureArgs {
- private final long mNativeLayer;
- private final long[] mNativeExcludeLayers;
- private final boolean mChildrenOnly;
-
- private LayerCaptureArgs(Builder builder) {
- super(builder);
- mChildrenOnly = builder.mChildrenOnly;
- mNativeLayer = builder.mLayer.mNativeObject;
- if (builder.mExcludeLayers != null) {
- mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
- for (int i = 0; i < builder.mExcludeLayers.length; i++) {
- mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
- }
- } else {
- mNativeExcludeLayers = null;
- }
- }
-
- /**
- * The Builder class used to construct {@link LayerCaptureArgs}
- */
- public static class Builder extends CaptureArgs.Builder<Builder> {
- private SurfaceControl mLayer;
- private SurfaceControl[] mExcludeLayers;
- private boolean mChildrenOnly = true;
-
- /**
- * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
- * remains valid.
- */
- public LayerCaptureArgs build() {
- if (mLayer == null) {
- throw new IllegalStateException(
- "Can't take screenshot with null layer");
- }
- return new LayerCaptureArgs(this);
- }
-
- public Builder(SurfaceControl layer) {
- setLayer(layer);
- }
-
- /**
- * The root layer to capture.
- */
- public Builder setLayer(SurfaceControl layer) {
- mLayer = layer;
- return this;
- }
-
-
- /**
- * An array of layer handles to exclude.
- */
- public Builder setExcludeLayers(@Nullable SurfaceControl[] excludeLayers) {
- mExcludeLayers = excludeLayers;
- return this;
- }
-
- /**
- * Whether to include the layer itself in the screenshot or just the children and their
- * descendants.
- */
- public Builder setChildrenOnly(boolean childrenOnly) {
- mChildrenOnly = childrenOnly;
- return this;
- }
-
- @Override
- Builder getThis() {
- return this;
- }
-
- }
- }
-
- /**
* Builder class for {@link SurfaceControl} objects.
*
* By default the surface will be hidden, and have "unset" bounds, meaning it can
@@ -2418,119 +2006,6 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * @param captureArgs Arguments about how to take the screenshot
- * @param captureListener A listener to receive the screenshot callback
- * @hide
- */
- public static int captureDisplay(@NonNull DisplayCaptureArgs captureArgs,
- @NonNull ScreenCaptureListener captureListener) {
- return nativeCaptureDisplay(captureArgs, captureListener);
- }
-
- /**
- * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with
- * the content.
- *
- * @hide
- */
- public static ScreenshotHardwareBuffer captureDisplay(DisplayCaptureArgs captureArgs) {
- SyncScreenCaptureListener screenCaptureListener = new SyncScreenCaptureListener();
-
- int status = captureDisplay(captureArgs, screenCaptureListener);
- if (status != 0) {
- return null;
- }
-
- return screenCaptureListener.waitForScreenshot();
- }
-
- /**
- * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
- *
- * @param layer The root layer to capture.
- * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
- * Rect()' or null if no cropping is desired. If the root layer does not
- * have a buffer or a crop set, then a non-empty source crop must be
- * specified.
- * @param frameScale The desired scale of the returned buffer; the raw
- * screen will be scaled up/down.
- *
- * @return Returns a HardwareBuffer that contains the layer capture.
- * @hide
- */
- public static ScreenshotHardwareBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
- float frameScale) {
- return captureLayers(layer, sourceCrop, frameScale, PixelFormat.RGBA_8888);
- }
-
- /**
- * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
- *
- * @param layer The root layer to capture.
- * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
- * Rect()' or null if no cropping is desired. If the root layer does not
- * have a buffer or a crop set, then a non-empty source crop must be
- * specified.
- * @param frameScale The desired scale of the returned buffer; the raw
- * screen will be scaled up/down.
- * @param format The desired pixel format of the returned buffer.
- *
- * @return Returns a HardwareBuffer that contains the layer capture.
- * @hide
- */
- public static ScreenshotHardwareBuffer captureLayers(@NonNull SurfaceControl layer,
- @Nullable Rect sourceCrop, float frameScale, int format) {
- LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
- .setSourceCrop(sourceCrop)
- .setFrameScale(frameScale)
- .setPixelFormat(format)
- .build();
-
- return captureLayers(captureArgs);
- }
-
- /**
- * @hide
- */
- public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) {
- SyncScreenCaptureListener screenCaptureListener = new SyncScreenCaptureListener();
-
- int status = captureLayers(captureArgs, screenCaptureListener);
- if (status != 0) {
- return null;
- }
-
- return screenCaptureListener.waitForScreenshot();
- }
-
- /**
- * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer
- * handles to exclude.
- * @hide
- */
- public static ScreenshotHardwareBuffer captureLayersExcluding(SurfaceControl layer,
- Rect sourceCrop, float frameScale, int format, SurfaceControl[] exclude) {
- LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
- .setSourceCrop(sourceCrop)
- .setFrameScale(frameScale)
- .setPixelFormat(format)
- .setExcludeLayers(exclude)
- .build();
-
- return captureLayers(captureArgs);
- }
-
- /**
- * @param captureArgs Arguments about how to take the screenshot
- * @param captureListener A listener to receive the screenshot callback
- * @hide
- */
- public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
- @NonNull ScreenCaptureListener captureListener) {
- return nativeCaptureLayers(captureArgs, captureListener);
- }
-
- /**
* Returns whether protected content is supported in GPU composition.
* @hide
*/
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
new file mode 100644
index 000000000000..887d027d26a8
--- /dev/null
+++ b/core/java/android/window/ScreenCapture.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.SurfaceControl;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handles display and layer captures for the system.
+ *
+ * @hide
+ */
+public class ScreenCapture {
+ private static final String TAG = "ScreenCapture";
+
+ private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
+ ScreenCaptureListener captureListener);
+ private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
+ ScreenCaptureListener captureListener);
+
+ /**
+ * @param captureArgs Arguments about how to take the screenshot
+ * @param captureListener A listener to receive the screenshot callback
+ * @hide
+ */
+ public static int captureDisplay(@NonNull DisplayCaptureArgs captureArgs,
+ @NonNull ScreenCaptureListener captureListener) {
+ return nativeCaptureDisplay(captureArgs, captureListener);
+ }
+
+ /**
+ * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with
+ * the content.
+ *
+ * @hide
+ */
+ public static ScreenshotHardwareBuffer captureDisplay(
+ DisplayCaptureArgs captureArgs) {
+ SyncScreenCaptureListener
+ screenCaptureListener = new SyncScreenCaptureListener();
+
+ int status = captureDisplay(captureArgs, screenCaptureListener);
+ if (status != 0) {
+ return null;
+ }
+
+ return screenCaptureListener.waitForScreenshot();
+ }
+
+ /**
+ * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
+ *
+ * @param layer The root layer to capture.
+ * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
+ * Rect()' or null if no cropping is desired. If the root layer does not
+ * have a buffer or a crop set, then a non-empty source crop must be
+ * specified.
+ * @param frameScale The desired scale of the returned buffer; the raw
+ * screen will be scaled up/down.
+ *
+ * @return Returns a HardwareBuffer that contains the layer capture.
+ * @hide
+ */
+ public static ScreenshotHardwareBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
+ float frameScale) {
+ return captureLayers(layer, sourceCrop, frameScale, PixelFormat.RGBA_8888);
+ }
+
+ /**
+ * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
+ *
+ * @param layer The root layer to capture.
+ * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
+ * Rect()' or null if no cropping is desired. If the root layer does not
+ * have a buffer or a crop set, then a non-empty source crop must be
+ * specified.
+ * @param frameScale The desired scale of the returned buffer; the raw
+ * screen will be scaled up/down.
+ * @param format The desired pixel format of the returned buffer.
+ *
+ * @return Returns a HardwareBuffer that contains the layer capture.
+ * @hide
+ */
+ public static ScreenshotHardwareBuffer captureLayers(@NonNull SurfaceControl layer,
+ @Nullable Rect sourceCrop, float frameScale, int format) {
+ LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
+ .setSourceCrop(sourceCrop)
+ .setFrameScale(frameScale)
+ .setPixelFormat(format)
+ .build();
+
+ return captureLayers(captureArgs);
+ }
+
+ /**
+ * @hide
+ */
+ public static ScreenshotHardwareBuffer captureLayers(
+ LayerCaptureArgs captureArgs) {
+ SyncScreenCaptureListener screenCaptureListener = new SyncScreenCaptureListener();
+
+ int status = captureLayers(captureArgs, screenCaptureListener);
+ if (status != 0) {
+ return null;
+ }
+
+ return screenCaptureListener.waitForScreenshot();
+ }
+
+ /**
+ * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer
+ * handles to exclude.
+ * @hide
+ */
+ public static ScreenshotHardwareBuffer captureLayersExcluding(SurfaceControl layer,
+ Rect sourceCrop, float frameScale, int format, SurfaceControl[] exclude) {
+ LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
+ .setSourceCrop(sourceCrop)
+ .setFrameScale(frameScale)
+ .setPixelFormat(format)
+ .setExcludeLayers(exclude)
+ .build();
+
+ return captureLayers(captureArgs);
+ }
+
+ /**
+ * @param captureArgs Arguments about how to take the screenshot
+ * @param captureListener A listener to receive the screenshot callback
+ * @hide
+ */
+ public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
+ @NonNull ScreenCaptureListener captureListener) {
+ return nativeCaptureLayers(captureArgs, captureListener);
+ }
+
+ /**
+ * @hide
+ */
+ public interface ScreenCaptureListener {
+ /**
+ * The callback invoked when the screen capture is complete.
+ * @param hardwareBuffer Data containing info about the screen capture.
+ */
+ void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer);
+ }
+
+ /**
+ * A wrapper around HardwareBuffer that contains extra information about how to
+ * interpret the screenshot HardwareBuffer.
+ *
+ * @hide
+ */
+ public static class ScreenshotHardwareBuffer {
+ private final HardwareBuffer mHardwareBuffer;
+ private final ColorSpace mColorSpace;
+ private final boolean mContainsSecureLayers;
+ private final boolean mContainsHdrLayers;
+
+ public ScreenshotHardwareBuffer(HardwareBuffer hardwareBuffer, ColorSpace colorSpace,
+ boolean containsSecureLayers, boolean containsHdrLayers) {
+ mHardwareBuffer = hardwareBuffer;
+ mColorSpace = colorSpace;
+ mContainsSecureLayers = containsSecureLayers;
+ mContainsHdrLayers = containsHdrLayers;
+ }
+
+ /**
+ * Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
+ * @param hardwareBuffer The existing HardwareBuffer object
+ * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
+ * @param containsSecureLayers Indicates whether this graphic buffer contains captured
+ * contents of secure layers, in which case the screenshot
+ * should not be persisted.
+ * @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
+ */
+ private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
+ int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
+ ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
+ return new ScreenshotHardwareBuffer(
+ hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
+ }
+
+ public ColorSpace getColorSpace() {
+ return mColorSpace;
+ }
+
+ public HardwareBuffer getHardwareBuffer() {
+ return mHardwareBuffer;
+ }
+
+ /**
+ * Whether this screenshot contains secure layers
+ */
+ public boolean containsSecureLayers() {
+ return mContainsSecureLayers;
+ }
+ /**
+ * Returns whether the screenshot contains at least one HDR layer.
+ * This information may be useful for informing the display whether this screenshot
+ * is allowed to be dimmed to SDR white.
+ */
+ public boolean containsHdrLayers() {
+ return mContainsHdrLayers;
+ }
+
+ /**
+ * Copy content of ScreenshotHardwareBuffer into a hardware bitmap and return it.
+ * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap
+ * into
+ * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
+ *
+ * CAVEAT: This can be extremely slow; avoid use unless absolutely necessary; prefer to
+ * directly
+ * use the {@link HardwareBuffer} directly.
+ *
+ * @return Bitmap generated from the {@link HardwareBuffer}
+ */
+ public Bitmap asBitmap() {
+ if (mHardwareBuffer == null) {
+ Log.w(TAG, "Failed to take screenshot. Null screenshot object");
+ return null;
+ }
+ return Bitmap.wrapHardwareBuffer(mHardwareBuffer, mColorSpace);
+ }
+ }
+
+ private static class SyncScreenCaptureListener implements ScreenCaptureListener {
+ private static final int SCREENSHOT_WAIT_TIME_S = 1;
+ private ScreenshotHardwareBuffer mScreenshotHardwareBuffer;
+ private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+ @Override
+ public void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer) {
+ mScreenshotHardwareBuffer = hardwareBuffer;
+ mCountDownLatch.countDown();
+ }
+
+ private ScreenshotHardwareBuffer waitForScreenshot() {
+ try {
+ mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to wait for screen capture result", e);
+ }
+
+ return mScreenshotHardwareBuffer;
+ }
+ }
+
+ /**
+ * A common arguments class used for various screenshot requests. This contains arguments that
+ * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
+ * @hide
+ */
+ private abstract static class CaptureArgs {
+ 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;
+
+ private CaptureArgs(Builder<? extends Builder<?>> builder) {
+ mPixelFormat = builder.mPixelFormat;
+ mSourceCrop.set(builder.mSourceCrop);
+ mFrameScaleX = builder.mFrameScaleX;
+ mFrameScaleY = builder.mFrameScaleY;
+ mCaptureSecureLayers = builder.mCaptureSecureLayers;
+ mAllowProtected = builder.mAllowProtected;
+ mUid = builder.mUid;
+ mGrayscale = builder.mGrayscale;
+ }
+
+ /**
+ * The Builder class used to construct {@link CaptureArgs}
+ *
+ * @param <T> A builder that extends {@link Builder}
+ */
+ abstract static class Builder<T extends Builder<T>> {
+ private int mPixelFormat = PixelFormat.RGBA_8888;
+ private final Rect mSourceCrop = new Rect();
+ private float mFrameScaleX = 1;
+ private float mFrameScaleY = 1;
+ private boolean mCaptureSecureLayers;
+ private boolean mAllowProtected;
+ private long mUid = -1;
+ private boolean mGrayscale;
+
+ /**
+ * The desired pixel format of the returned buffer.
+ */
+ public T setPixelFormat(int pixelFormat) {
+ mPixelFormat = pixelFormat;
+ return getThis();
+ }
+
+ /**
+ * The portion of the screen to capture into the buffer. Caller may pass in
+ * 'new Rect()' or null if no cropping is desired.
+ */
+ public T setSourceCrop(@Nullable Rect sourceCrop) {
+ if (sourceCrop == null) {
+ mSourceCrop.setEmpty();
+ } else {
+ mSourceCrop.set(sourceCrop);
+ }
+ return getThis();
+ }
+
+ /**
+ * The desired scale of the returned buffer. The raw screen will be scaled up/down.
+ */
+ public T setFrameScale(float frameScale) {
+ mFrameScaleX = frameScale;
+ mFrameScaleY = frameScale;
+ return getThis();
+ }
+
+ /**
+ * The desired scale of the returned buffer, allowing separate values for x and y scale.
+ * The raw screen will be scaled up/down.
+ */
+ public T setFrameScale(float frameScaleX, float frameScaleY) {
+ mFrameScaleX = frameScaleX;
+ mFrameScaleY = frameScaleY;
+ return getThis();
+ }
+
+ /**
+ * Whether to allow the screenshot of secure layers. Warning: This should only be done
+ * if the content will be placed in a secure SurfaceControl.
+ *
+ * @see ScreenshotHardwareBuffer#containsSecureLayers()
+ */
+ public T setCaptureSecureLayers(boolean captureSecureLayers) {
+ mCaptureSecureLayers = captureSecureLayers;
+ return getThis();
+ }
+
+ /**
+ * Whether to allow the screenshot of protected (DRM) content. Warning: The screenshot
+ * cannot be read in unprotected space.
+ *
+ * @see HardwareBuffer#USAGE_PROTECTED_CONTENT
+ */
+ public T setAllowProtected(boolean allowProtected) {
+ mAllowProtected = allowProtected;
+ return getThis();
+ }
+
+ /**
+ * Set the uid of the content that should be screenshot. The code will skip any surfaces
+ * that don't belong to the specified uid.
+ */
+ public T setUid(long uid) {
+ mUid = uid;
+ return getThis();
+ }
+
+ /**
+ * Set whether the screenshot should use grayscale or not.
+ */
+ public T setGrayscale(boolean grayscale) {
+ mGrayscale = grayscale;
+ return getThis();
+ }
+
+ /**
+ * Each sub class should return itself to allow the builder to chain properly
+ */
+ abstract T getThis();
+ }
+ }
+
+ /**
+ * The arguments class used to make display capture requests.
+ *
+ * @see #nativeCaptureDisplay(DisplayCaptureArgs, ScreenCaptureListener)
+ * @hide
+ */
+ public static class DisplayCaptureArgs extends CaptureArgs {
+ private final IBinder mDisplayToken;
+ private final int mWidth;
+ private final int mHeight;
+ private final boolean mUseIdentityTransform;
+
+ private DisplayCaptureArgs(Builder builder) {
+ super(builder);
+ mDisplayToken = builder.mDisplayToken;
+ mWidth = builder.mWidth;
+ mHeight = builder.mHeight;
+ mUseIdentityTransform = builder.mUseIdentityTransform;
+ }
+
+ /**
+ * The Builder class used to construct {@link DisplayCaptureArgs}
+ */
+ public static class Builder extends CaptureArgs.Builder<Builder> {
+ private IBinder mDisplayToken;
+ private int mWidth;
+ private int mHeight;
+ private boolean mUseIdentityTransform;
+
+ /**
+ * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
+ * remains valid.
+ */
+ public DisplayCaptureArgs build() {
+ if (mDisplayToken == null) {
+ throw new IllegalStateException(
+ "Can't take screenshot with null display token");
+ }
+ return new DisplayCaptureArgs(this);
+ }
+
+ public Builder(IBinder displayToken) {
+ setDisplayToken(displayToken);
+ }
+
+ /**
+ * The display to take the screenshot of.
+ */
+ public Builder setDisplayToken(IBinder displayToken) {
+ mDisplayToken = displayToken;
+ return this;
+ }
+
+ /**
+ * Set the desired size of the returned buffer. The raw screen will be scaled down to
+ * this size
+ *
+ * @param width The desired width of the returned buffer. Caller may pass in 0 if no
+ * scaling is desired.
+ * @param height The desired height of the returned buffer. Caller may pass in 0 if no
+ * scaling is desired.
+ */
+ public Builder setSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ return this;
+ }
+
+ /**
+ * Replace the rotation transform of the display with the identity transformation while
+ * taking the screenshot. This ensures the screenshot is taken in the ROTATION_0
+ * orientation. Set this value to false if the screenshot should be taken in the
+ * current screen orientation.
+ */
+ public Builder setUseIdentityTransform(boolean useIdentityTransform) {
+ mUseIdentityTransform = useIdentityTransform;
+ return this;
+ }
+
+ @Override
+ Builder getThis() {
+ return this;
+ }
+ }
+ }
+
+ /**
+ * The arguments class used to make layer capture requests.
+ *
+ * @see #nativeCaptureLayers(LayerCaptureArgs, ScreenCaptureListener)
+ * @hide
+ */
+ public static class LayerCaptureArgs extends CaptureArgs {
+ private final long mNativeLayer;
+ private final long[] mNativeExcludeLayers;
+ private final boolean mChildrenOnly;
+
+ private LayerCaptureArgs(Builder builder) {
+ super(builder);
+ mChildrenOnly = builder.mChildrenOnly;
+ mNativeLayer = builder.mLayer.mNativeObject;
+ if (builder.mExcludeLayers != null) {
+ mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
+ for (int i = 0; i < builder.mExcludeLayers.length; i++) {
+ mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
+ }
+ } else {
+ mNativeExcludeLayers = null;
+ }
+ }
+
+ /**
+ * The Builder class used to construct {@link LayerCaptureArgs}
+ */
+ public static class Builder extends CaptureArgs.Builder<Builder> {
+ private SurfaceControl mLayer;
+ private SurfaceControl[] mExcludeLayers;
+ private boolean mChildrenOnly = true;
+
+ /**
+ * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
+ * remains valid.
+ */
+ public LayerCaptureArgs build() {
+ if (mLayer == null) {
+ throw new IllegalStateException(
+ "Can't take screenshot with null layer");
+ }
+ return new LayerCaptureArgs(this);
+ }
+
+ public Builder(SurfaceControl layer) {
+ setLayer(layer);
+ }
+
+ /**
+ * The root layer to capture.
+ */
+ public Builder setLayer(SurfaceControl layer) {
+ mLayer = layer;
+ return this;
+ }
+
+
+ /**
+ * An array of layer handles to exclude.
+ */
+ public Builder setExcludeLayers(@Nullable SurfaceControl[] excludeLayers) {
+ mExcludeLayers = excludeLayers;
+ return this;
+ }
+
+ /**
+ * Whether to include the layer itself in the screenshot or just the children and their
+ * descendants.
+ */
+ public Builder setChildrenOnly(boolean childrenOnly) {
+ mChildrenOnly = childrenOnly;
+ return this;
+ }
+
+ @Override
+ Builder getThis() {
+ return this;
+ }
+
+ }
+ }
+
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5498769fcf8f..26d0be139b64 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -231,6 +231,8 @@ cc_library_shared {
"android_hardware_input_InputWindowHandle.cpp",
"android_hardware_input_InputApplicationHandle.cpp",
"android_window_WindowInfosListener.cpp",
+ "android_window_ScreenCapture.cpp",
+ "jni_common.cpp",
],
static_libs: [
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 817b3154889b..11cb64cdf81a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -211,6 +211,8 @@ extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_security_VerityUtils(JNIEnv* env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
extern int register_android_window_WindowInfosListener(JNIEnv* env);
+extern int register_android_window_ScreenCapture(JNIEnv* env);
+extern int register_jni_common(JNIEnv* env);
// Namespace for Android Runtime flags applied during boot time.
static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
@@ -1647,6 +1649,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_KernelSingleUidTimeReader),
REG_JNI(register_android_window_WindowInfosListener),
+ REG_JNI(register_android_window_ScreenCapture),
+ REG_JNI(register_jni_common),
};
/*
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e64b2615e1e2..11410c7ef73d 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -21,7 +21,6 @@
#include <android-base/chrono_utils.h>
#include <android/graphics/properties.h>
#include <android/graphics/region.h>
-#include <android/gui/BnScreenCaptureListener.h>
#include <android/gui/BnWindowInfosReportedListener.h>
#include <android/hardware/display/IDeviceProductInfoConstants.h>
#include <android/os/IInputConstants.h>
@@ -60,12 +59,12 @@
#include "android_os_Parcel.h"
#include "android_util_Binder.h"
#include "core_jni_helpers.h"
+#include "jni_common.h"
// ----------------------------------------------------------------------------
namespace android {
-using gui::CaptureArgs;
using gui::FocusRequest;
static void doThrowNPE(JNIEnv* env) {
@@ -130,37 +129,6 @@ static struct {
jfieldID group;
} gDisplayModeClassInfo;
-static struct {
- jfieldID bottom;
- jfieldID left;
- jfieldID right;
- jfieldID top;
-} gRectClassInfo;
-
-static struct {
- jfieldID pixelFormat;
- jfieldID sourceCrop;
- jfieldID frameScaleX;
- jfieldID frameScaleY;
- jfieldID captureSecureLayers;
- jfieldID allowProtected;
- jfieldID uid;
- jfieldID grayscale;
-} gCaptureArgsClassInfo;
-
-static struct {
- jfieldID displayToken;
- jfieldID width;
- jfieldID height;
- jfieldID useIdentityTransform;
-} gDisplayCaptureArgsClassInfo;
-
-static struct {
- jfieldID layer;
- jfieldID excludeLayers;
- jfieldID childrenOnly;
-} gLayerCaptureArgsClassInfo;
-
// Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
void DeleteScreenshot(void* addr, void* context) {
delete ((ScreenshotClient*) context);
@@ -220,16 +188,6 @@ static struct {
static struct {
jclass clazz;
- jmethodID builder;
-} gScreenshotHardwareBufferClassInfo;
-
-static struct {
- jclass clazz;
- jmethodID onScreenCaptureComplete;
-} gScreenCaptureListenerClassInfo;
-
-static struct {
- jclass clazz;
jmethodID ctor;
jfieldID defaultMode;
jfieldID allowGroupSwitching;
@@ -266,24 +224,6 @@ static struct {
jmethodID invokeReleaseCallback;
} gInvokeReleaseCallback;
-class JNamedColorSpace {
-public:
- // ColorSpace.Named.SRGB.ordinal() = 0;
- static constexpr jint SRGB = 0;
-
- // ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
- static constexpr jint DISPLAY_P3 = 7;
-};
-
-constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
- switch (dataspace) {
- case ui::Dataspace::DISPLAY_P3:
- return JNamedColorSpace::DISPLAY_P3;
- default:
- return JNamedColorSpace::SRGB;
- }
-}
-
constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
switch (colorMode) {
case ui::ColorMode::DISPLAY_P3:
@@ -296,59 +236,6 @@ constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode
}
}
-class ScreenCaptureListenerWrapper : public gui::BnScreenCaptureListener {
-public:
- explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) {
- env->GetJavaVM(&mVm);
- screenCaptureListenerObject = env->NewGlobalRef(jobject);
- LOG_ALWAYS_FATAL_IF(!screenCaptureListenerObject, "Failed to make global ref");
- }
-
- ~ScreenCaptureListenerWrapper() {
- if (screenCaptureListenerObject) {
- getenv()->DeleteGlobalRef(screenCaptureListenerObject);
- screenCaptureListenerObject = nullptr;
- }
- }
-
- binder::Status onScreenCaptureCompleted(
- const gui::ScreenCaptureResults& captureResults) override {
- JNIEnv* env = getenv();
- if (!captureResults.fenceResult.ok() || captureResults.buffer == nullptr) {
- env->CallVoidMethod(screenCaptureListenerObject,
- gScreenCaptureListenerClassInfo.onScreenCaptureComplete, nullptr);
- return binder::Status::ok();
- }
- captureResults.fenceResult.value()->waitForever("");
- jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
- env, captureResults.buffer->toAHardwareBuffer());
- const jint namedColorSpace =
- fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
- jobject screenshotHardwareBuffer =
- env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
- gScreenshotHardwareBufferClassInfo.builder,
- jhardwareBuffer, namedColorSpace,
- captureResults.capturedSecureLayers,
- captureResults.capturedHdrLayers);
- env->CallVoidMethod(screenCaptureListenerObject,
- gScreenCaptureListenerClassInfo.onScreenCaptureComplete,
- screenshotHardwareBuffer);
- env->DeleteLocalRef(jhardwareBuffer);
- env->DeleteLocalRef(screenshotHardwareBuffer);
- return binder::Status::ok();
- }
-
-private:
- jobject screenCaptureListenerObject;
- JavaVM* mVm;
-
- JNIEnv* getenv() {
- JNIEnv* env;
- mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
- return env;
- }
-};
-
class TransactionCommittedListenerWrapper {
public:
explicit TransactionCommittedListenerWrapper(JNIEnv* env, jobject object) {
@@ -494,102 +381,6 @@ static void nativeSetDefaultBufferSize(JNIEnv* env, jclass clazz, jlong nativeOb
}
}
-static Rect rectFromObj(JNIEnv* env, jobject rectObj) {
- int left = env->GetIntField(rectObj, gRectClassInfo.left);
- int top = env->GetIntField(rectObj, gRectClassInfo.top);
- int right = env->GetIntField(rectObj, gRectClassInfo.right);
- int bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
- return Rect(left, top, right, bottom);
-}
-
-static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs& captureArgs) {
- captureArgs.pixelFormat = static_cast<ui::PixelFormat>(
- env->GetIntField(captureArgsObject, gCaptureArgsClassInfo.pixelFormat));
- captureArgs.sourceCrop =
- rectFromObj(env,
- env->GetObjectField(captureArgsObject, gCaptureArgsClassInfo.sourceCrop));
- captureArgs.frameScaleX =
- env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScaleX);
- captureArgs.frameScaleY =
- env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScaleY);
- captureArgs.captureSecureLayers =
- env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.captureSecureLayers);
- captureArgs.allowProtected =
- env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.allowProtected);
- captureArgs.uid = env->GetLongField(captureArgsObject, gCaptureArgsClassInfo.uid);
- captureArgs.grayscale =
- env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.grayscale);
-}
-
-static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
- jobject displayCaptureArgsObject) {
- DisplayCaptureArgs captureArgs;
- getCaptureArgs(env, displayCaptureArgsObject, captureArgs);
-
- captureArgs.displayToken =
- ibinderForJavaObject(env,
- env->GetObjectField(displayCaptureArgsObject,
- gDisplayCaptureArgsClassInfo.displayToken));
- captureArgs.width =
- env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.width);
- captureArgs.height =
- env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.height);
- captureArgs.useIdentityTransform =
- env->GetBooleanField(displayCaptureArgsObject,
- gDisplayCaptureArgsClassInfo.useIdentityTransform);
- return captureArgs;
-}
-
-static jint nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject,
- jobject screenCaptureListenerObject) {
- const DisplayCaptureArgs captureArgs =
- displayCaptureArgsFromObject(env, displayCaptureArgsObject);
-
- if (captureArgs.displayToken == NULL) {
- return BAD_VALUE;
- }
-
- sp<IScreenCaptureListener> captureListener =
- new ScreenCaptureListenerWrapper(env, screenCaptureListenerObject);
- return ScreenshotClient::captureDisplay(captureArgs, captureListener);
-}
-
-static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject,
- jobject screenCaptureListenerObject) {
- LayerCaptureArgs captureArgs;
- getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
- SurfaceControl* layer = reinterpret_cast<SurfaceControl*>(
- env->GetLongField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.layer));
- if (layer == nullptr) {
- return BAD_VALUE;
- }
-
- captureArgs.layerHandle = layer->getHandle();
- captureArgs.childrenOnly =
- env->GetBooleanField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.childrenOnly);
- jlongArray excludeObjectArray = reinterpret_cast<jlongArray>(
- env->GetObjectField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.excludeLayers));
- if (excludeObjectArray != NULL) {
- const jsize len = env->GetArrayLength(excludeObjectArray);
- captureArgs.excludeHandles.reserve(len);
-
- const jlong* objects = env->GetLongArrayElements(excludeObjectArray, nullptr);
- for (jsize i = 0; i < len; i++) {
- auto excludeObject = reinterpret_cast<SurfaceControl *>(objects[i]);
- if (excludeObject == nullptr) {
- jniThrowNullPointerException(env, "Exclude layer is null");
- return NULL;
- }
- captureArgs.excludeHandles.emplace(excludeObject->getHandle());
- }
- env->ReleaseLongArrayElements(excludeObjectArray, const_cast<jlong*>(objects), JNI_ABORT);
- }
-
- sp<IScreenCaptureListener> captureListener =
- new ScreenCaptureListenerWrapper(env, screenCaptureListenerObject);
- return ScreenshotClient::captureLayers(captureArgs, captureListener);
-}
-
static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
transaction->apply(sync);
@@ -664,12 +455,12 @@ static void nativeSetGeometry(JNIEnv* env, jclass clazz, jlong transactionObj, j
Rect source, dst;
if (sourceObj != NULL) {
- source = rectFromObj(env, sourceObj);
+ source = JNICommon::rectFromObj(env, sourceObj);
} else {
source.makeInvalid();
}
if (dstObj != NULL) {
- dst = rectFromObj(env, dstObj);
+ dst = JNICommon::rectFromObj(env, dstObj);
} else {
dst.makeInvalid();
}
@@ -2269,12 +2060,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeGetProtectedContentSupport },
{"nativeReparent", "(JJJ)V",
(void*)nativeReparent },
- {"nativeCaptureDisplay",
- "(Landroid/view/SurfaceControl$DisplayCaptureArgs;Landroid/view/SurfaceControl$ScreenCaptureListener;)I",
- (void*)nativeCaptureDisplay },
- {"nativeCaptureLayers",
- "(Landroid/view/SurfaceControl$LayerCaptureArgs;Landroid/view/SurfaceControl$ScreenCaptureListener;)I",
- (void*)nativeCaptureLayers },
{"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
(void*)nativeSetInputWindowInfo },
{"nativeSetMetadata", "(JJILandroid/os/Parcel;)V",
@@ -2416,12 +2201,6 @@ int register_android_view_SurfaceControl(JNIEnv* env)
GetFieldIDOrDie(env, modeClazz, "presentationDeadlineNanos", "J");
gDisplayModeClassInfo.group = GetFieldIDOrDie(env, modeClazz, "group", "I");
- jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
- gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
- gRectClassInfo.left = GetFieldIDOrDie(env, rectClazz, "left", "I");
- gRectClassInfo.right = GetFieldIDOrDie(env, rectClazz, "right", "I");
- gRectClassInfo.top = GetFieldIDOrDie(env, rectClazz, "top", "I");
-
jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
@@ -2462,15 +2241,6 @@ int register_android_view_SurfaceControl(JNIEnv* env)
GetMethodIDOrDie(env, deviceProductInfoManufactureDateClazz, "<init>",
"(Ljava/lang/Integer;Ljava/lang/Integer;)V");
- jclass screenshotGraphicsBufferClazz =
- FindClassOrDie(env, "android/view/SurfaceControl$ScreenshotHardwareBuffer");
- gScreenshotHardwareBufferClassInfo.clazz =
- MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz);
- gScreenshotHardwareBufferClassInfo.builder =
- GetStaticMethodIDOrDie(env, screenshotGraphicsBufferClazz, "createFromNative",
- "(Landroid/hardware/HardwareBuffer;IZZ)Landroid/view/"
- "SurfaceControl$ScreenshotHardwareBuffer;");
-
jclass displayedContentSampleClazz = FindClassOrDie(env,
"android/hardware/display/DisplayedContentSample");
gDisplayedContentSampleClassInfo.clazz = MakeGlobalRefOrDie(env, displayedContentSampleClazz);
@@ -2523,46 +2293,6 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMax =
GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRefreshRateMax", "F");
- jclass captureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$CaptureArgs");
- gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
- gCaptureArgsClassInfo.sourceCrop =
- GetFieldIDOrDie(env, captureArgsClazz, "mSourceCrop", "Landroid/graphics/Rect;");
- gCaptureArgsClassInfo.frameScaleX = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScaleX", "F");
- gCaptureArgsClassInfo.frameScaleY = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScaleY", "F");
- gCaptureArgsClassInfo.captureSecureLayers =
- GetFieldIDOrDie(env, captureArgsClazz, "mCaptureSecureLayers", "Z");
- gCaptureArgsClassInfo.allowProtected =
- GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");
- gCaptureArgsClassInfo.uid = GetFieldIDOrDie(env, captureArgsClazz, "mUid", "J");
- gCaptureArgsClassInfo.grayscale = GetFieldIDOrDie(env, captureArgsClazz, "mGrayscale", "Z");
-
- jclass displayCaptureArgsClazz =
- FindClassOrDie(env, "android/view/SurfaceControl$DisplayCaptureArgs");
- gDisplayCaptureArgsClassInfo.displayToken =
- GetFieldIDOrDie(env, displayCaptureArgsClazz, "mDisplayToken", "Landroid/os/IBinder;");
- gDisplayCaptureArgsClassInfo.width =
- GetFieldIDOrDie(env, displayCaptureArgsClazz, "mWidth", "I");
- gDisplayCaptureArgsClassInfo.height =
- GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I");
- gDisplayCaptureArgsClassInfo.useIdentityTransform =
- GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z");
-
- jclass layerCaptureArgsClazz =
- FindClassOrDie(env, "android/view/SurfaceControl$LayerCaptureArgs");
- gLayerCaptureArgsClassInfo.layer =
- GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeLayer", "J");
- gLayerCaptureArgsClassInfo.excludeLayers =
- GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeExcludeLayers", "[J");
- gLayerCaptureArgsClassInfo.childrenOnly =
- GetFieldIDOrDie(env, layerCaptureArgsClazz, "mChildrenOnly", "Z");
-
- jclass screenCaptureListenerClazz =
- FindClassOrDie(env, "android/view/SurfaceControl$ScreenCaptureListener");
- gScreenCaptureListenerClassInfo.clazz = MakeGlobalRefOrDie(env, screenCaptureListenerClazz);
- gScreenCaptureListenerClassInfo.onScreenCaptureComplete =
- GetMethodIDOrDie(env, screenCaptureListenerClazz, "onScreenCaptureComplete",
- "(Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;)V");
-
jclass jankDataClazz =
FindClassOrDie(env, "android/view/SurfaceControl$JankData");
gJankDataClassInfo.clazz = MakeGlobalRefOrDie(env, jankDataClazz);
diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp
new file mode 100644
index 000000000000..3bada15aa834
--- /dev/null
+++ b/core/jni/android_window_ScreenCapture.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ScreenCapture"
+// #define LOG_NDEBUG 0
+
+#include <android/gui/BnScreenCaptureListener.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <ui/GraphicTypes.h>
+
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+#include "jni_common.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+using gui::CaptureArgs;
+
+static struct {
+ jfieldID pixelFormat;
+ jfieldID sourceCrop;
+ jfieldID frameScaleX;
+ jfieldID frameScaleY;
+ jfieldID captureSecureLayers;
+ jfieldID allowProtected;
+ jfieldID uid;
+ jfieldID grayscale;
+} gCaptureArgsClassInfo;
+
+static struct {
+ jfieldID displayToken;
+ jfieldID width;
+ jfieldID height;
+ jfieldID useIdentityTransform;
+} gDisplayCaptureArgsClassInfo;
+
+static struct {
+ jfieldID layer;
+ jfieldID excludeLayers;
+ jfieldID childrenOnly;
+} gLayerCaptureArgsClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID onScreenCaptureComplete;
+} gScreenCaptureListenerClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID builder;
+} gScreenshotHardwareBufferClassInfo;
+
+enum JNamedColorSpace : jint {
+ // ColorSpace.Named.SRGB.ordinal() = 0;
+ SRGB = 0,
+
+ // ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
+ DISPLAY_P3 = 7,
+};
+
+constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
+ switch (dataspace) {
+ case ui::Dataspace::DISPLAY_P3:
+ return JNamedColorSpace::DISPLAY_P3;
+ default:
+ return JNamedColorSpace::SRGB;
+ }
+}
+
+static void checkAndClearException(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ env->ExceptionClear();
+ }
+}
+
+class ScreenCaptureListenerWrapper : public gui::BnScreenCaptureListener {
+public:
+ explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) {
+ env->GetJavaVM(&mVm);
+ mScreenCaptureListenerObject = env->NewGlobalRef(jobject);
+ LOG_ALWAYS_FATAL_IF(!mScreenCaptureListenerObject, "Failed to make global ref");
+ }
+
+ ~ScreenCaptureListenerWrapper() {
+ if (mScreenCaptureListenerObject) {
+ getenv()->DeleteGlobalRef(mScreenCaptureListenerObject);
+ mScreenCaptureListenerObject = nullptr;
+ }
+ }
+
+ binder::Status onScreenCaptureCompleted(
+ const gui::ScreenCaptureResults& captureResults) override {
+ JNIEnv* env = getenv();
+ if (!captureResults.fenceResult.ok() || captureResults.buffer == nullptr) {
+ env->CallVoidMethod(mScreenCaptureListenerObject,
+ gScreenCaptureListenerClassInfo.onScreenCaptureComplete, nullptr);
+ checkAndClearException(env, "onScreenCaptureComplete");
+ return binder::Status::ok();
+ }
+ captureResults.fenceResult.value()->waitForever(LOG_TAG);
+ jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
+ env, captureResults.buffer->toAHardwareBuffer());
+ const jint namedColorSpace =
+ fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
+ jobject screenshotHardwareBuffer =
+ env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
+ gScreenshotHardwareBufferClassInfo.builder,
+ jhardwareBuffer, namedColorSpace,
+ captureResults.capturedSecureLayers,
+ captureResults.capturedHdrLayers);
+ checkAndClearException(env, "builder");
+ env->CallVoidMethod(mScreenCaptureListenerObject,
+ gScreenCaptureListenerClassInfo.onScreenCaptureComplete,
+ screenshotHardwareBuffer);
+ checkAndClearException(env, "onScreenCaptureComplete");
+ env->DeleteLocalRef(jhardwareBuffer);
+ env->DeleteLocalRef(screenshotHardwareBuffer);
+ return binder::Status::ok();
+ }
+
+private:
+ jobject mScreenCaptureListenerObject;
+ JavaVM* mVm;
+
+ JNIEnv* getenv() {
+ JNIEnv* env;
+ if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+ }
+ }
+ return env;
+ }
+};
+
+static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs& captureArgs) {
+ captureArgs.pixelFormat = static_cast<ui::PixelFormat>(
+ env->GetIntField(captureArgsObject, gCaptureArgsClassInfo.pixelFormat));
+ captureArgs.sourceCrop =
+ JNICommon::rectFromObj(env,
+ env->GetObjectField(captureArgsObject,
+ gCaptureArgsClassInfo.sourceCrop));
+ captureArgs.frameScaleX =
+ env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScaleX);
+ captureArgs.frameScaleY =
+ env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScaleY);
+ captureArgs.captureSecureLayers =
+ env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.captureSecureLayers);
+ captureArgs.allowProtected =
+ env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.allowProtected);
+ captureArgs.uid = env->GetLongField(captureArgsObject, gCaptureArgsClassInfo.uid);
+ captureArgs.grayscale =
+ env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.grayscale);
+}
+
+static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
+ jobject displayCaptureArgsObject) {
+ DisplayCaptureArgs captureArgs;
+ getCaptureArgs(env, displayCaptureArgsObject, captureArgs);
+
+ captureArgs.displayToken =
+ ibinderForJavaObject(env,
+ env->GetObjectField(displayCaptureArgsObject,
+ gDisplayCaptureArgsClassInfo.displayToken));
+ captureArgs.width =
+ env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.width);
+ captureArgs.height =
+ env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.height);
+ captureArgs.useIdentityTransform =
+ env->GetBooleanField(displayCaptureArgsObject,
+ gDisplayCaptureArgsClassInfo.useIdentityTransform);
+ return captureArgs;
+}
+
+static jint nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject,
+ jobject screenCaptureListenerObject) {
+ const DisplayCaptureArgs captureArgs =
+ displayCaptureArgsFromObject(env, displayCaptureArgsObject);
+
+ if (captureArgs.displayToken == nullptr) {
+ return BAD_VALUE;
+ }
+
+ sp<IScreenCaptureListener> captureListener =
+ sp<ScreenCaptureListenerWrapper>::make(env, screenCaptureListenerObject);
+ return ScreenshotClient::captureDisplay(captureArgs, captureListener);
+}
+
+static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject,
+ jobject screenCaptureListenerObject) {
+ LayerCaptureArgs captureArgs;
+ getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
+ SurfaceControl* layer = reinterpret_cast<SurfaceControl*>(
+ env->GetLongField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.layer));
+ if (layer == nullptr) {
+ return BAD_VALUE;
+ }
+
+ captureArgs.layerHandle = layer->getHandle();
+ captureArgs.childrenOnly =
+ env->GetBooleanField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.childrenOnly);
+
+ jlongArray excludeObjectArray = reinterpret_cast<jlongArray>(
+ env->GetObjectField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.excludeLayers));
+ if (excludeObjectArray != nullptr) {
+ ScopedLongArrayRO excludeArray(env, excludeObjectArray);
+ const jsize len = excludeArray.size();
+ captureArgs.excludeHandles.reserve(len);
+
+ for (jsize i = 0; i < len; i++) {
+ auto excludeObject = reinterpret_cast<SurfaceControl*>(excludeArray[i]);
+ if (excludeObject == nullptr) {
+ jniThrowNullPointerException(env, "Exclude layer is null");
+ return BAD_VALUE;
+ }
+ captureArgs.excludeHandles.emplace(excludeObject->getHandle());
+ }
+ }
+
+ sp<IScreenCaptureListener> captureListener =
+ sp<ScreenCaptureListenerWrapper>::make(env, screenCaptureListenerObject);
+ return ScreenshotClient::captureLayers(captureArgs, captureListener);
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod sScreenCaptureMethods[] = {
+ // clang-format off
+ {"nativeCaptureDisplay",
+ "(Landroid/window/ScreenCapture$DisplayCaptureArgs;Landroid/window/ScreenCapture$ScreenCaptureListener;)I",
+ (void*)nativeCaptureDisplay },
+ {"nativeCaptureLayers",
+ "(Landroid/window/ScreenCapture$LayerCaptureArgs;Landroid/window/ScreenCapture$ScreenCaptureListener;)I",
+ (void*)nativeCaptureLayers },
+ // clang-format on
+};
+
+int register_android_window_ScreenCapture(JNIEnv* env) {
+ int err = RegisterMethodsOrDie(env, "android/window/ScreenCapture", sScreenCaptureMethods,
+ NELEM(sScreenCaptureMethods));
+
+ jclass captureArgsClazz = FindClassOrDie(env, "android/window/ScreenCapture$CaptureArgs");
+ gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
+ gCaptureArgsClassInfo.sourceCrop =
+ GetFieldIDOrDie(env, captureArgsClazz, "mSourceCrop", "Landroid/graphics/Rect;");
+ gCaptureArgsClassInfo.frameScaleX = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScaleX", "F");
+ gCaptureArgsClassInfo.frameScaleY = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScaleY", "F");
+ gCaptureArgsClassInfo.captureSecureLayers =
+ GetFieldIDOrDie(env, captureArgsClazz, "mCaptureSecureLayers", "Z");
+ gCaptureArgsClassInfo.allowProtected =
+ GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");
+ gCaptureArgsClassInfo.uid = GetFieldIDOrDie(env, captureArgsClazz, "mUid", "J");
+ gCaptureArgsClassInfo.grayscale = GetFieldIDOrDie(env, captureArgsClazz, "mGrayscale", "Z");
+
+ jclass displayCaptureArgsClazz =
+ FindClassOrDie(env, "android/window/ScreenCapture$DisplayCaptureArgs");
+ gDisplayCaptureArgsClassInfo.displayToken =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mDisplayToken", "Landroid/os/IBinder;");
+ gDisplayCaptureArgsClassInfo.width =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mWidth", "I");
+ gDisplayCaptureArgsClassInfo.height =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I");
+ gDisplayCaptureArgsClassInfo.useIdentityTransform =
+ GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z");
+
+ jclass layerCaptureArgsClazz =
+ FindClassOrDie(env, "android/window/ScreenCapture$LayerCaptureArgs");
+ gLayerCaptureArgsClassInfo.layer =
+ GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeLayer", "J");
+ gLayerCaptureArgsClassInfo.excludeLayers =
+ GetFieldIDOrDie(env, layerCaptureArgsClazz, "mNativeExcludeLayers", "[J");
+ gLayerCaptureArgsClassInfo.childrenOnly =
+ GetFieldIDOrDie(env, layerCaptureArgsClazz, "mChildrenOnly", "Z");
+
+ jclass screenCaptureListenerClazz =
+ FindClassOrDie(env, "android/window/ScreenCapture$ScreenCaptureListener");
+ gScreenCaptureListenerClassInfo.clazz = MakeGlobalRefOrDie(env, screenCaptureListenerClazz);
+ gScreenCaptureListenerClassInfo.onScreenCaptureComplete =
+ GetMethodIDOrDie(env, screenCaptureListenerClazz, "onScreenCaptureComplete",
+ "(Landroid/window/ScreenCapture$ScreenshotHardwareBuffer;)V");
+
+ jclass screenshotGraphicsBufferClazz =
+ FindClassOrDie(env, "android/window/ScreenCapture$ScreenshotHardwareBuffer");
+ gScreenshotHardwareBufferClassInfo.clazz =
+ MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz);
+ gScreenshotHardwareBufferClassInfo.builder =
+ GetStaticMethodIDOrDie(env, screenshotGraphicsBufferClazz, "createFromNative",
+ "(Landroid/hardware/HardwareBuffer;IZZ)Landroid/window/"
+ "ScreenCapture$ScreenshotHardwareBuffer;");
+
+ return err;
+}
+
+} // namespace android
diff --git a/core/jni/jni_common.cpp b/core/jni/jni_common.cpp
new file mode 100644
index 000000000000..8d376cf2c7f9
--- /dev/null
+++ b/core/jni/jni_common.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "jni_common.h"
+
+#include <jni.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+
+#include "core_jni_helpers.h"
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+static struct {
+ jfieldID bottom;
+ jfieldID left;
+ jfieldID right;
+ jfieldID top;
+} gRectClassInfo;
+
+Rect JNICommon::rectFromObj(JNIEnv* env, jobject rectObj) {
+ int left = env->GetIntField(rectObj, gRectClassInfo.left);
+ int top = env->GetIntField(rectObj, gRectClassInfo.top);
+ int right = env->GetIntField(rectObj, gRectClassInfo.right);
+ int bottom = env->GetIntField(rectObj, gRectClassInfo.bottom);
+ return Rect(left, top, right, bottom);
+}
+
+int register_jni_common(JNIEnv* env) {
+ jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
+ gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
+ gRectClassInfo.left = GetFieldIDOrDie(env, rectClazz, "left", "I");
+ gRectClassInfo.right = GetFieldIDOrDie(env, rectClazz, "right", "I");
+ gRectClassInfo.top = GetFieldIDOrDie(env, rectClazz, "top", "I");
+ return 0;
+}
+
+} // namespace android
diff --git a/core/jni/jni_common.h b/core/jni/jni_common.h
new file mode 100644
index 000000000000..a2bf6fb3f5e0
--- /dev/null
+++ b/core/jni/jni_common.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <jni.h>
+
+namespace android {
+
+class Rect;
+
+class JNICommon {
+public:
+ static Rect rectFromObj(JNIEnv* env, jobject rectObj);
+};
+} // namespace android \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 43679364b443..dec1e38914e2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -44,6 +44,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizerController;
+import android.window.ScreenCapture;
import android.window.StartingWindowInfo;
import android.window.StartingWindowRemovalInfo;
import android.window.TaskAppearedInfo;
@@ -474,7 +475,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
* Take a screenshot of a task.
*/
public void screenshotTask(RunningTaskInfo taskInfo, Rect crop,
- Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
+ Consumer<ScreenCapture.ScreenshotHardwareBuffer> consumer) {
final TaskAppearedInfo info = mTasks.get(taskInfo.taskId);
if (info == null) {
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index cfbe1b3caf7a..54c91dde7668 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -53,13 +53,13 @@ import android.util.IntProperty;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
-import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
+import android.window.ScreenCapture;
import androidx.annotation.Nullable;
@@ -508,7 +508,7 @@ public class BubbleExpandedView extends LinearLayout {
/** Return a GraphicBuffer with the contents of the task view surface. */
@Nullable
- SurfaceControl.ScreenshotHardwareBuffer snapshotActivitySurface() {
+ ScreenCapture.ScreenshotHardwareBuffer snapshotActivitySurface() {
if (mIsOverflow) {
// For now, just snapshot the view and return it as a hw buffer so that the animation
// code for both the tasks and overflow can be the same
@@ -517,7 +517,7 @@ public class BubbleExpandedView extends LinearLayout {
p.beginRecording(mOverflowView.getWidth(), mOverflowView.getHeight()));
p.endRecording();
Bitmap snapshot = Bitmap.createBitmap(p);
- return new SurfaceControl.ScreenshotHardwareBuffer(
+ return new ScreenCapture.ScreenshotHardwareBuffer(
snapshot.getHardwareBuffer(),
snapshot.getColorSpace(),
false /* containsSecureLayers */,
@@ -526,7 +526,7 @@ public class BubbleExpandedView extends LinearLayout {
if (mTaskView == null || mTaskView.getSurfaceControl() == null) {
return null;
}
- return SurfaceControl.captureLayers(
+ return ScreenCapture.captureLayers(
mTaskView.getSurfaceControl(),
new Rect(0, 0, mTaskView.getWidth(), mTaskView.getHeight()),
1 /* scale */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index aeaf6eda9809..1d2617237ca1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -51,7 +51,6 @@ import android.util.Log;
import android.view.Choreographer;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
@@ -64,6 +63,7 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
+import android.window.ScreenCapture;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -244,7 +244,7 @@ public class BubbleStackView extends FrameLayout
* Buffer containing a screenshot of the animating-out bubble. This is drawn into the
* SurfaceView during animations.
*/
- private SurfaceControl.ScreenshotHardwareBuffer mAnimatingOutBubbleBuffer;
+ private ScreenCapture.ScreenshotHardwareBuffer mAnimatingOutBubbleBuffer;
private BubbleFlyoutView mFlyout;
/** Runnable that fades out the flyout and then sets it to GONE. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
index c4bd73ba1b4a..e6ddda339e84 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ScreenshotUtils.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.common;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.view.SurfaceControl;
+import android.window.ScreenCapture;
import java.util.function.Consumer;
@@ -35,9 +36,9 @@ public class ScreenshotUtils {
* @param consumer Consumer for the captured buffer
*/
public static void captureLayer(SurfaceControl sc, Rect crop,
- Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
- consumer.accept(SurfaceControl.captureLayers(
- new SurfaceControl.LayerCaptureArgs.Builder(sc)
+ Consumer<ScreenCapture.ScreenshotHardwareBuffer> consumer) {
+ consumer.accept(ScreenCapture.captureLayers(
+ new ScreenCapture.LayerCaptureArgs.Builder(sc)
.setSourceCrop(crop)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
@@ -45,7 +46,7 @@ public class ScreenshotUtils {
}
private static class BufferConsumer implements
- Consumer<SurfaceControl.ScreenshotHardwareBuffer> {
+ Consumer<ScreenCapture.ScreenshotHardwareBuffer> {
SurfaceControl mScreenshot = null;
SurfaceControl.Transaction mTransaction;
SurfaceControl mSurfaceControl;
@@ -58,7 +59,7 @@ public class ScreenshotUtils {
}
@Override
- public void accept(SurfaceControl.ScreenshotHardwareBuffer buffer) {
+ public void accept(ScreenCapture.ScreenshotHardwareBuffer buffer) {
if (buffer == null || buffer.getHardwareBuffer() == null) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 4c927b6e84b8..1ae779e25bbf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -96,6 +96,7 @@ import android.view.WindowManager.TransitionType;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
+import android.window.ScreenCapture;
import android.window.TransitionInfo;
import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
@@ -630,16 +631,16 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
.setBufferSize(extensionRect.width(), extensionRect.height())
.build();
- SurfaceControl.LayerCaptureArgs captureArgs =
- new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend)
+ ScreenCapture.LayerCaptureArgs captureArgs =
+ new ScreenCapture.LayerCaptureArgs.Builder(surfaceToExtend)
.setSourceCrop(edgeBounds)
.setFrameScale(1)
.setPixelFormat(PixelFormat.RGBA_8888)
.setChildrenOnly(true)
.setAllowProtected(true)
.build();
- final SurfaceControl.ScreenshotHardwareBuffer edgeBuffer =
- SurfaceControl.captureLayers(captureArgs);
+ final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
+ ScreenCapture.captureLayers(captureArgs);
if (edgeBuffer == null) {
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index b647f43da522..2b27baeb515a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -46,6 +46,7 @@ import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import android.window.ScreenCapture;
import android.window.TransitionInfo;
import com.android.internal.R;
@@ -144,14 +145,14 @@ class ScreenRotationAnimation {
t.reparent(mScreenshotLayer, mAnimLeash);
mStartLuma = change.getSnapshotLuma();
} else {
- SurfaceControl.LayerCaptureArgs args =
- new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+ ScreenCapture.LayerCaptureArgs args =
+ new ScreenCapture.LayerCaptureArgs.Builder(mSurfaceControl)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
.build();
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- SurfaceControl.captureLayers(args);
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ ScreenCapture.captureLayers(args);
if (screenshotBuffer == null) {
Slog.w(TAG, "Unable to take screenshot of display");
return;
@@ -481,8 +482,8 @@ class ScreenRotationAnimation {
}
Rect crop = new Rect(0, 0, bounds.width(), bounds.height());
- SurfaceControl.ScreenshotHardwareBuffer buffer =
- SurfaceControl.captureLayers(surfaceControl, crop, 1);
+ ScreenCapture.ScreenshotHardwareBuffer buffer =
+ ScreenCapture.captureLayers(surfaceControl, crop, 1);
if (buffer == null) {
return 0;
}
diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java
index 85f25528f07e..d55eda0c7062 100644
--- a/packages/Shell/src/com/android/shell/Screenshooter.java
+++ b/packages/Shell/src/com/android/shell/Screenshooter.java
@@ -20,6 +20,7 @@ import android.graphics.Bitmap;
import android.os.IBinder;
import android.util.Log;
import android.view.SurfaceControl;
+import android.window.ScreenCapture;
/**
* Helper class used to take screenshots.
@@ -40,11 +41,11 @@ final class Screenshooter {
Log.d(TAG, "Taking fullscreen screenshot");
// Take the screenshot
final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
- final SurfaceControl.DisplayCaptureArgs captureArgs =
- new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
+ final ScreenCapture.DisplayCaptureArgs captureArgs =
+ new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
.build();
- final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- SurfaceControl.captureDisplay(captureArgs);
+ final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ ScreenCapture.captureDisplay(captureArgs);
final Bitmap screenShot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
if (screenShot == null) {
Log.e(TAG, "Failed to take fullscreen screenshot");
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
index 246265b2c202..ac5640b14716 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
@@ -24,8 +24,9 @@ import android.os.IBinder
import android.util.Log
import android.view.DisplayAddress
import android.view.SurfaceControl
-import android.view.SurfaceControl.DisplayCaptureArgs
-import android.view.SurfaceControl.ScreenshotHardwareBuffer
+import android.window.ScreenCapture
+import android.window.ScreenCapture.DisplayCaptureArgs
+import android.window.ScreenCapture.ScreenshotHardwareBuffer
import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -84,6 +85,6 @@ open class ImageCaptureImpl @Inject constructor(
.setSize(width, height)
.setSourceCrop(crop)
.build()
- return SurfaceControl.captureDisplay(captureArgs)
+ return ScreenCapture.captureDisplay(captureArgs)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
index 00f38081c5c9..5a4bafcb7ded 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
@@ -23,7 +23,7 @@ import android.os.Binder
import android.os.IBinder
import android.testing.AndroidTestingRunner
import android.view.Display
-import android.view.SurfaceControl.ScreenshotHardwareBuffer
+import android.window.ScreenCapture.ScreenshotHardwareBuffer
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
@@ -84,7 +84,12 @@ class ImageCaptureImplTest : SysuiTestCase() {
this.width = width
this.height = height
this.crop = crop
- return ScreenshotHardwareBuffer(null, null, false, false)
+ return ScreenshotHardwareBuffer(
+ null,
+ null,
+ false,
+ false
+ )
}
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 3324c526ecc2..799c759b96d2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -75,7 +75,6 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
-import android.view.SurfaceControl.ScreenshotHardwareBuffer;
import android.view.View;
import android.view.WindowInfo;
import android.view.accessibility.AccessibilityCache;
@@ -84,6 +83,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import android.view.inputmethod.EditorInfo;
+import android.window.ScreenCapture.ScreenshotHardwareBuffer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.compat.IPlatformCompat;
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 0f5aa3a08950..4aaf1abf4147 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -52,6 +52,7 @@ import android.util.Slog;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost.SurfacePackage;
import android.view.WindowManager;
+import android.window.ScreenCapture;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -843,8 +844,8 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
final SurfaceControl overlaySurfaceControl =
overlaySurfacePackage != null ? overlaySurfacePackage.getSurfaceControl() : null;
mBackgroundExecutor.execute(() -> {
- final SurfaceControl.LayerCaptureArgs.Builder layerCaptureArgsBuilder =
- new SurfaceControl.LayerCaptureArgs.Builder(/* layer */ null);
+ final ScreenCapture.LayerCaptureArgs.Builder layerCaptureArgsBuilder =
+ new ScreenCapture.LayerCaptureArgs.Builder(/* layer */ null);
if (overlaySurfaceControl != null) {
SurfaceControl[] excludeLayers = new SurfaceControl[1];
excludeLayers[0] = overlaySurfaceControl;
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index cb04ddfd636d..2f67dddc1bf5 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -39,6 +39,7 @@ import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
+import android.window.ScreenCapture;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
@@ -181,7 +182,7 @@ final class ColorFade {
// Set mPrepared here so if initialization fails, resources can be cleaned up.
mPrepared = true;
- final SurfaceControl.ScreenshotHardwareBuffer hardwareBuffer = captureScreen();
+ final ScreenCapture.ScreenshotHardwareBuffer hardwareBuffer = captureScreen();
if (hardwareBuffer == null) {
dismiss();
return false;
@@ -508,7 +509,7 @@ final class ColorFade {
}
private boolean setScreenshotTextureAndSetViewport(
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer) {
if (!attachEglContext()) {
return false;
}
@@ -559,8 +560,8 @@ final class ColorFade {
}
}
- private SurfaceControl.ScreenshotHardwareBuffer captureScreen() {
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+ private ScreenCapture.ScreenshotHardwareBuffer captureScreen() {
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
mDisplayManagerInternal.systemScreenshot(mDisplayId);
if (screenshotBuffer == null) {
Slog.e(TAG, "Failed to take screenshot. Buffer is null");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e53ac379536b..8e72294c31d4 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -118,6 +118,7 @@ import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.DisplayWindowPolicyController;
+import android.window.ScreenCapture;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -2049,8 +2050,8 @@ public final class DisplayManagerService extends SystemService {
return null;
}
- private SurfaceControl.ScreenshotHardwareBuffer systemScreenshotInternal(int displayId) {
- final SurfaceControl.DisplayCaptureArgs captureArgs;
+ private ScreenCapture.ScreenshotHardwareBuffer systemScreenshotInternal(int displayId) {
+ final ScreenCapture.DisplayCaptureArgs captureArgs;
synchronized (mSyncRoot) {
final IBinder token = getDisplayToken(displayId);
if (token == null) {
@@ -2062,27 +2063,27 @@ public final class DisplayManagerService extends SystemService {
}
final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
- captureArgs = new SurfaceControl.DisplayCaptureArgs.Builder(token)
+ captureArgs = new ScreenCapture.DisplayCaptureArgs.Builder(token)
.setSize(displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight())
.setUseIdentityTransform(true)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.build();
}
- return SurfaceControl.captureDisplay(captureArgs);
+ return ScreenCapture.captureDisplay(captureArgs);
}
- private SurfaceControl.ScreenshotHardwareBuffer userScreenshotInternal(int displayId) {
+ private ScreenCapture.ScreenshotHardwareBuffer userScreenshotInternal(int displayId) {
synchronized (mSyncRoot) {
final IBinder token = getDisplayToken(displayId);
if (token == null) {
return null;
}
- final SurfaceControl.DisplayCaptureArgs captureArgs =
- new SurfaceControl.DisplayCaptureArgs.Builder(token)
+ final ScreenCapture.DisplayCaptureArgs captureArgs =
+ new ScreenCapture.DisplayCaptureArgs.Builder(token)
.build();
- return SurfaceControl.captureDisplay(captureArgs);
+ return ScreenCapture.captureDisplay(captureArgs);
}
}
@@ -3564,12 +3565,12 @@ public final class DisplayManagerService extends SystemService {
}
@Override
- public SurfaceControl.ScreenshotHardwareBuffer systemScreenshot(int displayId) {
+ public ScreenCapture.ScreenshotHardwareBuffer systemScreenshot(int displayId) {
return systemScreenshotInternal(displayId);
}
@Override
- public SurfaceControl.ScreenshotHardwareBuffer userScreenshot(int displayId) {
+ public ScreenCapture.ScreenshotHardwareBuffer userScreenshot(int displayId) {
return userScreenshotInternal(displayId);
}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index d9ab971c9a78..a3f5401fd375 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -36,6 +36,7 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.BackNavigationInfo;
import android.window.OnBackInvokedCallbackInfo;
+import android.window.ScreenCapture;
import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
@@ -422,7 +423,7 @@ class BackNavigationController {
ComponentName activityComponent) {
// Check if we have a screenshot of the previous activity, indexed by its
// component name.
- SurfaceControl.ScreenshotHardwareBuffer backBuffer = task.mBackScreenshots
+ ScreenCapture.ScreenshotHardwareBuffer backBuffer = task.mBackScreenshots
.get(activityComponent.flattenToString());
return backBuffer != null ? backBuffer.getHardwareBuffer() : null;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7471993545a7..21f6dca10baf 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -231,6 +231,7 @@ import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import android.window.DisplayWindowPolicyController;
import android.window.IDisplayAreaOrganizer;
+import android.window.ScreenCapture;
import android.window.TransitionRequestInfo;
import com.android.internal.R;
@@ -4243,7 +4244,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mImeTarget;
}
- private SurfaceControl createImeSurface(SurfaceControl.ScreenshotHardwareBuffer b,
+ private SurfaceControl createImeSurface(ScreenCapture.ScreenshotHardwareBuffer b,
Transaction t) {
final HardwareBuffer buffer = b.getHardwareBuffer();
ProtoLog.i(WM_DEBUG_IME, "create IME snapshot for %s, buff width=%s, height=%s",
@@ -4305,7 +4306,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|| mImeSurface.getWidth() != dc.mInputMethodWindow.getFrame().width()
|| mImeSurface.getHeight() != dc.mInputMethodWindow.getFrame().height();
if (task != null && !task.isActivityTypeHomeOrRecents()) {
- SurfaceControl.ScreenshotHardwareBuffer imeBuffer = renewImeSurface
+ ScreenCapture.ScreenshotHardwareBuffer imeBuffer = renewImeSurface
? dc.mWmService.mTaskSnapshotController.snapshotImeFromAttachedTask(task)
: null;
if (imeBuffer != null) {
@@ -4914,12 +4915,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Send invalid rect and no width and height since it will screenshot the entire display.
final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
- final SurfaceControl.DisplayCaptureArgs captureArgs =
- new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
+ final ScreenCapture.DisplayCaptureArgs captureArgs =
+ new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
.setUseIdentityTransform(inRotation)
.build();
- final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- SurfaceControl.captureDisplay(captureArgs);
+ final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ ScreenCapture.captureDisplay(captureArgs);
final Bitmap bitmap = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
if (bitmap == null) {
Slog.w(TAG_WM, "Failed to take screenshot");
diff --git a/services/core/java/com/android/server/wm/DisplayHashController.java b/services/core/java/com/android/server/wm/DisplayHashController.java
index 543d4ad6b507..1a8b43403b25 100644
--- a/services/core/java/com/android/server/wm/DisplayHashController.java
+++ b/services/core/java/com/android/server/wm/DisplayHashController.java
@@ -53,9 +53,9 @@ import android.service.displayhash.IDisplayHashingService;
import android.util.Size;
import android.util.Slog;
import android.view.MagnificationSpec;
-import android.view.SurfaceControl;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
+import android.window.ScreenCapture;
import com.android.internal.annotations.GuardedBy;
@@ -194,7 +194,7 @@ public class DisplayHashController {
return true;
}
- void generateDisplayHash(SurfaceControl.LayerCaptureArgs.Builder args,
+ void generateDisplayHash(ScreenCapture.LayerCaptureArgs.Builder args,
Rect boundsInWindow, String hashAlgorithm, int uid, RemoteCallback callback) {
if (!allowedToGenerateHash(uid)) {
sendDisplayHashError(callback, DISPLAY_HASH_ERROR_TOO_MANY_REQUESTS);
@@ -217,8 +217,8 @@ public class DisplayHashController {
args.setGrayscale(displayHashParams.isGrayscaleBuffer());
- SurfaceControl.ScreenshotHardwareBuffer screenshotHardwareBuffer =
- SurfaceControl.captureLayers(args.build());
+ ScreenCapture.ScreenshotHardwareBuffer screenshotHardwareBuffer =
+ ScreenCapture.captureLayers(args.build());
if (screenshotHardwareBuffer == null
|| screenshotHardwareBuffer.getHardwareBuffer() == null) {
Slog.w(TAG, "Failed to generate DisplayHash. Couldn't capture content");
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index fd8b614de9b7..24d4e981e9ce 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -52,6 +52,7 @@ import android.view.SurfaceControl;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
+import android.window.ScreenCapture;
import com.android.internal.R;
import com.android.internal.protolog.common.ProtoLog;
@@ -167,7 +168,7 @@ class ScreenRotationAnimation {
final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
try {
- final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer;
+ final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer;
if (isSizeChanged) {
final DisplayAddress address = displayInfo.address;
if (!(address instanceof DisplayAddress.Physical)) {
@@ -186,22 +187,22 @@ class ScreenRotationAnimation {
// the whole display to include the rounded corner overlays.
setSkipScreenshotForRoundedCornerOverlays(false, t);
mRoundedCornerOverlay = displayContent.findRoundedCornerOverlays();
- final SurfaceControl.DisplayCaptureArgs captureArgs =
- new SurfaceControl.DisplayCaptureArgs.Builder(displayToken)
+ final ScreenCapture.DisplayCaptureArgs captureArgs =
+ new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
.setSourceCrop(new Rect(0, 0, width, height))
.setAllowProtected(true)
.setCaptureSecureLayers(true)
.build();
- screenshotBuffer = SurfaceControl.captureDisplay(captureArgs);
+ screenshotBuffer = ScreenCapture.captureDisplay(captureArgs);
} else {
- SurfaceControl.LayerCaptureArgs captureArgs =
- new SurfaceControl.LayerCaptureArgs.Builder(
+ ScreenCapture.LayerCaptureArgs captureArgs =
+ new ScreenCapture.LayerCaptureArgs.Builder(
displayContent.getSurfaceControl())
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, width, height))
.build();
- screenshotBuffer = SurfaceControl.captureLayers(captureArgs);
+ screenshotBuffer = ScreenCapture.captureLayers(captureArgs);
}
if (screenshotBuffer == null) {
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index f3670e49f01e..94d4ddeb465c 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -45,6 +45,7 @@ import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.animation.Animation;
import android.view.animation.Transformation;
+import android.window.ScreenCapture;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -433,16 +434,16 @@ class SurfaceAnimationRunner {
private void doCreateExtensionSurface(SurfaceControl leash, Rect edgeBounds,
Rect extensionRect, int xPos, int yPos, String layerName,
Transaction startTransaction) {
- SurfaceControl.LayerCaptureArgs captureArgs =
- new SurfaceControl.LayerCaptureArgs.Builder(leash /* surfaceToExtend */)
+ ScreenCapture.LayerCaptureArgs captureArgs =
+ new ScreenCapture.LayerCaptureArgs.Builder(leash /* surfaceToExtend */)
.setSourceCrop(edgeBounds)
.setFrameScale(1)
.setPixelFormat(PixelFormat.RGBA_8888)
.setChildrenOnly(true)
.setAllowProtected(true)
.build();
- final SurfaceControl.ScreenshotHardwareBuffer edgeBuffer =
- SurfaceControl.captureLayers(captureArgs);
+ final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
+ ScreenCapture.captureLayers(captureArgs);
if (edgeBuffer == null) {
// The leash we are trying to screenshot may have been removed by this point, which is
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index a7ef36b01d91..0c36d27603c8 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -28,6 +28,7 @@ import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.util.Slog;
import android.view.SurfaceControl;
+import android.window.ScreenCapture;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -89,7 +90,7 @@ class SurfaceFreezer {
freezeTarget = freezeTarget != null ? freezeTarget : mAnimatable.getFreezeSnapshotTarget();
if (freezeTarget != null) {
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBufferInner(
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBufferInner(
freezeTarget, startBounds);
final HardwareBuffer buffer = screenshotBuffer == null ? null
: screenshotBuffer.getHardwareBuffer();
@@ -183,31 +184,31 @@ class SurfaceFreezer {
return mLeash != null;
}
- private static SurfaceControl.ScreenshotHardwareBuffer createSnapshotBuffer(
+ private static ScreenCapture.ScreenshotHardwareBuffer createSnapshotBuffer(
@NonNull SurfaceControl target, @Nullable Rect bounds) {
Rect cropBounds = null;
if (bounds != null) {
cropBounds = new Rect(bounds);
cropBounds.offsetTo(0, 0);
}
- SurfaceControl.LayerCaptureArgs captureArgs =
- new SurfaceControl.LayerCaptureArgs.Builder(target)
+ ScreenCapture.LayerCaptureArgs captureArgs =
+ new ScreenCapture.LayerCaptureArgs.Builder(target)
.setSourceCrop(cropBounds)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.build();
- return SurfaceControl.captureLayers(captureArgs);
+ return ScreenCapture.captureLayers(captureArgs);
}
@VisibleForTesting
- SurfaceControl.ScreenshotHardwareBuffer createSnapshotBufferInner(
+ ScreenCapture.ScreenshotHardwareBuffer createSnapshotBufferInner(
SurfaceControl target, Rect bounds) {
return createSnapshotBuffer(target, bounds);
}
@VisibleForTesting
GraphicBuffer createFromHardwareBufferInner(
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer) {
return GraphicBuffer.createFromHardwareBuffer(screenshotBuffer.getHardwareBuffer());
}
@@ -220,7 +221,7 @@ class SurfaceFreezer {
* @param screenshotBuffer A thumbnail or placeholder for thumbnail to initialize with.
*/
Snapshot(SurfaceControl.Transaction t,
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
GraphicBuffer graphicBuffer = createFromHardwareBufferInner(screenshotBuffer);
mSurfaceControl = mAnimatable.makeAnimationLeash()
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 1f6690ac5c51..d49956b09d96 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -89,6 +89,7 @@ import android.view.DisplayInfo;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
+import android.window.ScreenCapture;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizerToken;
@@ -306,7 +307,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
//TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
// implemented
- HashMap<String, SurfaceControl.ScreenshotHardwareBuffer> mBackScreenshots = new HashMap<>();
+ HashMap<String, ScreenCapture.ScreenshotHardwareBuffer> mBackScreenshots = new HashMap<>();
private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
new EnsureActivitiesVisibleHelper(this);
@@ -1859,7 +1860,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
r.mActivityComponent.flattenToString());
Rect outBounds = r.getBounds();
- SurfaceControl.ScreenshotHardwareBuffer backBuffer = SurfaceControl.captureLayers(
+ ScreenCapture.ScreenshotHardwareBuffer backBuffer = ScreenCapture.captureLayers(
r.mSurfaceControl,
new Rect(0, 0, outBounds.width(), outBounds.height()),
1f);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 534616fb7207..9306749f17b9 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -58,6 +58,7 @@ import android.view.ThreadedRenderer;
import android.view.WindowInsets.Type;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager.LayoutParams;
+import android.window.ScreenCapture;
import android.window.TaskSnapshot;
import com.android.internal.R;
@@ -389,11 +390,11 @@ class TaskSnapshotController {
}
@Nullable
- SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
+ ScreenCapture.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
TaskSnapshot.Builder builder) {
Point taskSize = new Point();
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "createTaskSnapshot");
- final SurfaceControl.ScreenshotHardwareBuffer taskSnapshot = createTaskSnapshot(task,
+ final ScreenCapture.ScreenshotHardwareBuffer taskSnapshot = createTaskSnapshot(task,
mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize, builder);
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
builder.setTaskSize(taskSize);
@@ -401,7 +402,7 @@ class TaskSnapshotController {
}
@Nullable
- private SurfaceControl.ScreenshotHardwareBuffer createImeSnapshot(@NonNull Task task,
+ private ScreenCapture.ScreenshotHardwareBuffer createImeSnapshot(@NonNull Task task,
int pixelFormat) {
if (task.getSurfaceControl() == null) {
if (DEBUG_SCREENSHOT) {
@@ -410,11 +411,11 @@ class TaskSnapshotController {
return null;
}
final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow;
- SurfaceControl.ScreenshotHardwareBuffer imeBuffer = null;
+ ScreenCapture.ScreenshotHardwareBuffer imeBuffer = null;
if (imeWindow != null && imeWindow.isWinVisibleLw()) {
final Rect bounds = imeWindow.getParentFrame();
bounds.offsetTo(0, 0);
- imeBuffer = SurfaceControl.captureLayersExcluding(imeWindow.getSurfaceControl(),
+ imeBuffer = ScreenCapture.captureLayersExcluding(imeWindow.getSurfaceControl(),
bounds, 1.0f, pixelFormat, null);
}
return imeBuffer;
@@ -425,7 +426,7 @@ class TaskSnapshotController {
* task to keep IME visibility while app transitioning.
*/
@Nullable
- SurfaceControl.ScreenshotHardwareBuffer snapshotImeFromAttachedTask(@NonNull Task task) {
+ ScreenCapture.ScreenshotHardwareBuffer snapshotImeFromAttachedTask(@NonNull Task task) {
// Check if the IME targets task ready to take the corresponding IME snapshot, if not,
// means the task is not yet visible for some reasons and no need to snapshot IME surface.
if (checkIfReadyToSnapshot(task) == null) {
@@ -438,7 +439,7 @@ class TaskSnapshotController {
}
@Nullable
- SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
+ ScreenCapture.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
float scaleFraction, int pixelFormat, Point outTaskSize, TaskSnapshot.Builder builder) {
if (task.getSurfaceControl() == null) {
if (DEBUG_SCREENSHOT) {
@@ -473,8 +474,8 @@ class TaskSnapshotController {
}
builder.setHasImeSurface(!excludeIme && imeWindow != null && imeWindow.isVisible());
- final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- SurfaceControl.captureLayersExcluding(
+ final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ ScreenCapture.captureLayersExcluding(
task.getSurfaceControl(), mTmpRect, scaleFraction,
pixelFormat, excludeLayers);
if (outTaskSize != null) {
@@ -508,7 +509,7 @@ class TaskSnapshotController {
return null;
}
- final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+ final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
createTaskSnapshot(task, builder);
if (screenshotBuffer == null) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 32b753241cab..e241723cefb8 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -77,6 +77,7 @@ import android.view.Display;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.RemoteTransition;
+import android.window.ScreenCapture;
import android.window.TransitionInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -2105,14 +2106,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
Rect cropBounds = new Rect(bounds);
cropBounds.offsetTo(0, 0);
- SurfaceControl.LayerCaptureArgs captureArgs =
- new SurfaceControl.LayerCaptureArgs.Builder(wc.getSurfaceControl())
+ ScreenCapture.LayerCaptureArgs captureArgs =
+ new ScreenCapture.LayerCaptureArgs.Builder(wc.getSurfaceControl())
.setSourceCrop(cropBounds)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.build();
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- SurfaceControl.captureLayers(captureArgs);
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ ScreenCapture.captureLayers(captureArgs);
final HardwareBuffer buffer = screenshotBuffer == null ? null
: screenshotBuffer.getHardwareBuffer();
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index d652b8e0ab32..0fd3e9b4abae 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -53,6 +53,7 @@ import android.view.DisplayInfo;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.animation.Animation;
+import android.window.ScreenCapture;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogImpl;
@@ -931,7 +932,7 @@ class WallpaperController {
final Rect bounds = wallpaperWindowState.getBounds();
bounds.offsetTo(0, 0);
- SurfaceControl.ScreenshotHardwareBuffer wallpaperBuffer = SurfaceControl.captureLayers(
+ ScreenCapture.ScreenshotHardwareBuffer wallpaperBuffer = ScreenCapture.captureLayers(
wallpaperWindowState.getSurfaceControl(), bounds, 1 /* frameScale */);
if (wallpaperBuffer == null) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index bc668526b24c..8cc0d5dd8c1b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -622,7 +622,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
setInitialSurfaceControlProperties(makeSurface());
}
- void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
+ void setInitialSurfaceControlProperties(Builder b) {
setSurfaceControl(b.setCallsite("WindowContainer.setInitialSurfaceControlProperties").build());
if (showSurfaceOnCreation()) {
getSyncTransaction().show(mSurfaceControl);
@@ -652,7 +652,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
mLastSurfacePosition.set(0, 0);
mLastDeltaRotation = Surface.ROTATION_0;
- final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(null)
+ final Builder b = mWmService.makeSurfaceBuilder(null)
.setContainerLayer()
.setName(getName());
@@ -2437,7 +2437,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
} while (current != null);
}
- SurfaceControl.Builder makeSurface() {
+ Builder makeSurface() {
final WindowContainer p = getParent();
return p.makeChildSurface(this);
}
@@ -2446,7 +2446,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* @param child The WindowContainer this child surface is for, or null if the Surface
* is not assosciated with a WindowContainer (e.g. a surface used for Dimming).
*/
- SurfaceControl.Builder makeChildSurface(WindowContainer child) {
+ Builder makeChildSurface(WindowContainer child) {
final WindowContainer p = getParent();
// Give the parent a chance to set properties. In hierarchy v1 we rely
// on this to set full-screen dimensions on all our Surface-less Layers.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5ad6fbd69d7e..88d6d851fc1c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -289,6 +289,7 @@ import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import android.window.ClientWindowFrames;
import android.window.ITaskFpsCallback;
+import android.window.ScreenCapture;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
@@ -3980,7 +3981,7 @@ public class WindowManagerService extends IWindowManager.Stub
* Generates and returns an up-to-date {@link Bitmap} for the specified taskId.
*
* @param taskId The task ID of the task for which a Bitmap is requested.
- * @param layerCaptureArgsBuilder A {@link SurfaceControl.LayerCaptureArgs.Builder} with
+ * @param layerCaptureArgsBuilder A {@link ScreenCapture.LayerCaptureArgs.Builder} with
* arguments for how to capture the Bitmap. The caller can
* specify any arguments, but this method will ensure that the
* specified task's SurfaceControl is used and the crop is set to
@@ -3990,7 +3991,7 @@ public class WindowManagerService extends IWindowManager.Stub
*/
@Nullable
public Bitmap captureTaskBitmap(int taskId,
- @NonNull SurfaceControl.LayerCaptureArgs.Builder layerCaptureArgsBuilder) {
+ @NonNull ScreenCapture.LayerCaptureArgs.Builder layerCaptureArgsBuilder) {
if (mTaskSnapshotController.shouldDisableSnapshots()) {
return null;
}
@@ -4009,7 +4010,7 @@ public class WindowManagerService extends IWindowManager.Stub
mTmpRect.offsetTo(0, 0);
final SurfaceControl sc = task.getSurfaceControl();
- final SurfaceControl.ScreenshotHardwareBuffer buffer = SurfaceControl.captureLayers(
+ final ScreenCapture.ScreenshotHardwareBuffer buffer = ScreenCapture.captureLayers(
layerCaptureArgsBuilder.setLayer(sc).setSourceCrop(mTmpRect).build());
if (buffer == null) {
Slog.w(TAG, "Could not get screenshot buffer for taskId: " + taskId);
@@ -9085,8 +9086,8 @@ public class WindowManagerService extends IWindowManager.Stub
// be covering it with the same uid. We want to make sure we include content that's
// covering to ensure we get as close as possible to what the user sees
final int uid = session.mUid;
- SurfaceControl.LayerCaptureArgs.Builder args =
- new SurfaceControl.LayerCaptureArgs.Builder(displaySurfaceControl)
+ ScreenCapture.LayerCaptureArgs.Builder args =
+ new ScreenCapture.LayerCaptureArgs.Builder(displaySurfaceControl)
.setUid(uid)
.setSourceCrop(boundsInDisplay);
diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
index 261dda7ab15d..b93b8d866a00 100644
--- a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
+++ b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java
@@ -30,6 +30,7 @@ import android.media.ImageReader;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.window.ScreenCapture;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -118,8 +119,8 @@ public class RotationAnimationUtils {
Point size = new Point();
display.getSize(size);
Rect crop = new Rect(0, 0, size.x, size.y);
- SurfaceControl.ScreenshotHardwareBuffer buffer =
- SurfaceControl.captureLayers(surfaceControl, crop, 1);
+ ScreenCapture.ScreenshotHardwareBuffer buffer =
+ ScreenCapture.captureLayers(surfaceControl, crop, 1);
if (buffer == null) {
return 0;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 7244d9492deb..8d377558130c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -139,6 +139,7 @@ import android.view.View;
import android.view.WindowManager;
import android.window.DisplayAreaInfo;
import android.window.IDisplayAreaOrganizer;
+import android.window.ScreenCapture;
import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
@@ -2124,8 +2125,8 @@ public class DisplayContentTests extends WindowTestsBase {
// Preparation: Simulate snapshot IME surface.
spyOn(mWm.mTaskSnapshotController);
- SurfaceControl.ScreenshotHardwareBuffer mockHwBuffer = mock(
- SurfaceControl.ScreenshotHardwareBuffer.class);
+ ScreenCapture.ScreenshotHardwareBuffer mockHwBuffer = mock(
+ ScreenCapture.ScreenshotHardwareBuffer.class);
doReturn(mock(HardwareBuffer.class)).when(mockHwBuffer).getHardwareBuffer();
doReturn(mockHwBuffer).when(mWm.mTaskSnapshotController).snapshotImeFromAttachedTask(any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
index f542e290c701..0b58428e9bfb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenshotTests.java
@@ -36,6 +36,7 @@ import android.platform.test.annotations.Presubmit;
import android.view.PointerIcon;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import android.window.ScreenCapture;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
@@ -98,11 +99,11 @@ public class ScreenshotTests {
.setColorSpace(secureSC, ColorSpace.get(ColorSpace.Named.SRGB))
.apply(true);
- SurfaceControl.LayerCaptureArgs args = new SurfaceControl.LayerCaptureArgs.Builder(secureSC)
+ ScreenCapture.LayerCaptureArgs args = new ScreenCapture.LayerCaptureArgs.Builder(secureSC)
.setCaptureSecureLayers(true)
.setChildrenOnly(false)
.build();
- SurfaceControl.ScreenshotHardwareBuffer hardwareBuffer = SurfaceControl.captureLayers(args);
+ ScreenCapture.ScreenshotHardwareBuffer hardwareBuffer = ScreenCapture.captureLayers(args);
assertNotNull(hardwareBuffer);
Bitmap screenshot = hardwareBuffer.asBitmap();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index ff0063c4ffa0..6c8a7ac0c613 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -361,7 +361,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
@Override
public Builder makeAnimationLeash() {
- return new SurfaceControl.Builder(mSession) {
+ return new Builder(mSession) {
@Override
public SurfaceControl build() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 353b757e985e..4293d487bcc2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -97,6 +97,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
import android.window.ITransitionPlayer;
+import android.window.ScreenCapture;
import android.window.StartingWindowInfo;
import android.window.StartingWindowRemovalInfo;
import android.window.TaskFragmentOrganizer;
@@ -946,8 +947,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
/** Mocks the behavior of taking a snapshot. */
void mockSurfaceFreezerSnapshot(SurfaceFreezer surfaceFreezer) {
- final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
- mock(SurfaceControl.ScreenshotHardwareBuffer.class);
+ final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ mock(ScreenCapture.ScreenshotHardwareBuffer.class);
final HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
spyOn(surfaceFreezer);
doReturn(screenshotBuffer).when(surfaceFreezer)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 77fca451547d..a95fa5a4e978 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -147,7 +147,7 @@ public class ZOrderingTests extends WindowTestsBase {
}
private static class HierarchyRecordingBuilderFactory implements Function<SurfaceSession,
- SurfaceControl.Builder> {
+ SurfaceControl.Builder> {
private LayerRecordingTransaction mTransaction;
HierarchyRecordingBuilderFactory(LayerRecordingTransaction transaction) {