Merge changes from topic "hw_bitmap"
* changes: Update screenshot requests to render proper crop and rotation. Revert "Revert "Updated screenshot code to reflect native changes.""
This commit is contained in:
committed by
Android (Google) Code Review
commit
29fdbc67fc
@@ -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<IBinder> 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<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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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<h ; y++) {
|
||||
write(fd, base, w*Bpp);
|
||||
base = (void *)((char *)base + s*Bpp);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
@@ -253,4 +258,4 @@ int main(int argc, char** argv)
|
||||
|
||||
// b/36066697: Avoid running static destructors.
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -55,8 +58,6 @@ 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);
|
||||
|
||||
@@ -1144,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,
|
||||
@@ -1175,26 +1189,29 @@ 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}.
|
||||
*
|
||||
* @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 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,
|
||||
public static GraphicBuffer captureLayers(IBinder layerHandleToken, Rect sourceCrop,
|
||||
float frameScale) {
|
||||
return nativeCaptureLayers(layerHandleToken, sourceCrop, frameScale);
|
||||
}
|
||||
|
||||
@@ -517,23 +517,7 @@ static jint nativeAttachAndQueueBuffer(JNIEnv *env, jclass clazz, jlong nativeOb
|
||||
jobject graphicBuffer) {
|
||||
Surface* surface = reinterpret_cast<Surface*>(nativeObject);
|
||||
sp<GraphicBuffer> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz,
|
||||
maxLayer = INT32_MAX;
|
||||
}
|
||||
sp<GraphicBuffer> 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<uint32_t>(rotation));
|
||||
sp<GraphicBuffer> buffer;
|
||||
res = ScreenshotClient::capture(displayToken, sourceCrop, width, height,
|
||||
minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(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<SkColorSpace> 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<Bitmap>(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<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
|
||||
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) {
|
||||
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<GraphicBuffer> 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<IBinder> layerHandle = ibinderForJavaObject(env, layerHandleToken);
|
||||
@@ -326,8 +291,7 @@ static jobject nativeCaptureLayersToBuffer(JNIEnv* env, jclass clazz, jobject la
|
||||
}
|
||||
|
||||
sp<GraphicBuffer> 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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Void, Void, Void> {
|
||||
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<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, 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user