Loading core/java/android/view/SurfaceControl.java +11 −4 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ public class SurfaceControl { private static native Bitmap nativeScreenshot(IBinder displayToken, Rect sourceCrop, int width, int height, int minLayer, int maxLayer, boolean allLayers, boolean useIdentityTransform); 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); Loading Loading @@ -688,17 +688,23 @@ public class SurfaceControl { * @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 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. */ public static Bitmap screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer, boolean useIdentityTransform) { 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); minLayer, maxLayer, false, useIdentityTransform, rotation); } /** Loading @@ -717,7 +723,8 @@ public class SurfaceControl { // TODO: should take the display as a parameter IBinder displayToken = SurfaceControl.getBuiltInDisplay( SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); return nativeScreenshot(displayToken, new Rect(), width, height, 0, 0, true, false); return nativeScreenshot(displayToken, new Rect(), width, height, 0, 0, true, false, Surface.ROTATION_0); } private static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, Loading core/jni/android_view_SurfaceControl.cpp +9 −12 Original line number Diff line number Diff line Loading @@ -117,7 +117,8 @@ static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) { static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj, jobject sourceCropObj, jint width, jint height, jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) { jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform, int rotation) { sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); if (displayToken == NULL) { return NULL; Loading @@ -131,17 +132,13 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, SkAutoTDelete<ScreenshotClient> screenshot(new ScreenshotClient()); status_t res; if (width > 0 && height > 0) { if (allLayers) { res = screenshot->update(displayToken, sourceCrop, width, height, useIdentityTransform); } else { res = screenshot->update(displayToken, sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform); } } else { res = screenshot->update(displayToken, sourceCrop, useIdentityTransform); minLayer = 0; maxLayer = -1UL; } res = screenshot->update(displayToken, sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation)); if (res != NO_ERROR) { return NULL; } Loading Loading @@ -588,7 +585,7 @@ static JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeRelease }, {"nativeDestroy", "(J)V", (void*)nativeDestroy }, {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZ)Landroid/graphics/Bitmap;", {"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 }, Loading services/core/java/com/android/server/wm/WindowManagerService.java +12 −22 Original line number Diff line number Diff line Loading @@ -5931,7 +5931,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height, boolean force565) { if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER, "screenshotApplications()")) { throw new SecurityException("Requires READ_FRAME_BUFFER permission"); } Loading @@ -5951,7 +5951,7 @@ public class WindowManagerService extends IWindowManager.Stub return null; } Bitmap rawss = null; Bitmap bm = null; int maxLayer = 0; final Rect frame = new Rect(); Loading Loading @@ -6092,10 +6092,8 @@ public class WindowManagerService extends IWindowManager.Stub // The screenshot API does not apply the current screen rotation. rot = getDefaultDisplayContentLocked().getDisplay().getRotation(); if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { final int tmp = width; width = height; height = tmp; rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90; } Loading @@ -6121,9 +6119,9 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG, "Taking screenshot while rotating"); rawss = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer, inRotation); if (rawss == null) { bm = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer, inRotation, rot); if (bm == null) { Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh + ") to layer " + maxLayer); return null; Loading @@ -6133,17 +6131,6 @@ public class WindowManagerService extends IWindowManager.Stub break; } Bitmap bm = Bitmap.createBitmap(width, height, force565 ? Config.RGB_565 : rawss.getConfig()); if (DEBUG_SCREENSHOT) { bm.eraseColor(0xFF000000); } Matrix matrix = new Matrix(); ScreenRotationAnimation.createRotationMatrix(rot, width, height, matrix); Canvas canvas = new Canvas(bm); canvas.drawBitmap(rawss, matrix, null); canvas.setBitmap(null); if (DEBUG_SCREENSHOT) { // TEST IF IT's ALL BLACK int[] buffer = new int[bm.getWidth() * bm.getHeight()]; Loading @@ -6164,9 +6151,12 @@ public class WindowManagerService extends IWindowManager.Stub } } rawss.recycle(); return bm; // Copy the screenshot bitmap to another buffer so that the gralloc backed // bitmap will not have a long lifetime. Gralloc memory can be pinned or // duplicated and might have a higher cost than a skia backed buffer. Bitmap ret = bm.copy(bm.getConfig(),true); bm.recycle(); return ret; } /** Loading Loading
core/java/android/view/SurfaceControl.java +11 −4 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ public class SurfaceControl { private static native Bitmap nativeScreenshot(IBinder displayToken, Rect sourceCrop, int width, int height, int minLayer, int maxLayer, boolean allLayers, boolean useIdentityTransform); 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); Loading Loading @@ -688,17 +688,23 @@ public class SurfaceControl { * @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 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. */ public static Bitmap screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer, boolean useIdentityTransform) { 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); minLayer, maxLayer, false, useIdentityTransform, rotation); } /** Loading @@ -717,7 +723,8 @@ public class SurfaceControl { // TODO: should take the display as a parameter IBinder displayToken = SurfaceControl.getBuiltInDisplay( SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); return nativeScreenshot(displayToken, new Rect(), width, height, 0, 0, true, false); return nativeScreenshot(displayToken, new Rect(), width, height, 0, 0, true, false, Surface.ROTATION_0); } private static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, Loading
core/jni/android_view_SurfaceControl.cpp +9 −12 Original line number Diff line number Diff line Loading @@ -117,7 +117,8 @@ static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) { static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj, jobject sourceCropObj, jint width, jint height, jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) { jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform, int rotation) { sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); if (displayToken == NULL) { return NULL; Loading @@ -131,17 +132,13 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, SkAutoTDelete<ScreenshotClient> screenshot(new ScreenshotClient()); status_t res; if (width > 0 && height > 0) { if (allLayers) { res = screenshot->update(displayToken, sourceCrop, width, height, useIdentityTransform); } else { res = screenshot->update(displayToken, sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform); } } else { res = screenshot->update(displayToken, sourceCrop, useIdentityTransform); minLayer = 0; maxLayer = -1UL; } res = screenshot->update(displayToken, sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation)); if (res != NO_ERROR) { return NULL; } Loading Loading @@ -588,7 +585,7 @@ static JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeRelease }, {"nativeDestroy", "(J)V", (void*)nativeDestroy }, {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZ)Landroid/graphics/Bitmap;", {"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 }, Loading
services/core/java/com/android/server/wm/WindowManagerService.java +12 −22 Original line number Diff line number Diff line Loading @@ -5931,7 +5931,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height, boolean force565) { if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER, "screenshotApplications()")) { throw new SecurityException("Requires READ_FRAME_BUFFER permission"); } Loading @@ -5951,7 +5951,7 @@ public class WindowManagerService extends IWindowManager.Stub return null; } Bitmap rawss = null; Bitmap bm = null; int maxLayer = 0; final Rect frame = new Rect(); Loading Loading @@ -6092,10 +6092,8 @@ public class WindowManagerService extends IWindowManager.Stub // The screenshot API does not apply the current screen rotation. rot = getDefaultDisplayContentLocked().getDisplay().getRotation(); if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { final int tmp = width; width = height; height = tmp; rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90; } Loading @@ -6121,9 +6119,9 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG, "Taking screenshot while rotating"); rawss = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer, inRotation); if (rawss == null) { bm = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer, inRotation, rot); if (bm == null) { Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh + ") to layer " + maxLayer); return null; Loading @@ -6133,17 +6131,6 @@ public class WindowManagerService extends IWindowManager.Stub break; } Bitmap bm = Bitmap.createBitmap(width, height, force565 ? Config.RGB_565 : rawss.getConfig()); if (DEBUG_SCREENSHOT) { bm.eraseColor(0xFF000000); } Matrix matrix = new Matrix(); ScreenRotationAnimation.createRotationMatrix(rot, width, height, matrix); Canvas canvas = new Canvas(bm); canvas.drawBitmap(rawss, matrix, null); canvas.setBitmap(null); if (DEBUG_SCREENSHOT) { // TEST IF IT's ALL BLACK int[] buffer = new int[bm.getWidth() * bm.getHeight()]; Loading @@ -6164,9 +6151,12 @@ public class WindowManagerService extends IWindowManager.Stub } } rawss.recycle(); return bm; // Copy the screenshot bitmap to another buffer so that the gralloc backed // bitmap will not have a long lifetime. Gralloc memory can be pinned or // duplicated and might have a higher cost than a skia backed buffer. Bitmap ret = bm.copy(bm.getConfig(),true); bm.recycle(); return ret; } /** Loading