Loading cmds/screencap/screencap.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -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; Loading core/java/android/view/SurfaceControl.java +63 −123 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); } /** Loading @@ -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); Loading @@ -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) { Loading core/jni/android_view_SurfaceControl.cpp +6 −111 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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) { Loading Loading @@ -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", Loading Loading @@ -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 }, }; Loading services/core/java/com/android/server/wm/DisplayContent.java +1 −1 Original line number Diff line number Diff line Loading @@ -3251,7 +3251,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; Loading Loading
cmds/screencap/screencap.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -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; Loading
core/java/android/view/SurfaceControl.java +63 −123 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); } /** Loading @@ -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); Loading @@ -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) { Loading
core/jni/android_view_SurfaceControl.cpp +6 −111 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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) { Loading Loading @@ -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", Loading Loading @@ -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 }, }; Loading
services/core/java/com/android/server/wm/DisplayContent.java +1 −1 Original line number Diff line number Diff line Loading @@ -3251,7 +3251,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; Loading