diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index 31722815276c8..6ded24648353a 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 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 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); + 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(); } - result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base); - - if (base == NULL) { - close(fd); - _exit(1); - } - - 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 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(nativeObject); sp 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 8c968a2a70838..f77e6c4fa7b81 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 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 buffer; - res = ScreenshotClient::capture(displayToken, sourceCrop, width, height, - minLayer, maxLayer, useIdentityTransform, static_cast(rotation), &buffer); + res = screenshot->update(displayToken, sourceCrop, width, height, + minLayer, maxLayer, useIdentityTransform, static_cast(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 colorSpace; + if (screenshot->getDataSpace() == HAL_DATASPACE_DISPLAY_P3) { + colorSpace = SkColorSpace::MakeRGB( + SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut); + } else { + colorSpace = SkColorSpace::MakeSRGB(); + } - auto bitmap = sk_sp(new Bitmap(buffer.get(), info)); - return bitmap::createBitmap(env, bitmap.release(), - android::bitmap::kBitmapCreateFlag_Premultiplied, NULL); + SkImageInfo screenshotInfo = SkImageInfo::Make(screenshot->getWidth(), + screenshot->getHeight(), + colorType, + alphaType, + colorSpace); + + 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 displayToken = ibinderForJavaObject(env, displayTokenObj); - if (displayToken == NULL) { + if (displayToken != NULL) { + sp 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 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 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 layerHandle = ibinderForJavaObject(env, layerHandleToken); @@ -291,7 +326,8 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandl } sp 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 e9096447bbf6d..991c3c83cbc18 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 { 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 { // 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 43a089373a35c..84e475a251875 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) {