diff options
-rw-r--r-- | cmds/screencap/screencap.cpp | 3 | ||||
-rw-r--r-- | core/java/android/view/SurfaceControl.java | 186 | ||||
-rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 117 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/DisplayContent.java | 2 |
4 files changed, 71 insertions, 237 deletions
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index b11e84322dde..11029e75d46a 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -198,8 +198,7 @@ int main(int argc, char** argv) sp<GraphicBuffer> outBuffer; status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */, - 0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation, - &outBuffer); + 0 /* reqHeight */, false, captureOrientation, &outBuffer); if (result != NO_ERROR) { close(fd); return 1; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 79eafa80454a..7271a9e4616f 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -70,15 +70,8 @@ public class SurfaceControl implements Parcelable { private static native void nativeDestroy(long nativeObject); private static native void nativeDisconnect(long nativeObject); - private static native Bitmap nativeScreenshot(IBinder displayToken, - Rect sourceCrop, int width, int height, int minLayer, int maxLayer, - boolean allLayers, boolean useIdentityTransform, int rotation); - private static native GraphicBuffer nativeScreenshotToBuffer(IBinder displayToken, - Rect sourceCrop, int width, int height, int minLayer, int maxLayer, - boolean allLayers, boolean useIdentityTransform, int rotation); - private static native void nativeScreenshot(IBinder displayToken, Surface consumer, - Rect sourceCrop, int width, int height, int minLayer, int maxLayer, - boolean allLayers, boolean useIdentityTransform); + private static native GraphicBuffer nativeScreenshot(IBinder displayToken, + Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation); private static native GraphicBuffer nativeCaptureLayers(IBinder layerHandleToken, Rect sourceCrop, float frameScale); @@ -1189,52 +1182,39 @@ public class SurfaceControl implements Parcelable { } /** - * Copy the current screen contents into the provided {@link Surface} - * - * @param display The display to take the screenshot of. - * @param consumer The {@link Surface} to take the screenshot into. - * @param width The desired width of the returned bitmap; the raw - * screen will be scaled down to this size. - * @param height The desired height of the returned bitmap; the raw - * screen will be scaled down to this size. - * @param minLayer The lowest (bottom-most Z order) surface layer to - * include in the screenshot. - * @param maxLayer The highest (top-most Z order) surface layer to - * include in the screenshot. - * @param useIdentityTransform Replace whatever transformation (rotation, - * scaling, translation) the surface layers are currently using with the - * identity transformation while taking the screenshot. + * @see SurfaceControl#screenshot(IBinder, Surface, Rect, int, int, boolean, int) */ - public static void screenshot(IBinder display, Surface consumer, - int width, int height, int minLayer, int maxLayer, - boolean useIdentityTransform) { - screenshot(display, consumer, new Rect(), width, height, minLayer, maxLayer, - false, useIdentityTransform); + public static void screenshot(IBinder display, Surface consumer) { + screenshot(display, consumer, new Rect(), 0, 0, false, 0); } /** * Copy the current screen contents into the provided {@link Surface} * - * @param display The display to take the screenshot of. * @param consumer The {@link Surface} to take the screenshot into. - * @param width The desired width of the returned bitmap; the raw - * screen will be scaled down to this size. - * @param height The desired height of the returned bitmap; the raw - * screen will be scaled down to this size. + * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int) */ - public static void screenshot(IBinder display, Surface consumer, - int width, int height) { - screenshot(display, consumer, new Rect(), width, height, 0, 0, true, false); + public static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, int width, + int height, boolean useIdentityTransform, int rotation) { + if (consumer == null) { + throw new IllegalArgumentException("consumer must not be null"); + } + + final GraphicBuffer buffer = screenshotToBuffer(display, sourceCrop, width, height, + useIdentityTransform, rotation); + try { + consumer.attachAndQueueBuffer(buffer); + } catch (RuntimeException e) { + Log.w(TAG, "Failed to take screenshot - " + e.getMessage()); + } } /** - * Copy the current screen contents into the provided {@link Surface} - * - * @param display The display to take the screenshot of. - * @param consumer The {@link Surface} to take the screenshot into. + * @see SurfaceControl#screenshot(Rect, int, int, boolean, int)} */ - public static void screenshot(IBinder display, Surface consumer) { - screenshot(display, consumer, new Rect(), 0, 0, 0, 0, true, false); + @UnsupportedAppUsage + public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) { + return screenshot(sourceCrop, width, height, false, rotation); } /** @@ -1242,79 +1222,16 @@ public class SurfaceControl implements Parcelable { * 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: Versions of screenshot that return a {@link Bitmap} can - * be extremely slow; avoid use unless absolutely necessary; prefer - * the versions that use a {@link Surface} instead, such as - * {@link SurfaceControl#screenshot(IBinder, Surface)}. + * CAVEAT: Versions of screenshot that return a {@link Bitmap} can be extremely slow; avoid use + * unless absolutely necessary; prefer the versions that use a {@link Surface} such as + * {@link SurfaceControl#screenshot(IBinder, Surface)} or {@link GraphicBuffer} such as + * {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}. * - * @param sourceCrop The portion of the screen to capture into the Bitmap; - * caller may pass in 'new Rect()' if no cropping is desired. - * @param width The desired width of the returned bitmap; the raw - * screen will be scaled down to this size. - * @param height The desired height of the returned bitmap; the raw - * screen will be scaled down to this size. - * @param minLayer The lowest (bottom-most Z order) surface layer to - * include in the screenshot. - * @param maxLayer The highest (top-most Z order) surface layer to - * include in the screenshot. - * @param useIdentityTransform Replace whatever transformation (rotation, - * scaling, translation) the surface layers are currently using with the - * identity transformation while taking the screenshot. - * @param rotation Apply a custom clockwise rotation to the screenshot, i.e. - * Surface.ROTATION_0,90,180,270. Surfaceflinger will always take - * screenshots in its native portrait orientation by default, so this is - * useful for returning screenshots that are independent of device - * orientation. - * @return Returns a hardware Bitmap containing the screen contents, or null - * if an error occurs. Make sure to call Bitmap.recycle() as soon as - * possible, once its content is not needed anymore. + * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)} */ @UnsupportedAppUsage public static Bitmap screenshot(Rect sourceCrop, int width, int height, - int minLayer, int maxLayer, boolean useIdentityTransform, - int rotation) { - // TODO: should take the display as a parameter - IBinder displayToken = SurfaceControl.getBuiltInDisplay( - SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); - return nativeScreenshot(displayToken, sourceCrop, width, height, - minLayer, maxLayer, false, useIdentityTransform, rotation); - } - - /** - * Like {@link SurfaceControl#screenshot(Rect, int, int, int, int, boolean, int)} - * but returns a GraphicBuffer. - */ - public static GraphicBuffer screenshotToBuffer(Rect sourceCrop, int width, int height, - int minLayer, int maxLayer, boolean useIdentityTransform, - int rotation) { - IBinder displayToken = SurfaceControl.getBuiltInDisplay( - SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); - return nativeScreenshotToBuffer(displayToken, sourceCrop, width, height, - minLayer, maxLayer, false, useIdentityTransform, rotation); - } - - /** - * Like {@link SurfaceControl#screenshot(Rect, int, int, int, int, boolean, int)} but - * includes all Surfaces in the screenshot. This will also update the orientation so it - * sends the correct coordinates to SF based on the rotation value. - * - * @param sourceCrop The portion of the screen to capture into the Bitmap; - * caller may pass in 'new Rect()' if no cropping is desired. - * @param width The desired width of the returned bitmap; the raw - * screen will be scaled down to this size. - * @param height The desired height of the returned bitmap; the raw - * screen will be scaled down to this size. - * @param rotation Apply a custom clockwise rotation to the screenshot, i.e. - * Surface.ROTATION_0,90,180,270. Surfaceflinger will always take - * screenshots in its native portrait orientation by default, so this is - * useful for returning screenshots that are independent of device - * orientation. - * @return Returns a Bitmap containing the screen contents, or null - * if an error occurs. Make sure to call Bitmap.recycle() as soon as - * possible, once its content is not needed anymore. - */ - @UnsupportedAppUsage - public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) { + boolean useIdentityTransform, int rotation) { // TODO: should take the display as a parameter IBinder displayToken = SurfaceControl.getBuiltInDisplay( SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); @@ -1323,22 +1240,45 @@ public class SurfaceControl implements Parcelable { } SurfaceControl.rotateCropForSF(sourceCrop, rotation); - return nativeScreenshot(displayToken, sourceCrop, width, height, 0, 0, true, - false, rotation); + final GraphicBuffer buffer = screenshotToBuffer(displayToken, sourceCrop, width, height, + useIdentityTransform, rotation); + + if (buffer == null) { + Log.w(TAG, "Failed to take screenshot"); + return null; + } + return Bitmap.createHardwareBitmap(buffer); } - @UnsupportedAppUsage - private static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, - int width, int height, int minLayer, int maxLayer, boolean allLayers, - boolean useIdentityTransform) { + /** + * Captures all the surfaces in a display and returns a {@link GraphicBuffer} with the content. + * + * @param display The display to take the screenshot of. + * @param sourceCrop The portion of the screen to capture into the Bitmap; caller may + * pass in 'new Rect()' if no cropping is desired. + * @param width The desired width of the returned bitmap; the raw screen will be + * scaled down to this size; caller may pass in 0 if no scaling is + * desired. + * @param height The desired height of the returned bitmap; the raw screen will + * be scaled down to this size; caller may pass in 0 if no scaling + * is desired. + * @param useIdentityTransform Replace whatever transformation (rotation, scaling, translation) + * the surface layers are currently using with the identity + * transformation while taking the screenshot. + * @param rotation Apply a custom clockwise rotation to the screenshot, i.e. + * Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take + * screenshots in its native portrait orientation by default, so + * this is useful for returning screenshots that are independent of + * device orientation. + * @return Returns a GraphicBuffer that contains the captured content. + */ + public static GraphicBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, int width, + int height, boolean useIdentityTransform, int rotation) { if (display == null) { throw new IllegalArgumentException("displayToken must not be null"); } - if (consumer == null) { - throw new IllegalArgumentException("consumer must not be null"); - } - nativeScreenshot(display, consumer, sourceCrop, width, height, - minLayer, maxLayer, allLayers, useIdentityTransform); + + return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation); } private static void rotateCropForSF(Rect crop, int rot) { diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 743b9f6e471d..b70177ffab9a 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -157,23 +157,17 @@ static Rect rectFromObj(JNIEnv* env, jobject rectObj) { return Rect(left, top, right, bottom); } -static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz, +static jobject nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj, jobject sourceCropObj, jint width, jint height, - jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform, - int rotation) { + bool useIdentityTransform, int rotation) { sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); if (displayToken == NULL) { return NULL; } Rect sourceCrop = rectFromObj(env, sourceCropObj); - if (allLayers) { - minLayer = INT32_MIN; - maxLayer = INT32_MAX; - } sp<GraphicBuffer> buffer; - status_t res = ScreenshotClient::capture(displayToken, - sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform, - rotation, &buffer); + status_t res = ScreenshotClient::capture(displayToken, sourceCrop, width, height, + useIdentityTransform, rotation, &buffer); if (res != NO_ERROR) { return NULL; } @@ -187,100 +181,6 @@ static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz, (jlong)buffer.get()); } -static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, - jobject displayTokenObj, jobject sourceCropObj, jint width, jint height, - jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform, - int rotation) { - sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); - if (displayToken == NULL) { - return NULL; - } - - Rect sourceCrop = rectFromObj(env, sourceCropObj); - - std::unique_ptr<ScreenshotClient> screenshot(new ScreenshotClient()); - status_t res; - if (allLayers) { - minLayer = INT32_MIN; - maxLayer = INT32_MAX; - } - - sp<GraphicBuffer> buffer; - res = ScreenshotClient::capture(displayToken, sourceCrop, width, height, - minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation), &buffer); - if (res != NO_ERROR) { - return NULL; - } - - SkColorType colorType; - SkAlphaType alphaType; - - PixelFormat format = buffer->getPixelFormat(); - switch (format) { - case PIXEL_FORMAT_RGBX_8888: { - colorType = kRGBA_8888_SkColorType; - alphaType = kOpaque_SkAlphaType; - break; - } - case PIXEL_FORMAT_RGBA_8888: { - colorType = kRGBA_8888_SkColorType; - alphaType = kPremul_SkAlphaType; - break; - } - case PIXEL_FORMAT_RGBA_FP16: { - colorType = kRGBA_F16_SkColorType; - alphaType = kPremul_SkAlphaType; - break; - } - case PIXEL_FORMAT_RGB_565: { - colorType = kRGB_565_SkColorType; - alphaType = kOpaque_SkAlphaType; - break; - } - default: { - return NULL; - } - } - - SkImageInfo info = SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(), - colorType, alphaType, - SkColorSpace::MakeSRGB()); - - auto bitmap = sk_sp<Bitmap>(new Bitmap(buffer.get(), info)); - return bitmap::createBitmap(env, bitmap.release(), - android::bitmap::kBitmapCreateFlag_Premultiplied, NULL); -} - -static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj, - jobject surfaceObj, jobject sourceCropObj, jint width, jint height, - jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) { - sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); - if (displayToken == NULL) { - return; - } - - sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj); - if (consumer == NULL) { - return; - } - - Rect sourceCrop; - if (sourceCropObj != NULL) { - sourceCrop = rectFromObj(env, sourceCropObj); - } - - if (allLayers) { - minLayer = INT32_MIN; - maxLayer = INT32_MAX; - } - - sp<GraphicBuffer> buffer; - ScreenshotClient::capture(displayToken, sourceCrop, width, height, minLayer, maxLayer, - useIdentityTransform, 0, &buffer); - - Surface::attachAndQueueBuffer(consumer.get(), buffer); -} - static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken, jobject sourceCropObj, jfloat frameScale) { @@ -919,10 +819,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeDestroy }, {"nativeDisconnect", "(J)V", (void*)nativeDisconnect }, - {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;", - (void*)nativeScreenshotBitmap }, - {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V", - (void*)nativeScreenshot }, {"nativeCreateTransaction", "()J", (void*)nativeCreateTransaction }, {"nativeApplyTransaction", "(JZ)V", @@ -1013,9 +909,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeDestroyInTransaction }, {"nativeGetHandle", "(J)Landroid/os/IBinder;", (void*)nativeGetHandle }, - {"nativeScreenshotToBuffer", - "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/GraphicBuffer;", - (void*)nativeScreenshotToBuffer }, + {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIZI)Landroid/graphics/GraphicBuffer;", + (void*)nativeScreenshot }, {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;", (void*)nativeCaptureLayers }, }; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ac6582634bf8..03a4d8ea0659 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3252,7 +3252,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // TODO(b/68392460): We should screenshot Task controls directly // but it's difficult at the moment as the Task doesn't have the // correct size set. - final Bitmap bitmap = SurfaceControl.screenshot(frame, dw, dh, 0, 1, inRotation, rot); + final Bitmap bitmap = SurfaceControl.screenshot(frame, dw, dh, inRotation, rot); if (bitmap == null) { Slog.w(TAG_WM, "Failed to take screenshot"); return null; |