diff options
-rw-r--r-- | cmds/screencap/screencap.cpp | 97 | ||||
-rw-r--r-- | core/java/android/view/SurfaceControl.java | 16 | ||||
-rw-r--r-- | core/jni/android_view_Surface.cpp | 18 | ||||
-rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 92 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java | 4 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/TaskSnapshotController.java | 2 |
6 files changed, 144 insertions, 85 deletions
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index 31722815276c..6ded24648353 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -159,7 +159,7 @@ int main(int argc, char** argv) void const* mapbase = MAP_FAILED; ssize_t mapsize = -1; - void* base = NULL; + void const* base = NULL; uint32_t w, s, h, f; android_dataspace d; size_t size = 0; @@ -179,6 +179,7 @@ int main(int argc, char** argv) ProcessState::self()->setThreadPoolMaxThreadCount(0); ProcessState::self()->startThreadPool(); + ScreenshotClient screenshot; sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId); if (display == NULL) { fprintf(stderr, "Unable to get handle for display %d\n", displayId); @@ -198,57 +199,51 @@ int main(int argc, char** argv) uint8_t displayOrientation = configs[activeConfig].orientation; uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation]; - sp<GraphicBuffer> outBuffer; - status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */, - 0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation, - &outBuffer); - if (result != NO_ERROR) { - close(fd); - _exit(1); - } - - result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base); - - if (base == NULL) { - close(fd); - _exit(1); + status_t result = screenshot.update(display, Rect(), + 0 /* reqWidth */, 0 /* reqHeight */, + INT32_MIN, INT32_MAX, /* all layers */ + false, captureOrientation); + if (result == NO_ERROR) { + base = screenshot.getPixels(); + w = screenshot.getWidth(); + h = screenshot.getHeight(); + s = screenshot.getStride(); + f = screenshot.getFormat(); + d = screenshot.getDataSpace(); + size = screenshot.getSize(); } - w = outBuffer->getWidth(); - h = outBuffer->getHeight(); - s = outBuffer->getStride(); - f = outBuffer->getPixelFormat(); - d = HAL_DATASPACE_UNKNOWN; - size = s * h * bytesPerPixel(f); - - if (png) { - const SkImageInfo info = - SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, dataSpaceToColorSpace(d)); - SkPixmap pixmap(info, base, s * bytesPerPixel(f)); - struct FDWStream final : public SkWStream { - size_t fBytesWritten = 0; - int fFd; - FDWStream(int f) : fFd(f) {} - size_t bytesWritten() const override { return fBytesWritten; } - bool write(const void* buffer, size_t size) override { - fBytesWritten += size; - return size == 0 || ::write(fFd, buffer, size) > 0; - } - } fdStream(fd); - (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100); - if (fn != NULL) { - notifyMediaScanner(fn); - } - } else { - uint32_t c = dataSpaceToInt(d); - write(fd, &w, 4); - write(fd, &h, 4); - write(fd, &f, 4); - write(fd, &c, 4); - size_t Bpp = bytesPerPixel(f); - for (size_t y=0 ; y<h ; y++) { - write(fd, base, w*Bpp); - base = (void *)((char *)base + s*Bpp); + if (base != NULL) { + if (png) { + const SkImageInfo info = + SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, + dataSpaceToColorSpace(d)); + SkPixmap pixmap(info, base, s * bytesPerPixel(f)); + struct FDWStream final : public SkWStream { + size_t fBytesWritten = 0; + int fFd; + FDWStream(int f) : fFd(f) {} + size_t bytesWritten() const override { return fBytesWritten; } + bool write(const void* buffer, size_t size) override { + fBytesWritten += size; + return size == 0 || ::write(fFd, buffer, size) > 0; + } + } fdStream(fd); + (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100); + if (fn != NULL) { + notifyMediaScanner(fn); + } + } else { + uint32_t c = dataSpaceToInt(d); + write(fd, &w, 4); + write(fd, &h, 4); + write(fd, &f, 4); + write(fd, &c, 4); + size_t Bpp = bytesPerPixel(f); + for (size_t y=0 ; y<h ; y++) { + write(fd, base, w*Bpp); + base = (void *)((char *)base + s*Bpp); + } } } close(fd); @@ -258,4 +253,4 @@ int main(int argc, char** argv) // b/36066697: Avoid running static destructors. _exit(0); -}
\ No newline at end of file +} diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index cf059104e373..3d01ec23b723 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -55,6 +55,8 @@ public class SurfaceControl { 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 void nativeCaptureLayers(IBinder layerHandleToken, Surface consumer, + Rect sourceCrop, float frameScale); private static native GraphicBuffer nativeCaptureLayers(IBinder layerHandleToken, Rect sourceCrop, float frameScale); @@ -1177,14 +1179,22 @@ public class SurfaceControl { * Captures a layer and its children into the provided {@link Surface}. * * @param layerHandleToken The root layer to capture. + * @param consumer The {@link Surface} to capture the layer into. * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new * Rect()' or null if no cropping is desired. * @param frameScale The desired scale of the returned buffer; the raw * screen will be scaled up/down. - * - * @return Returns a GraphicBuffer that contains the layer capture. */ - public static GraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop, + public static void captureLayers(IBinder layerHandleToken, Surface consumer, Rect sourceCrop, + float frameScale) { + nativeCaptureLayers(layerHandleToken, consumer, sourceCrop, frameScale); + } + + /** + * Same as {@link #captureLayers(IBinder, Surface, Rect, float)} except this + * captures to a {@link GraphicBuffer} instead of a {@link Surface}. + */ + public static GraphicBuffer captureLayersToBuffer(IBinder layerHandleToken, Rect sourceCrop, float frameScale) { return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale); } diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 421e0de52cc0..3ad4da6b6580 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -517,7 +517,23 @@ static jint nativeAttachAndQueueBuffer(JNIEnv *env, jclass clazz, jlong nativeOb jobject graphicBuffer) { Surface* surface = reinterpret_cast<Surface*>(nativeObject); sp<GraphicBuffer> bp = graphicBufferForJavaObject(env, graphicBuffer); - int err = Surface::attachAndQueueBuffer(surface, bp); + if (bp == nullptr) { + return BAD_VALUE; + } + int err = ((ANativeWindow*)surface)->perform(surface, NATIVE_WINDOW_API_CONNECT, + NATIVE_WINDOW_API_CPU); + if (err != OK) { + return err; + } + err = surface->attachBuffer(bp->getNativeBuffer()); + if (err != OK) { + return err; + } + err = ((ANativeWindow*)surface)->queueBuffer(surface, bp->getNativeBuffer(), -1); + if (err != OK) { + return err; + } + err = surface->disconnect(NATIVE_WINDOW_API_CPU); return err; } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 8c968a2a7083..f77e6c4fa7b8 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -167,7 +167,7 @@ static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz, maxLayer = INT32_MAX; } sp<GraphicBuffer> buffer; - status_t res = ScreenshotClient::capture(displayToken, + status_t res = ScreenshotClient::captureToBuffer(displayToken, sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform, rotation, &buffer); if (res != NO_ERROR) { @@ -201,18 +201,15 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, maxLayer = INT32_MAX; } - sp<GraphicBuffer> buffer; - res = ScreenshotClient::capture(displayToken, sourceCrop, width, height, - minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation), &buffer); + res = screenshot->update(displayToken, sourceCrop, width, height, + minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation)); if (res != NO_ERROR) { return NULL; } SkColorType colorType; SkAlphaType alphaType; - - PixelFormat format = buffer->getPixelFormat(); - switch (format) { + switch (screenshot->getFormat()) { case PIXEL_FORMAT_RGBX_8888: { colorType = kRGBA_8888_SkColorType; alphaType = kOpaque_SkAlphaType; @@ -238,20 +235,66 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, } } - SkImageInfo info = SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(), - colorType, alphaType, - SkColorSpace::MakeSRGB()); + sk_sp<SkColorSpace> colorSpace; + if (screenshot->getDataSpace() == HAL_DATASPACE_DISPLAY_P3) { + colorSpace = SkColorSpace::MakeRGB( + SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut); + } else { + colorSpace = SkColorSpace::MakeSRGB(); + } + + SkImageInfo screenshotInfo = SkImageInfo::Make(screenshot->getWidth(), + screenshot->getHeight(), + colorType, + alphaType, + colorSpace); - auto bitmap = sk_sp<Bitmap>(new Bitmap(buffer.get(), info)); - return bitmap::createBitmap(env, bitmap.release(), - android::bitmap::kBitmapCreateFlag_Premultiplied, NULL); + const size_t rowBytes = + screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat()); + + if (!screenshotInfo.width() || !screenshotInfo.height()) { + return NULL; + } + + auto bitmap = new Bitmap( + (void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot, + screenshotInfo, rowBytes); + screenshot.release(); + bitmap->setImmutable(); + return bitmap::createBitmap(env, bitmap, + 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) { + if (displayToken != NULL) { + sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj); + if (consumer != NULL) { + int left = env->GetIntField(sourceCropObj, gRectClassInfo.left); + int top = env->GetIntField(sourceCropObj, gRectClassInfo.top); + int right = env->GetIntField(sourceCropObj, gRectClassInfo.right); + int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom); + Rect sourceCrop(left, top, right, bottom); + + if (allLayers) { + minLayer = INT32_MIN; + maxLayer = INT32_MAX; + } + ScreenshotClient::capture(displayToken, + consumer->getIGraphicBufferProducer(), sourceCrop, + width, height, minLayer, maxLayer, + useIdentityTransform); + } + } +} + +static void nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken, + jobject surfaceObj, jobject sourceCropObj, jfloat frameScale) { + + sp<IBinder> layerHandle = ibinderForJavaObject(env, layerHandleToken); + if (layerHandle == NULL) { return; } @@ -265,19 +308,11 @@ static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj, 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); + ScreenshotClient::captureLayers(layerHandle, consumer->getIGraphicBufferProducer(), sourceCrop, + frameScale); } -static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken, +static jobject nativeCaptureLayersToBuffer(JNIEnv* env, jclass clazz, jobject layerHandleToken, jobject sourceCropObj, jfloat frameScale) { sp<IBinder> layerHandle = ibinderForJavaObject(env, layerHandleToken); @@ -291,7 +326,8 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandl } sp<GraphicBuffer> buffer; - status_t res = ScreenshotClient::captureLayers(layerHandle, sourceCrop, frameScale, &buffer); + status_t res = ScreenshotClient::captureLayersToBuffer(layerHandle, sourceCrop, frameScale, + &buffer); if (res != NO_ERROR) { return NULL; } @@ -974,8 +1010,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = { {"nativeScreenshotToBuffer", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/GraphicBuffer;", (void*)nativeScreenshotToBuffer }, - {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;", + {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;F)V", (void*)nativeCaptureLayers }, + {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;", + (void*)nativeCaptureLayersToBuffer }, }; int register_android_view_SurfaceControl(JNIEnv* env) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index e9096447bbf6..991c3c83cbc1 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -162,7 +162,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { Matrix matrix = new Matrix(); int overlayColor = 0x40FFFFFF; - Bitmap picture = Bitmap.createBitmap(previewWidth, previewHeight, Bitmap.Config.ARGB_8888); + Bitmap picture = Bitmap.createBitmap(previewWidth, previewHeight, data.image.getConfig()); matrix.setTranslate((previewWidth - mImageWidth) / 2, (previewHeight - mImageHeight) / 2); c.setBitmap(picture); c.drawBitmap(data.image, matrix, paint); @@ -171,7 +171,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { // Note, we can't use the preview for the small icon, since it is non-square float scale = (float) iconSize / Math.min(mImageWidth, mImageHeight); - Bitmap icon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888); + Bitmap icon = Bitmap.createBitmap(iconSize, iconSize, data.image.getConfig()); matrix.setScale(scale, scale); matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2, (iconSize - (scale * mImageHeight)) / 2); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 43a089373a35..84e475a25187 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -226,7 +226,7 @@ class TaskSnapshotController { final Rect taskFrame = new Rect(); task.getBounds(taskFrame); - final GraphicBuffer buffer = SurfaceControl.captureLayers( + final GraphicBuffer buffer = SurfaceControl.captureLayersToBuffer( task.getSurfaceControl().getHandle(), taskFrame, scaleFraction); if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) { |