diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index 6ded24648353a..31722815276c8 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 const* base = NULL; + void* base = NULL; uint32_t w, s, h, f; android_dataspace d; size_t size = 0; @@ -179,7 +179,6 @@ 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); @@ -199,51 +198,57 @@ int main(int argc, char** argv) uint8_t displayOrientation = configs[activeConfig].orientation; uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation]; - 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(); + 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); } - 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 ; ylock(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(nativeObject); sp bp = graphicBufferForJavaObject(env, graphicBuffer); - 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); + int err = Surface::attachAndQueueBuffer(surface, bp); return err; } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index f77e6c4fa7b81..8c968a2a70838 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::captureToBuffer(displayToken, + status_t res = ScreenshotClient::capture(displayToken, sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform, rotation, &buffer); if (res != NO_ERROR) { @@ -201,15 +201,18 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, maxLayer = INT32_MAX; } - res = screenshot->update(displayToken, sourceCrop, width, height, - minLayer, maxLayer, useIdentityTransform, static_cast(rotation)); + sp buffer; + res = ScreenshotClient::capture(displayToken, sourceCrop, width, height, + minLayer, maxLayer, useIdentityTransform, static_cast(rotation), &buffer); if (res != NO_ERROR) { return NULL; } SkColorType colorType; SkAlphaType alphaType; - switch (screenshot->getFormat()) { + + PixelFormat format = buffer->getPixelFormat(); + switch (format) { case PIXEL_FORMAT_RGBX_8888: { colorType = kRGBA_8888_SkColorType; alphaType = kOpaque_SkAlphaType; @@ -235,66 +238,20 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, } } - sk_sp colorSpace; - if (screenshot->getDataSpace() == HAL_DATASPACE_DISPLAY_P3) { - colorSpace = SkColorSpace::MakeRGB( - SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut); - } else { - colorSpace = SkColorSpace::MakeSRGB(); - } + SkImageInfo info = SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(), + colorType, alphaType, + SkColorSpace::MakeSRGB()); - 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); + auto bitmap = sk_sp(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 displayToken = ibinderForJavaObject(env, displayTokenObj); - 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) { + if (displayToken == NULL) { return; } @@ -308,11 +265,19 @@ static void nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleTo sourceCrop = rectFromObj(env, sourceCropObj); } - ScreenshotClient::captureLayers(layerHandle, consumer->getIGraphicBufferProducer(), sourceCrop, - frameScale); + 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); } -static jobject nativeCaptureLayersToBuffer(JNIEnv* env, jclass clazz, jobject layerHandleToken, +static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerHandleToken, jobject sourceCropObj, jfloat frameScale) { sp layerHandle = ibinderForJavaObject(env, layerHandleToken); @@ -326,8 +291,7 @@ static jobject nativeCaptureLayersToBuffer(JNIEnv* env, jclass clazz, jobject la } sp buffer; - status_t res = ScreenshotClient::captureLayersToBuffer(layerHandle, sourceCrop, frameScale, - &buffer); + status_t res = ScreenshotClient::captureLayers(layerHandle, sourceCrop, frameScale, &buffer); if (res != NO_ERROR) { return NULL; } @@ -1010,10 +974,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { {"nativeScreenshotToBuffer", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/GraphicBuffer;", (void*)nativeScreenshotToBuffer }, - {"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 }, + (void*)nativeCaptureLayers }, }; int register_android_view_SurfaceControl(JNIEnv* env) diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java index 8e27edf93d9ce..8e0161961a490 100644 --- a/packages/Shell/src/com/android/shell/Screenshooter.java +++ b/packages/Shell/src/com/android/shell/Screenshooter.java @@ -17,12 +17,11 @@ package com.android.shell; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Point; +import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.util.Log; import android.view.Display; -import android.view.Surface; import android.view.SurfaceControl; /** @@ -35,18 +34,6 @@ final class Screenshooter { private static final String TAG = "Screenshooter"; - /** Rotation constant: Freeze rotation to 0 degrees (natural orientation) */ - public static final int ROTATION_FREEZE_0 = Surface.ROTATION_0; - - /** Rotation constant: Freeze rotation to 90 degrees . */ - public static final int ROTATION_FREEZE_90 = Surface.ROTATION_90; - - /** Rotation constant: Freeze rotation to 180 degrees . */ - public static final int ROTATION_FREEZE_180 = Surface.ROTATION_180; - - /** Rotation constant: Freeze rotation to 270 degrees . */ - public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270; - /** * Takes a screenshot. * @@ -60,78 +47,21 @@ final class Screenshooter { final int displayWidth = displaySize.x; final int displayHeight = displaySize.y; - final float screenshotWidth; - final float screenshotHeight; - - final int rotation = display.getRotation(); - switch (rotation) { - case ROTATION_FREEZE_0: { - screenshotWidth = displayWidth; - screenshotHeight = displayHeight; - } break; - case ROTATION_FREEZE_90: { - screenshotWidth = displayHeight; - screenshotHeight = displayWidth; - } break; - case ROTATION_FREEZE_180: { - screenshotWidth = displayWidth; - screenshotHeight = displayHeight; - } break; - case ROTATION_FREEZE_270: { - screenshotWidth = displayHeight; - screenshotHeight = displayWidth; - } break; - default: { - throw new IllegalArgumentException("Invalid rotation: " - + rotation); - } - } - + int rotation = display.getRotation(); + Rect crop = new Rect(0, 0, displayWidth, displayHeight); Log.d(TAG, "Taking screenshot of dimensions " + displayWidth + " x " + displayHeight); // Take the screenshot Bitmap screenShot = - SurfaceControl.screenshot((int) screenshotWidth, (int) screenshotHeight); + SurfaceControl.screenshot(crop, displayWidth, displayHeight, rotation); if (screenShot == null) { - Log.e(TAG, "Failed to take screenshot of dimensions " + screenshotWidth + " x " - + screenshotHeight); + Log.e(TAG, "Failed to take screenshot of dimensions " + displayWidth + " x " + + displayHeight); return null; } - // Rotate the screenshot to the current orientation - if (rotation != ROTATION_FREEZE_0) { - Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight, - Bitmap.Config.ARGB_8888, screenShot.hasAlpha(), screenShot.getColorSpace()); - Canvas canvas = new Canvas(unrotatedScreenShot); - canvas.translate(unrotatedScreenShot.getWidth() / 2, - unrotatedScreenShot.getHeight() / 2); - canvas.rotate(getDegreesForRotation(rotation)); - canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2); - canvas.drawBitmap(screenShot, 0, 0, null); - canvas.setBitmap(null); - screenShot.recycle(); - screenShot = unrotatedScreenShot; - } - // Optimization screenShot.setHasAlpha(false); return screenShot; } - - private static float getDegreesForRotation(int value) { - switch (value) { - case Surface.ROTATION_90: { - return 360f - 90f; - } - case Surface.ROTATION_180: { - return 360f - 180f; - } - case Surface.ROTATION_270: { - return 360f - 270f; - } default: { - return 0; - } - } - } - } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 991c3c83cbc18..5fcd0061fa6f5 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -49,7 +49,6 @@ import android.graphics.Rect; import android.media.MediaActionSound; import android.net.Uri; import android.os.AsyncTask; -import android.os.Bundle; import android.os.Environment; import android.os.PowerManager; import android.os.Process; @@ -162,7 +161,7 @@ class SaveImageInBackgroundTask extends AsyncTask { Matrix matrix = new Matrix(); int overlayColor = 0x40FFFFFF; - Bitmap picture = Bitmap.createBitmap(previewWidth, previewHeight, data.image.getConfig()); + Bitmap picture = Bitmap.createBitmap(previewWidth, previewHeight, Bitmap.Config.ARGB_8888); matrix.setTranslate((previewWidth - mImageWidth) / 2, (previewHeight - mImageHeight) / 2); c.setBitmap(picture); c.drawBitmap(data.image, matrix, paint); @@ -171,7 +170,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, data.image.getConfig()); + Bitmap icon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888); matrix.setScale(scale, scale); matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2, (iconSize - (scale * mImageHeight)) / 2); @@ -557,25 +556,14 @@ class GlobalScreenshot { /** * Takes a screenshot of the current display and shows an animation. */ - void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible, - int x, int y, int width, int height) { - // We need to orient the screenshot correctly (and the Surface api seems to take screenshots - // only in the natural orientation of the device :!) - mDisplay.getRealMetrics(mDisplayMetrics); - float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels}; - float degrees = getDegreesForRotation(mDisplay.getRotation()); - boolean requiresRotation = (degrees > 0); - if (requiresRotation) { - // Get the dimensions of the device in its native orientation - mDisplayMatrix.reset(); - mDisplayMatrix.preRotate(-degrees); - mDisplayMatrix.mapPoints(dims); - dims[0] = Math.abs(dims[0]); - dims[1] = Math.abs(dims[1]); - } + private void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible, + Rect crop) { + int rot = mDisplay.getRotation(); + int width = crop.width(); + int height = crop.height(); // Take the screenshot - mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]); + mScreenBitmap = SurfaceControl.screenshot(crop, width, height, rot); if (mScreenBitmap == null) { notifyScreenshotError(mContext, mNotificationManager, R.string.screenshot_failed_to_capture_text); @@ -583,29 +571,6 @@ class GlobalScreenshot { return; } - if (requiresRotation) { - // Rotate the screenshot to the current orientation - Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels, - mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888, - mScreenBitmap.hasAlpha(), mScreenBitmap.getColorSpace()); - Canvas c = new Canvas(ss); - c.translate(ss.getWidth() / 2, ss.getHeight() / 2); - c.rotate(degrees); - c.translate(-dims[0] / 2, -dims[1] / 2); - c.drawBitmap(mScreenBitmap, 0, 0, null); - c.setBitmap(null); - // Recycle the previous bitmap - mScreenBitmap.recycle(); - mScreenBitmap = ss; - } - - if (width != mDisplayMetrics.widthPixels || height != mDisplayMetrics.heightPixels) { - // Crop the screenshot to selected region - Bitmap cropped = Bitmap.createBitmap(mScreenBitmap, x, y, width, height); - mScreenBitmap.recycle(); - mScreenBitmap = cropped; - } - // Optimizations mScreenBitmap.setHasAlpha(false); mScreenBitmap.prepareToDraw(); @@ -617,8 +582,8 @@ class GlobalScreenshot { void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) { mDisplay.getRealMetrics(mDisplayMetrics); - takeScreenshot(finisher, statusBarVisible, navBarVisible, 0, 0, mDisplayMetrics.widthPixels, - mDisplayMetrics.heightPixels); + takeScreenshot(finisher, statusBarVisible, navBarVisible, + new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)); } /** @@ -648,7 +613,7 @@ class GlobalScreenshot { mScreenshotLayout.post(new Runnable() { public void run() { takeScreenshot(finisher, statusBarVisible, navBarVisible, - rect.left, rect.top, rect.width(), rect.height()); + rect); } }); } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 84e475a251875..43a089373a35c 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.captureLayersToBuffer( + final GraphicBuffer buffer = SurfaceControl.captureLayers( task.getSurfaceControl().getHandle(), taskFrame, scaleFraction); if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {