From d7ec64ccd0c2b180fc9fd3ff526642e5e7e28af0 Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Thu, 30 Nov 2017 01:52:01 +0000 Subject: [PATCH 1/2] Revert "Revert "Updated screenshot code to reflect native changes."" This reverts commit ea2eb5a14447869325ced829910f072c81913ef3. Reason for revert: Ready to test out changes with SystemUI update Change-Id: I9c8d5672a530334300bc1ea454a7fd7900296c7c --- cmds/screencap/screencap.cpp | 97 ++++++++++--------- core/java/android/view/SurfaceControl.java | 16 +-- core/jni/android_view_Surface.cpp | 18 +--- core/jni/android_view_SurfaceControl.cpp | 92 ++++++------------ .../systemui/screenshot/GlobalScreenshot.java | 4 +- .../server/wm/TaskSnapshotController.java | 2 +- 6 files changed, 85 insertions(+), 144 deletions(-) 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/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 991c3c83cbc18..e9096447bbf6d 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, 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 +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, 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); 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) { From a69e0a7d7c11d586c5a3ff74306a41c1456fd250 Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 29 Nov 2017 17:55:12 -0800 Subject: [PATCH 2/2] Update screenshot requests to render proper crop and rotation. The previous screenshot requests in SystemUI would generate a bitmap and then adjust crop and rotation afterwards. Bitmaps from screenshots are now hw Bitmaps so they can't be updated in software. Instead request the proper crop and rotation from the native code to generate a Bitmap with the correct configurations. Change-Id: I4591c468b055c784460e5ddf2f9163ffa943c2ee Fixes: 69898957 Test: Manual screenshots work and bugreport screenshots work in landscape. --- .../android/app/IUiAutomationConnection.aidl | 3 +- core/java/android/app/UiAutomation.java | 49 +---------- .../android/app/UiAutomationConnection.java | 7 +- core/java/android/view/SurfaceControl.java | 35 +++++++- .../src/com/android/shell/Screenshooter.java | 82 ++----------------- .../systemui/screenshot/GlobalScreenshot.java | 53 ++---------- 6 files changed, 57 insertions(+), 172 deletions(-) diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index b26117d3d31c2..d01938b123b17 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -18,6 +18,7 @@ package android.app; import android.accessibilityservice.IAccessibilityServiceClient; import android.graphics.Bitmap; +import android.graphics.Rect; import android.view.InputEvent; import android.view.WindowContentFrameStats; import android.view.WindowAnimationFrameStats; @@ -37,7 +38,7 @@ interface IUiAutomationConnection { void disconnect(); boolean injectInputEvent(in InputEvent event, boolean sync); boolean setRotation(int rotation); - Bitmap takeScreenshot(int width, int height); + Bitmap takeScreenshot(in Rect crop, int rotation); boolean clearWindowContentFrameStats(int windowId); WindowContentFrameStats getWindowContentFrameStats(int windowId); void clearWindowAnimationFrameStats(); diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index c99de5ddb776a..8f0168530273b 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -26,6 +26,7 @@ import android.annotation.TestApi; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Point; +import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManagerGlobal; import android.os.IBinder; @@ -690,42 +691,15 @@ public final class UiAutomation { .getRealDisplay(Display.DEFAULT_DISPLAY); Point displaySize = new Point(); display.getRealSize(displaySize); - 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(); // Take the screenshot Bitmap screenShot = null; try { // Calling out without a lock held. - screenShot = mUiAutomationConnection.takeScreenshot((int) screenshotWidth, - (int) screenshotHeight); + screenShot = mUiAutomationConnection.takeScreenshot( + new Rect(0, 0, displaySize.x, displaySize.y), rotation); if (screenShot == null) { return null; } @@ -734,21 +708,6 @@ public final class UiAutomation { return null; } - // Rotate the screenshot to the current orientation - if (rotation != ROTATION_FREEZE_0) { - Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight, - Bitmap.Config.ARGB_8888); - 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); diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index 5e414b837f790..d3828ab478832 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -21,6 +21,7 @@ import android.accessibilityservice.IAccessibilityServiceClient; import android.content.Context; import android.content.pm.IPackageManager; import android.graphics.Bitmap; +import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Binder; import android.os.IBinder; @@ -153,7 +154,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } @Override - public Bitmap takeScreenshot(int width, int height) { + public Bitmap takeScreenshot(Rect crop, int rotation) { synchronized (mLock) { throwIfCalledByNotTrustedUidLocked(); throwIfShutdownLocked(); @@ -161,7 +162,9 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } final long identity = Binder.clearCallingIdentity(); try { - return SurfaceControl.screenshot(width, height); + int width = crop.width(); + int height = crop.height(); + return SurfaceControl.screenshot(crop, width, height, rotation); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index cf059104e3731..37550d87adf30 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -16,6 +16,9 @@ package android.view; +import static android.view.Surface.ROTATION_270; +import static android.view.Surface.ROTATION_90; + import android.annotation.Size; import android.graphics.Bitmap; import android.graphics.GraphicBuffer; @@ -1142,22 +1145,35 @@ public class SurfaceControl { /** * Like {@link SurfaceControl#screenshot(int, int, int, int, boolean)} but - * includes all Surfaces in the screenshot. + * 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. */ - public static Bitmap screenshot(int width, int height) { + public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) { // 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, Surface.ROTATION_0); + if (rotation == ROTATION_90 || rotation == ROTATION_270) { + rotation = (rotation == ROTATION_90) ? ROTATION_270 : ROTATION_90; + } + + SurfaceControl.rotateCropForSF(sourceCrop, rotation); + return nativeScreenshot(displayToken, sourceCrop, width, height, 0, 0, true, + false, rotation); } private static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, @@ -1173,6 +1189,17 @@ public class SurfaceControl { minLayer, maxLayer, allLayers, useIdentityTransform); } + private static void rotateCropForSF(Rect crop, int rot) { + if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { + int tmp = crop.top; + crop.top = crop.left; + crop.left = tmp; + tmp = crop.right; + crop.right = crop.bottom; + crop.bottom = tmp; + } + } + /** * Captures a layer and its children into the provided {@link Surface}. * 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 e9096447bbf6d..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; @@ -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); } }); }