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

Commit 932d7167 authored by Chavi Weingarten's avatar Chavi Weingarten Committed by Android (Google) Code Review
Browse files

Merge "Send ScreenCaptureListener to native screen capture requests."

parents 75f48b12 3510924a
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -30,8 +30,9 @@

#include <binder/ProcessState.h>

#include <gui/SurfaceComposerClient.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SyncScreenCaptureListener.h>

#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
@@ -181,13 +182,18 @@ int main(int argc, char** argv)
    ProcessState::self()->setThreadPoolMaxThreadCount(0);
    ProcessState::self()->startThreadPool();

    ScreenCaptureResults captureResults;
    status_t result = ScreenshotClient::captureDisplay(displayId->value, captureResults);
    sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
    status_t result = ScreenshotClient::captureDisplay(displayId->value, captureListener);
    if (result != NO_ERROR) {
        close(fd);
        return 1;
    }

    ScreenCaptureResults captureResults = captureListener->waitForResults();
    if (captureResults.result != NO_ERROR) {
        close(fd);
        return 1;
    }
    ui::Dataspace dataspace = captureResults.capturedDataspace;
    sp<GraphicBuffer> buffer = captureResults.buffer;

+87 −9
Original line number Diff line number Diff line
@@ -65,6 +65,9 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -87,10 +90,10 @@ 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 nativeCaptureDisplay(
            DisplayCaptureArgs captureArgs);
    private static native ScreenshotHardwareBuffer nativeCaptureLayers(
            LayerCaptureArgs captureArgs);
    private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
            ScreenCaptureListener captureListener);
    private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
            ScreenCaptureListener captureListener);
    private static native long nativeMirrorSurface(long mirrorOfObject);
    private static native long nativeCreateTransaction();
    private static native long nativeGetNativeTransactionFinalizer();
@@ -493,6 +496,8 @@ public final class SurfaceControl implements Parcelable {
    private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696;
    private static final int INTERNAL_DATASPACE_SCRGB = 411107328;

    private static final int SCREENSHOT_WAIT_TIME_S = 1;

    private void assignNativeObject(long nativeObject, String callsite) {
        if (mNativeObject != 0) {
            release();
@@ -610,6 +615,13 @@ public final class SurfaceControl implements Parcelable {
        }
    }

    /**
     * @hide
     */
    public abstract static class ScreenCaptureListener {
        abstract void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer);
    }

    /**
     * A common arguments class used for various screenshot requests. This contains arguments that
     * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
@@ -685,7 +697,7 @@ public final class SurfaceControl implements Parcelable {
    /**
     * The arguments class used to make display capture requests.
     *
     * @see #nativeCaptureDisplay(DisplayCaptureArgs)
     * @see #nativeCaptureDisplay(DisplayCaptureArgs, ScreenCaptureListener)
     * @hide
     */
    public static class DisplayCaptureArgs extends CaptureArgs {
@@ -2225,6 +2237,16 @@ public final class SurfaceControl implements Parcelable {
        return getPhysicalDisplayToken(physicalDisplayIds[0]);
    }

    /**
     * @param captureArgs Arguments about how to take the screenshot
     * @param captureListener A listener to receive the screenshot callback
     * @hide
     */
    public static int captureDisplay(@NonNull DisplayCaptureArgs captureArgs,
            @NonNull ScreenCaptureListener captureListener) {
        return nativeCaptureDisplay(captureArgs, captureListener);
    }

    /**
     * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with
     * the content.
@@ -2232,7 +2254,30 @@ public final class SurfaceControl implements Parcelable {
     * @hide
     */
    public static ScreenshotHardwareBuffer captureDisplay(DisplayCaptureArgs captureArgs) {
        return nativeCaptureDisplay(captureArgs);
        final AtomicReference<ScreenshotHardwareBuffer> outHardwareBuffer =
                new AtomicReference<>(null);

        final CountDownLatch countDownLatch = new CountDownLatch(1);
        ScreenCaptureListener screenCaptureListener = new ScreenCaptureListener() {
            @Override
            void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer) {
                outHardwareBuffer.set(hardwareBuffer);
                countDownLatch.countDown();
            }
        };

        int status = captureDisplay(captureArgs, screenCaptureListener);
        if (status != 0) {
            return null;
        }

        try {
            countDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
        } catch (Exception e) {
            Log.e(TAG, "Failed to wait for captureDisplay result", e);
        }

        return outHardwareBuffer.get();
    }

    /**
@@ -2277,14 +2322,37 @@ public final class SurfaceControl implements Parcelable {
                .setPixelFormat(format)
                .build();

        return nativeCaptureLayers(captureArgs);
        return captureLayers(captureArgs);
    }

    /**
     * @hide
     */
    public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) {
        return nativeCaptureLayers(captureArgs);
        final AtomicReference<ScreenshotHardwareBuffer> outHardwareBuffer =
                new AtomicReference<>(null);

        final CountDownLatch countDownLatch = new CountDownLatch(1);
        ScreenCaptureListener screenCaptureListener = new ScreenCaptureListener() {
            @Override
            void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer) {
                outHardwareBuffer.set(hardwareBuffer);
                countDownLatch.countDown();
            }
        };

        int status = captureLayers(captureArgs, screenCaptureListener);
        if (status != 0) {
            return null;
        }

        try {
            countDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
        } catch (Exception e) {
            Log.e(TAG, "Failed to wait for captureLayers result", e);
        }

        return outHardwareBuffer.get();
    }

    /**
@@ -2301,7 +2369,17 @@ public final class SurfaceControl implements Parcelable {
                .setExcludeLayers(exclude)
                .build();

        return nativeCaptureLayers(captureArgs);
        return captureLayers(captureArgs);
    }

    /**
     * @param captureArgs Arguments about how to take the screenshot
     * @param captureListener A listener to receive the screenshot callback
     * @hide
     */
    public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
            @NonNull ScreenCaptureListener captureListener) {
        return nativeCaptureLayers(captureArgs, captureListener);
    }

    /**
+76 −34
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_view_SurfaceSession.h>
#include <gui/IScreenCaptureListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -186,6 +187,11 @@ static struct {
    jmethodID builder;
} gScreenshotHardwareBufferClassInfo;

static struct {
    jclass clazz;
    jmethodID onScreenCaptureComplete;
} gScreenCaptureListenerClassInfo;

static struct {
    jclass clazz;
    jmethodID ctor;
@@ -226,6 +232,54 @@ constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode
    }
}

class ScreenCaptureListenerWrapper : public BnScreenCaptureListener {
public:
    explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) {
        env->GetJavaVM(&mVm);
        screenCaptureListenerObject = env->NewGlobalRef(jobject);
        LOG_ALWAYS_FATAL_IF(!screenCaptureListenerObject, "Failed to make global ref");
    }

    ~ScreenCaptureListenerWrapper() {
        if (screenCaptureListenerObject) {
            getenv()->DeleteGlobalRef(screenCaptureListenerObject);
            screenCaptureListenerObject = nullptr;
        }
    }

    status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) {
        JNIEnv* env = getenv();
        if (captureResults.result != NO_ERROR || captureResults.buffer == nullptr) {
            env->CallVoidMethod(screenCaptureListenerObject,
                                gScreenCaptureListenerClassInfo.onScreenCaptureComplete, nullptr);
            return NO_ERROR;
        }
        jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
                env, captureResults.buffer->toAHardwareBuffer());
        const jint namedColorSpace =
                fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
        jobject screenshotHardwareBuffer =
                env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
                                            gScreenshotHardwareBufferClassInfo.builder,
                                            jhardwareBuffer, namedColorSpace,
                                            captureResults.capturedSecureLayers);
        env->CallVoidMethod(screenCaptureListenerObject,
                            gScreenCaptureListenerClassInfo.onScreenCaptureComplete,
                            screenshotHardwareBuffer);
        return NO_ERROR;
    }

private:
    jobject screenCaptureListenerObject;
    JavaVM* mVm;

    JNIEnv* getenv() {
        JNIEnv* env;
        mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
        return env;
    }
};

// ----------------------------------------------------------------------------

static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
@@ -327,36 +381,28 @@ static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
    return captureArgs;
}

static jobject nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject) {
static jint nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptureArgsObject,
                                 jobject screenCaptureListenerObject) {
    const DisplayCaptureArgs captureArgs =
            displayCaptureArgsFromObject(env, displayCaptureArgsObject);

    if (captureArgs.displayToken == NULL) {
        return NULL;
    }

    ScreenCaptureResults captureResults;
    status_t res = ScreenshotClient::captureDisplay(captureArgs, captureResults);
    if (res != NO_ERROR) {
        return NULL;
        return BAD_VALUE;
    }

    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, captureResults.capturedSecureLayers);
    sp<IScreenCaptureListener> captureListener =
            new ScreenCaptureListenerWrapper(env, screenCaptureListenerObject);
    return ScreenshotClient::captureDisplay(captureArgs, captureListener);
}

static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject) {
static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject,
                                jobject screenCaptureListenerObject) {
    LayerCaptureArgs captureArgs;
    getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
    SurfaceControl* layer = reinterpret_cast<SurfaceControl*>(
            env->GetLongField(layerCaptureArgsObject, gLayerCaptureArgsClassInfo.layer));
    if (layer == nullptr) {
        return nullptr;
        return BAD_VALUE;
    }

    captureArgs.layerHandle = layer->getHandle();
@@ -380,19 +426,9 @@ static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptu
        env->ReleaseLongArrayElements(excludeObjectArray, const_cast<jlong*>(objects), JNI_ABORT);
    }

    ScreenCaptureResults captureResults;
    status_t res = ScreenshotClient::captureLayers(captureArgs, captureResults);
    if (res != NO_ERROR) {
        return NULL;
    }

    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, captureResults.capturedSecureLayers);
    sp<IScreenCaptureListener> captureListener =
            new ScreenCaptureListenerWrapper(env, screenCaptureListenerObject);
    return ScreenshotClient::captureLayers(captureArgs, captureListener);
}

static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
@@ -1507,6 +1543,7 @@ static jlong nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {

// ----------------------------------------------------------------------------

// clang-format off
static const JNINativeMethod sSurfaceControlMethods[] = {
    {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJLandroid/os/Parcel;)J",
            (void*)nativeCreate },
@@ -1649,12 +1686,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
    {"nativeSetOverrideScalingMode", "(JJI)V",
            (void*)nativeSetOverrideScalingMode },
    {"nativeCaptureDisplay",
            "(Landroid/view/SurfaceControl$DisplayCaptureArgs;)"
            "Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;",
            "(Landroid/view/SurfaceControl$DisplayCaptureArgs;Landroid/view/SurfaceControl$ScreenCaptureListener;)I",
            (void*)nativeCaptureDisplay },
    {"nativeCaptureLayers",
            "(Landroid/view/SurfaceControl$LayerCaptureArgs;)"
            "Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;",
            "(Landroid/view/SurfaceControl$LayerCaptureArgs;Landroid/view/SurfaceControl$ScreenCaptureListener;)I",
            (void*)nativeCaptureLayers },
    {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
            (void*)nativeSetInputWindowInfo },
@@ -1688,6 +1723,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
            (void*)nativeGetHandle },
    {"nativeSetFixedTransformHint", "(JJI)V", (void*)nativeSetFixedTransformHint},
};
// clang-format on

int register_android_view_SurfaceControl(JNIEnv* env)
{
@@ -1856,6 +1892,12 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    gLayerCaptureArgsClassInfo.childrenOnly =
            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mChildrenOnly", "Z");

    jclass screenCaptureListenerClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$ScreenCaptureListener");
    gScreenCaptureListenerClassInfo.clazz = MakeGlobalRefOrDie(env, screenCaptureListenerClazz);
    gScreenCaptureListenerClassInfo.onScreenCaptureComplete =
            GetMethodIDOrDie(env, screenCaptureListenerClazz, "onScreenCaptureComplete",
                             "(Landroid/view/SurfaceControl$ScreenshotHardwareBuffer;)V");
    return err;
}