Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc27bc71 authored by chaviw's avatar chaviw
Browse files

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
parent e9bb6aa4
Loading
Loading
Loading
Loading
+16 −15
Original line number Diff line number Diff line
@@ -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);
+23 −12
Original line number Diff line number Diff line
@@ -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) {
+84 −23
Original line number Diff line number Diff line
@@ -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;
}