diff options
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) { |