Updated display capture and screencap to match native functions
Modified Java and JNI display capture functions to match the new function in SurfaceComposerClient. The Java method will send an args object instead of individual arguments to SurfaceComposerClient Test: display screenshots working Test: adb shell screencap Bug: 162367424 Change-Id: Ic8d9cbc626e9ef73300304ce155a50f76f017dfc
This commit is contained in:
@@ -182,16 +182,17 @@ int main(int argc, char** argv)
|
||||
ProcessState::self()->setThreadPoolMaxThreadCount(0);
|
||||
ProcessState::self()->startThreadPool();
|
||||
|
||||
ui::Dataspace outDataspace;
|
||||
sp<GraphicBuffer> outBuffer;
|
||||
|
||||
status_t result = ScreenshotClient::capture(*displayId, &outDataspace, &outBuffer);
|
||||
ScreenCaptureResults captureResults;
|
||||
status_t result = ScreenshotClient::captureDisplay(*displayId, captureResults);
|
||||
if (result != NO_ERROR) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
|
||||
ui::Dataspace dataspace = captureResults.capturedDataspace;
|
||||
sp<GraphicBuffer> buffer = captureResults.buffer;
|
||||
|
||||
result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
|
||||
|
||||
if (base == nullptr || result != NO_ERROR) {
|
||||
String8 reason;
|
||||
@@ -207,13 +208,13 @@ int main(int argc, char** argv)
|
||||
|
||||
if (png) {
|
||||
AndroidBitmapInfo info;
|
||||
info.format = flinger2bitmapFormat(outBuffer->getPixelFormat());
|
||||
info.format = flinger2bitmapFormat(buffer->getPixelFormat());
|
||||
info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
|
||||
info.width = outBuffer->getWidth();
|
||||
info.height = outBuffer->getHeight();
|
||||
info.stride = outBuffer->getStride() * bytesPerPixel(outBuffer->getPixelFormat());
|
||||
info.width = buffer->getWidth();
|
||||
info.height = buffer->getHeight();
|
||||
info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
|
||||
|
||||
int result = AndroidBitmap_compress(&info, static_cast<int32_t>(outDataspace), base,
|
||||
int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base,
|
||||
ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd,
|
||||
[](void* fdPtr, const void* data, size_t size) -> bool {
|
||||
int bytesWritten = write(*static_cast<int*>(fdPtr),
|
||||
@@ -229,11 +230,11 @@ int main(int argc, char** argv)
|
||||
notifyMediaScanner(fn);
|
||||
}
|
||||
} else {
|
||||
uint32_t w = outBuffer->getWidth();
|
||||
uint32_t h = outBuffer->getHeight();
|
||||
uint32_t s = outBuffer->getStride();
|
||||
uint32_t f = outBuffer->getPixelFormat();
|
||||
uint32_t c = dataSpaceToInt(outDataspace);
|
||||
uint32_t w = buffer->getWidth();
|
||||
uint32_t h = buffer->getHeight();
|
||||
uint32_t s = buffer->getStride();
|
||||
uint32_t f = buffer->getPixelFormat();
|
||||
uint32_t c = dataSpaceToInt(dataspace);
|
||||
|
||||
write(fd, &w, 4);
|
||||
write(fd, &h, 4);
|
||||
|
||||
@@ -89,10 +89,8 @@ public final class SurfaceControl implements Parcelable {
|
||||
private static native void nativeWriteToParcel(long nativeObject, Parcel out);
|
||||
private static native void nativeRelease(long nativeObject);
|
||||
private static native void nativeDisconnect(long nativeObject);
|
||||
|
||||
private static native ScreenshotHardwareBuffer nativeScreenshot(IBinder displayToken,
|
||||
Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation,
|
||||
boolean captureSecureLayers);
|
||||
private static native ScreenshotHardwareBuffer nativeCaptureDisplay(
|
||||
DisplayCaptureArgs captureArgs);
|
||||
private static native ScreenshotHardwareBuffer nativeCaptureLayers(IBinder displayToken,
|
||||
long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects,
|
||||
int format);
|
||||
@@ -662,14 +660,14 @@ public final class SurfaceControl implements Parcelable {
|
||||
/**
|
||||
* Each sub class should return itself to allow the builder to chain properly
|
||||
*/
|
||||
public abstract T getThis();
|
||||
abstract T getThis();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The arguments class used to make display capture requests.
|
||||
*
|
||||
* @see #nativeScreenshot(IBinder, Rect, int, int, boolean, int, boolean)
|
||||
* @see #nativeCaptureDisplay(DisplayCaptureArgs)
|
||||
* @hide
|
||||
*/
|
||||
public static class DisplayCaptureArgs extends CaptureArgs {
|
||||
@@ -759,7 +757,7 @@ public final class SurfaceControl implements Parcelable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder getThis() {
|
||||
Builder getThis() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -837,7 +835,7 @@ public final class SurfaceControl implements Parcelable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder getThis() {
|
||||
Builder getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2293,8 +2291,14 @@ public final class SurfaceControl implements Parcelable {
|
||||
throw new IllegalArgumentException("displayToken must not be null");
|
||||
}
|
||||
|
||||
return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation,
|
||||
false /* captureSecureLayers */);
|
||||
DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display)
|
||||
.setSourceCrop(sourceCrop)
|
||||
.setSize(width, height)
|
||||
.setUseIdentityTransform(useIdentityTransform)
|
||||
.setRotation(rotation)
|
||||
.build();
|
||||
|
||||
return nativeCaptureDisplay(captureArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2314,8 +2318,15 @@ public final class SurfaceControl implements Parcelable {
|
||||
throw new IllegalArgumentException("displayToken must not be null");
|
||||
}
|
||||
|
||||
return nativeScreenshot(display, sourceCrop, width, height, useIdentityTransform, rotation,
|
||||
true /* captureSecureLayers */);
|
||||
DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display)
|
||||
.setSourceCrop(sourceCrop)
|
||||
.setSize(width, height)
|
||||
.setUseIdentityTransform(useIdentityTransform)
|
||||
.setRotation(rotation)
|
||||
.setCaptureSecureLayers(true)
|
||||
.build();
|
||||
|
||||
return nativeCaptureDisplay(captureArgs);
|
||||
}
|
||||
|
||||
private static void rotateCropForSF(Rect crop, int rot) {
|
||||
|
||||
@@ -104,6 +104,21 @@ static struct {
|
||||
jfieldID top;
|
||||
} gRectClassInfo;
|
||||
|
||||
static struct {
|
||||
jfieldID pixelFormat;
|
||||
jfieldID sourceCrop;
|
||||
jfieldID frameScale;
|
||||
jfieldID captureSecureLayers;
|
||||
} gCaptureArgsClassInfo;
|
||||
|
||||
static struct {
|
||||
jfieldID displayToken;
|
||||
jfieldID width;
|
||||
jfieldID height;
|
||||
jfieldID useIdentityTransform;
|
||||
jfieldID rotation;
|
||||
} gDisplayCaptureArgsClassInfo;
|
||||
|
||||
// Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
|
||||
void DeleteScreenshot(void* addr, void* context) {
|
||||
delete ((ScreenshotClient*) context);
|
||||
@@ -276,35 +291,60 @@ static Rect rectFromObj(JNIEnv* env, jobject rectObj) {
|
||||
return Rect(left, top, right, bottom);
|
||||
}
|
||||
|
||||
static jobject nativeScreenshot(JNIEnv* env, jclass clazz,
|
||||
jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
|
||||
bool useIdentityTransform, int rotation, bool captureSecureLayers) {
|
||||
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
|
||||
if (displayToken == NULL) {
|
||||
static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs& captureArgs) {
|
||||
captureArgs.pixelFormat = static_cast<ui::PixelFormat>(
|
||||
env->GetIntField(captureArgsObject, gCaptureArgsClassInfo.pixelFormat));
|
||||
captureArgs.sourceCrop =
|
||||
rectFromObj(env,
|
||||
env->GetObjectField(captureArgsObject, gCaptureArgsClassInfo.sourceCrop));
|
||||
captureArgs.frameScale =
|
||||
env->GetFloatField(captureArgsObject, gCaptureArgsClassInfo.frameScale);
|
||||
captureArgs.captureSecureLayers =
|
||||
env->GetBooleanField(captureArgsObject, gCaptureArgsClassInfo.captureSecureLayers);
|
||||
}
|
||||
|
||||
static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
|
||||
jobject displayCaptureArgsObject) {
|
||||
DisplayCaptureArgs captureArgs;
|
||||
getCaptureArgs(env, displayCaptureArgsObject, captureArgs);
|
||||
|
||||
captureArgs.displayToken =
|
||||
ibinderForJavaObject(env,
|
||||
env->GetObjectField(displayCaptureArgsObject,
|
||||
gDisplayCaptureArgsClassInfo.displayToken));
|
||||
captureArgs.width =
|
||||
env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.width);
|
||||
captureArgs.height =
|
||||
env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.height);
|
||||
captureArgs.useIdentityTransform =
|
||||
env->GetBooleanField(displayCaptureArgsObject,
|
||||
gDisplayCaptureArgsClassInfo.useIdentityTransform);
|
||||
captureArgs.rotation = ui::toRotation(
|
||||
env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.rotation));
|
||||
return captureArgs;
|
||||
}
|
||||
|
||||
static jobject nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject) {
|
||||
const DisplayCaptureArgs captureArgs =
|
||||
displayCaptureArgsFromObject(env, displayCaptureArgsObject);
|
||||
|
||||
if (captureArgs.displayToken == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
const ui::ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(displayToken);
|
||||
const ui::Dataspace dataspace = pickDataspaceFromColorMode(colorMode);
|
||||
|
||||
Rect sourceCrop = rectFromObj(env, sourceCropObj);
|
||||
sp<GraphicBuffer> buffer;
|
||||
bool capturedSecureLayers = false;
|
||||
status_t res = ScreenshotClient::capture(displayToken, dataspace,
|
||||
ui::PixelFormat::RGBA_8888,
|
||||
sourceCrop, width, height,
|
||||
useIdentityTransform, ui::toRotation(rotation),
|
||||
captureSecureLayers, &buffer, capturedSecureLayers);
|
||||
ScreenCaptureResults captureResults;
|
||||
status_t res = ScreenshotClient::captureDisplay(captureArgs, captureResults);
|
||||
if (res != NO_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject jhardwareBuffer =
|
||||
android_hardware_HardwareBuffer_createFromAHardwareBuffer(env,
|
||||
buffer->toAHardwareBuffer());
|
||||
const jint namedColorSpace = fromDataspaceToNamedColorSpaceValue(dataspace);
|
||||
jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
|
||||
env, captureResults.buffer->toAHardwareBuffer());
|
||||
const jint namedColorSpace =
|
||||
fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
|
||||
return env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
|
||||
gScreenshotHardwareBufferClassInfo.builder, jhardwareBuffer,
|
||||
namedColorSpace, capturedSecureLayers);
|
||||
namedColorSpace, captureResults.capturedSecureLayers);
|
||||
}
|
||||
|
||||
static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTokenObj,
|
||||
@@ -1614,10 +1654,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
|
||||
(void*)nativeSeverChildren } ,
|
||||
{"nativeSetOverrideScalingMode", "(JJI)V",
|
||||
(void*)nativeSetOverrideScalingMode },
|
||||
{"nativeScreenshot",
|
||||
"(Landroid/os/IBinder;Landroid/graphics/Rect;IIZIZ)"
|
||||
{"nativeCaptureDisplay",
|
||||
"(Landroid/view/SurfaceControl$DisplayCaptureArgs;)"
|
||||
"Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;",
|
||||
(void*)nativeScreenshot },
|
||||
(void*)nativeCaptureDisplay },
|
||||
{"nativeCaptureLayers",
|
||||
"(Landroid/os/IBinder;JLandroid/graphics/Rect;"
|
||||
"F[JI)"
|
||||
@@ -1795,6 +1835,27 @@ int register_android_view_SurfaceControl(JNIEnv* env)
|
||||
gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax =
|
||||
GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMax", "F");
|
||||
|
||||
jclass captureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$CaptureArgs");
|
||||
gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
|
||||
gCaptureArgsClassInfo.sourceCrop =
|
||||
GetFieldIDOrDie(env, captureArgsClazz, "mSourceCrop", "Landroid/graphics/Rect;");
|
||||
gCaptureArgsClassInfo.frameScale = GetFieldIDOrDie(env, captureArgsClazz, "mFrameScale", "F");
|
||||
gCaptureArgsClassInfo.captureSecureLayers =
|
||||
GetFieldIDOrDie(env, captureArgsClazz, "mCaptureSecureLayers", "Z");
|
||||
|
||||
jclass displayCaptureArgsClazz =
|
||||
FindClassOrDie(env, "android/view/SurfaceControl$DisplayCaptureArgs");
|
||||
gDisplayCaptureArgsClassInfo.displayToken =
|
||||
GetFieldIDOrDie(env, displayCaptureArgsClazz, "mDisplayToken", "Landroid/os/IBinder;");
|
||||
gDisplayCaptureArgsClassInfo.width =
|
||||
GetFieldIDOrDie(env, displayCaptureArgsClazz, "mWidth", "I");
|
||||
gDisplayCaptureArgsClassInfo.height =
|
||||
GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I");
|
||||
gDisplayCaptureArgsClassInfo.useIdentityTransform =
|
||||
GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z");
|
||||
gDisplayCaptureArgsClassInfo.rotation =
|
||||
GetFieldIDOrDie(env, displayCaptureArgsClazz, "mRotation", "I");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user