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

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

Merge "Add captureDisplay API in WMS."

parents 78282c61 c184fd71
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import android.view.SurfaceControl;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import android.window.ITaskFpsCallback;
import android.window.ScreenCapture;

/**
 * System private interface to the window manager.
@@ -968,4 +969,7 @@ interface IWindowManager
     * treatment.
     */
    boolean isLetterboxBackgroundMultiColored();

    oneway void captureDisplay(int displayId, in @nullable ScreenCapture.CaptureArgs captureArgs,
            in ScreenCapture.ScreenCaptureListener listener);
}
+26 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.window;

/** @hide */
parcelable ScreenCapture.CaptureArgs;

/** @hide */
parcelable ScreenCapture.ScreenshotHardwareBuffer;

/** @hide */
parcelable ScreenCapture.ScreenCaptureListener;
 No newline at end of file
+215 −79
Original line number Diff line number Diff line
@@ -24,11 +24,16 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import android.view.SurfaceControl;

import libcore.util.NativeAllocationRegistry;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * Handles display and layer captures for the system.
@@ -39,9 +44,14 @@ public class ScreenCapture {
    private static final String TAG = "ScreenCapture";

    private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
            ScreenCaptureListener captureListener);
            long captureListener);
    private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
            ScreenCaptureListener captureListener);
            long captureListener);
    private static native long nativeCreateScreenCaptureListener(
            Consumer<ScreenshotHardwareBuffer> consumer);
    private static native void nativeWriteListenerToParcel(long nativeObject, Parcel out);
    private static native long nativeReadListenerFromParcel(Parcel in);
    private static native long getNativeListenerFinalizer();

    /**
     * @param captureArgs     Arguments about how to take the screenshot
@@ -50,7 +60,7 @@ public class ScreenCapture {
     */
    public static int captureDisplay(@NonNull DisplayCaptureArgs captureArgs,
            @NonNull ScreenCaptureListener captureListener) {
        return nativeCaptureDisplay(captureArgs, captureListener);
        return nativeCaptureDisplay(captureArgs, captureListener.mNativeObject);
    }

    /**
@@ -61,10 +71,8 @@ public class ScreenCapture {
     */
    public static ScreenshotHardwareBuffer captureDisplay(
            DisplayCaptureArgs captureArgs) {
        SyncScreenCaptureListener
                screenCaptureListener = new SyncScreenCaptureListener();

        int status = captureDisplay(captureArgs, screenCaptureListener);
        SyncScreenCaptureListener screenCaptureListener = new SyncScreenCaptureListener();
        int status = captureDisplay(captureArgs, screenCaptureListener.getScreenCaptureListener());
        if (status != 0) {
            return null;
        }
@@ -80,9 +88,8 @@ public class ScreenCapture {
     *                   Rect()' or null if no cropping is desired. If the root layer does not
     *                   have a buffer or a crop set, then a non-empty source crop must be
     *                   specified.
     * @param frameScale       The desired scale of the returned buffer; the raw
     *                         screen will be scaled up/down.
     *
     * @param frameScale The desired scale of the returned buffer; the raw screen will be scaled
     *                   up/down.
     * @return Returns a HardwareBuffer that contains the layer capture.
     * @hide
     */
@@ -99,10 +106,9 @@ public class ScreenCapture {
     *                   Rect()' or null if no cropping is desired. If the root layer does not
     *                   have a buffer or a crop set, then a non-empty source crop must be
     *                   specified.
     * @param frameScale       The desired scale of the returned buffer; the raw
     *                         screen will be scaled up/down.
     * @param frameScale The desired scale of the returned buffer; the raw screen will be scaled
     *                   up/down.
     * @param format     The desired pixel format of the returned buffer.
     *
     * @return Returns a HardwareBuffer that contains the layer capture.
     * @hide
     */
@@ -124,7 +130,7 @@ public class ScreenCapture {
            LayerCaptureArgs captureArgs) {
        SyncScreenCaptureListener screenCaptureListener = new SyncScreenCaptureListener();

        int status = captureLayers(captureArgs, screenCaptureListener);
        int status = captureLayers(captureArgs, screenCaptureListener.getScreenCaptureListener());
        if (status != 0) {
            return null;
        }
@@ -135,6 +141,7 @@ public class ScreenCapture {
    /**
     * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer
     * handles to exclude.
     *
     * @hide
     */
    public static ScreenshotHardwareBuffer captureLayersExcluding(SurfaceControl layer,
@@ -156,18 +163,7 @@ public class ScreenCapture {
     */
    public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
            @NonNull ScreenCaptureListener captureListener) {
        return nativeCaptureLayers(captureArgs, captureListener);
    }

    /**
     * @hide
     */
    public interface ScreenCaptureListener {
        /**
         * The callback invoked when the screen capture is complete.
         * @param hardwareBuffer Data containing info about the screen capture.
         */
        void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer);
        return nativeCaptureLayers(captureArgs, captureListener.mNativeObject);
    }

    /**
@@ -192,6 +188,7 @@ public class ScreenCapture {

        /**
         * Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
         *
         * @param hardwareBuffer       The existing HardwareBuffer object
         * @param namedColorSpace      Integer value of a named color space {@link ColorSpace.Named}
         * @param containsSecureLayers Indicates whether this graphic buffer contains captured
@@ -220,6 +217,7 @@ public class ScreenCapture {
        public boolean containsSecureLayers() {
            return mContainsSecureLayers;
        }

        /**
         * Returns whether the screenshot contains at least one HDR layer.
         * This information may be useful for informing the display whether this screenshot
@@ -234,7 +232,7 @@ public class ScreenCapture {
         * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap
         * into
         * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
         *
         * <p>
         * CAVEAT: This can be extremely slow; avoid use unless absolutely necessary; prefer to
         * directly
         * use the {@link HardwareBuffer} directly.
@@ -250,34 +248,13 @@ public class ScreenCapture {
        }
    }

    private static class SyncScreenCaptureListener implements ScreenCaptureListener {
        private static final int SCREENSHOT_WAIT_TIME_S = 1;
        private ScreenshotHardwareBuffer mScreenshotHardwareBuffer;
        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);

        @Override
        public void onScreenCaptureComplete(ScreenshotHardwareBuffer hardwareBuffer) {
            mScreenshotHardwareBuffer = hardwareBuffer;
            mCountDownLatch.countDown();
        }

        private ScreenshotHardwareBuffer waitForScreenshot() {
            try {
                mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
            } catch (Exception e) {
                Log.e(TAG, "Failed to wait for screen capture result", e);
            }

            return mScreenshotHardwareBuffer;
        }
    }

    /**
     * A common arguments class used for various screenshot requests. This contains arguments that
     * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
     *
     * @hide
     */
    private abstract static class CaptureArgs {
    public static class CaptureArgs implements Parcelable {
        private final int mPixelFormat;
        private final Rect mSourceCrop = new Rect();
        private final float mFrameScaleX;
@@ -287,7 +264,7 @@ public class ScreenCapture {
        private final long mUid;
        private final boolean mGrayscale;

        private CaptureArgs(Builder<? extends Builder<?>> builder) {
        private CaptureArgs(CaptureArgs.Builder<? extends CaptureArgs.Builder<?>> builder) {
            mPixelFormat = builder.mPixelFormat;
            mSourceCrop.set(builder.mSourceCrop);
            mFrameScaleX = builder.mFrameScaleX;
@@ -298,12 +275,23 @@ public class ScreenCapture {
            mGrayscale = builder.mGrayscale;
        }

        private CaptureArgs(Parcel in) {
            mPixelFormat = in.readInt();
            mSourceCrop.readFromParcel(in);
            mFrameScaleX = in.readFloat();
            mFrameScaleY = in.readFloat();
            mCaptureSecureLayers = in.readBoolean();
            mAllowProtected = in.readBoolean();
            mUid = in.readLong();
            mGrayscale = in.readBoolean();
        }

        /**
         * The Builder class used to construct {@link CaptureArgs}
         *
         * @param <T> A builder that extends {@link Builder}
         * @param <T> A builder that extends {@link CaptureArgs.Builder}
         */
        abstract static class Builder<T extends Builder<T>> {
        public static class Builder<T extends CaptureArgs.Builder<T>> {
            private int mPixelFormat = PixelFormat.RGBA_8888;
            private final Rect mSourceCrop = new Rect();
            private float mFrameScaleX = 1;
@@ -313,6 +301,14 @@ public class ScreenCapture {
            private long mUid = -1;
            private boolean mGrayscale;

            /**
             * Construct a new {@link CaptureArgs} with the set parameters. The builder remains
             * valid.
             */
            public CaptureArgs build() {
                return new CaptureArgs(this);
            }

            /**
             * The desired pixel format of the returned buffer.
             */
@@ -395,15 +391,47 @@ public class ScreenCapture {
            /**
             * Each sub class should return itself to allow the builder to chain properly
             */
            abstract T getThis();
            T getThis() {
                return (T) this;
            }
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeInt(mPixelFormat);
            mSourceCrop.writeToParcel(dest, flags);
            dest.writeFloat(mFrameScaleX);
            dest.writeFloat(mFrameScaleY);
            dest.writeBoolean(mCaptureSecureLayers);
            dest.writeBoolean(mAllowProtected);
            dest.writeLong(mUid);
            dest.writeBoolean(mGrayscale);
        }

        public static final Parcelable.Creator<CaptureArgs> CREATOR =
                new Parcelable.Creator<CaptureArgs>() {
                    @Override
                    public CaptureArgs createFromParcel(Parcel in) {
                        return new CaptureArgs(in);
                    }

                    @Override
                    public CaptureArgs[] newArray(int size) {
                        return new CaptureArgs[size];
                    }
                };
    }

    /**
     * The arguments class used to make display capture requests.
     *
     * @see #nativeCaptureDisplay(DisplayCaptureArgs, ScreenCaptureListener)
     * @hide
     * @see #nativeCaptureDisplay(DisplayCaptureArgs, long)
     */
    public static class DisplayCaptureArgs extends CaptureArgs {
        private final IBinder mDisplayToken;
@@ -488,8 +516,8 @@ public class ScreenCapture {
    /**
     * The arguments class used to make layer capture requests.
     *
     * @see #nativeCaptureLayers(LayerCaptureArgs, ScreenCaptureListener)
     * @hide
     * @see #nativeCaptureLayers(LayerCaptureArgs, long)
     */
    public static class LayerCaptureArgs extends CaptureArgs {
        private final long mNativeLayer;
@@ -530,6 +558,17 @@ public class ScreenCapture {
                return new LayerCaptureArgs(this);
            }

            public Builder(SurfaceControl layer, CaptureArgs args) {
                setLayer(layer);
                setPixelFormat(args.mPixelFormat);
                setSourceCrop(args.mSourceCrop);
                setFrameScale(args.mFrameScaleX, args.mFrameScaleY);
                setCaptureSecureLayers(args.mCaptureSecureLayers);
                setAllowProtected(args.mAllowProtected);
                setUid(args.mUid);
                setGrayscale(args.mGrayscale);
            }

            public Builder(SurfaceControl layer) {
                setLayer(layer);
            }
@@ -542,7 +581,6 @@ public class ScreenCapture {
                return this;
            }


            /**
             * An array of layer handles to exclude.
             */
@@ -564,8 +602,106 @@ public class ScreenCapture {
            Builder getThis() {
                return this;
            }
        }
    }

    /**
     * The object used to receive the results when invoking screen capture requests via
     * {@link #captureDisplay(DisplayCaptureArgs, ScreenCaptureListener)} or
     * {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)}
     */
    public static class ScreenCaptureListener implements Parcelable {
        private final long mNativeObject;
        private static final NativeAllocationRegistry sRegistry =
                NativeAllocationRegistry.createMalloced(
                        ScreenCaptureListener.class.getClassLoader(), getNativeListenerFinalizer());

        /**
         * @param consumer The callback invoked when the screen capture is complete.
         */
        public ScreenCaptureListener(Consumer<ScreenshotHardwareBuffer> consumer) {
            mNativeObject = nativeCreateScreenCaptureListener(consumer);
            sRegistry.registerNativeAllocation(this, mNativeObject);
        }

        private ScreenCaptureListener(Parcel in) {
            if (in.readBoolean()) {
                mNativeObject = nativeReadListenerFromParcel(in);
                sRegistry.registerNativeAllocation(this, mNativeObject);
            } else {
                mNativeObject = 0;
            }
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            if (mNativeObject == 0) {
                dest.writeBoolean(false);
            } else {
                dest.writeBoolean(true);
                nativeWriteListenerToParcel(mNativeObject, dest);
            }
        }

        public static final Parcelable.Creator<ScreenCaptureListener> CREATOR =
                new Parcelable.Creator<ScreenCaptureListener>() {
                    @Override
                    public ScreenCaptureListener createFromParcel(Parcel in) {
                        return new ScreenCaptureListener(in);
                    }

                    @Override
                    public ScreenCaptureListener[] newArray(int size) {
                        return new ScreenCaptureListener[0];
                    }
                };
    }

    /**
     * A helper class to handle the async screencapture callbacks synchronously. This should only
     * be used if the screencapture caller doesn't care that it blocks waiting for a screenshot.
     */
    public static class SyncScreenCaptureListener {
        private static final int SCREENSHOT_WAIT_TIME_S = 1;
        private ScreenshotHardwareBuffer mScreenshotHardwareBuffer;
        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
        private final ScreenCaptureListener mScreenCaptureListener;

        public SyncScreenCaptureListener() {
            mScreenCaptureListener = new ScreenCaptureListener(screenshotHardwareBuffer -> {
                mScreenshotHardwareBuffer = screenshotHardwareBuffer;
                mCountDownLatch.countDown();
            });
        }

        /**
         * @return The underlying {@link ScreenCaptureListener}
         */
        public ScreenCaptureListener getScreenCaptureListener() {
            return mScreenCaptureListener;
        }

        /**
         * Waits until the screenshot callback has been invoked and the screenshot is ready. This
         * can return {@code null} if the screenshot callback wasn't invoked after
         * {@link #SCREENSHOT_WAIT_TIME_S} or the screencapture request resulted in an error
         *
         * @return A ScreenshotHardwareBuffer for the content that was captured.
         */
        @Nullable
        public ScreenshotHardwareBuffer waitForScreenshot() {
            try {
                mCountDownLatch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
            } catch (Exception e) {
                Log.e(TAG, "Failed to wait for screen capture result", e);
            }

            return mScreenshotHardwareBuffer;
        }
    }
}
+73 −32
Original line number Diff line number Diff line
@@ -61,9 +61,8 @@ static struct {
} gLayerCaptureArgsClassInfo;

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

static struct {
    jclass clazz;
@@ -98,14 +97,14 @@ class ScreenCaptureListenerWrapper : public gui::BnScreenCaptureListener {
public:
    explicit ScreenCaptureListenerWrapper(JNIEnv* env, jobject jobject) {
        env->GetJavaVM(&mVm);
        mScreenCaptureListenerObject = env->NewGlobalRef(jobject);
        LOG_ALWAYS_FATAL_IF(!mScreenCaptureListenerObject, "Failed to make global ref");
        mConsumerObject = env->NewGlobalRef(jobject);
        LOG_ALWAYS_FATAL_IF(!mConsumerObject, "Failed to make global ref");
    }

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

@@ -113,9 +112,8 @@ public:
            const gui::ScreenCaptureResults& captureResults) override {
        JNIEnv* env = getenv();
        if (!captureResults.fenceResult.ok() || captureResults.buffer == nullptr) {
            env->CallVoidMethod(mScreenCaptureListenerObject,
                                gScreenCaptureListenerClassInfo.onScreenCaptureComplete, nullptr);
            checkAndClearException(env, "onScreenCaptureComplete");
            env->CallVoidMethod(mConsumerObject, gConsumerClassInfo.accept, nullptr);
            checkAndClearException(env, "accept");
            return binder::Status::ok();
        }
        captureResults.fenceResult.value()->waitForever(LOG_TAG);
@@ -130,17 +128,15 @@ public:
                                            captureResults.capturedSecureLayers,
                                            captureResults.capturedHdrLayers);
        checkAndClearException(env, "builder");
        env->CallVoidMethod(mScreenCaptureListenerObject,
                            gScreenCaptureListenerClassInfo.onScreenCaptureComplete,
                            screenshotHardwareBuffer);
        checkAndClearException(env, "onScreenCaptureComplete");
        env->CallVoidMethod(mConsumerObject, gConsumerClassInfo.accept, screenshotHardwareBuffer);
        checkAndClearException(env, "accept");
        env->DeleteLocalRef(jhardwareBuffer);
        env->DeleteLocalRef(screenshotHardwareBuffer);
        return binder::Status::ok();
    }

private:
    jobject mScreenCaptureListenerObject;
    jobject mConsumerObject;
    JavaVM* mVm;

    JNIEnv* getenv() {
@@ -194,7 +190,7 @@ static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
}

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

@@ -202,13 +198,13 @@ static jint nativeCaptureDisplay(JNIEnv* env, jclass clazz, jobject displayCaptu
        return BAD_VALUE;
    }

    sp<IScreenCaptureListener> captureListener =
            sp<ScreenCaptureListenerWrapper>::make(env, screenCaptureListenerObject);
    sp<gui::IScreenCaptureListener> captureListener =
            reinterpret_cast<gui::IScreenCaptureListener*>(screenCaptureListenerObject);
    return ScreenshotClient::captureDisplay(captureArgs, captureListener);
}

static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject,
                                jobject screenCaptureListenerObject) {
                                jlong screenCaptureListenerObject) {
    LayerCaptureArgs captureArgs;
    getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
    SurfaceControl* layer = reinterpret_cast<SurfaceControl*>(
@@ -238,21 +234,70 @@ static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureA
        }
    }

    sp<IScreenCaptureListener> captureListener =
            sp<ScreenCaptureListenerWrapper>::make(env, screenCaptureListenerObject);
    sp<gui::IScreenCaptureListener> captureListener =
            reinterpret_cast<gui::IScreenCaptureListener*>(screenCaptureListenerObject);
    return ScreenshotClient::captureLayers(captureArgs, captureListener);
}

static jlong nativeCreateScreenCaptureListener(JNIEnv* env, jclass clazz, jobject consumerObj) {
    sp<gui::IScreenCaptureListener> listener =
            sp<ScreenCaptureListenerWrapper>::make(env, consumerObj);
    listener->incStrong((void*)nativeCreateScreenCaptureListener);
    return reinterpret_cast<jlong>(listener.get());
}

static void nativeWriteListenerToParcel(JNIEnv* env, jclass clazz, jlong nativeObject,
                                        jobject parcelObj) {
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    if (parcel == NULL) {
        jniThrowNullPointerException(env, NULL);
        return;
    }
    ScreenCaptureListenerWrapper* const self =
            reinterpret_cast<ScreenCaptureListenerWrapper*>(nativeObject);
    if (self != nullptr) {
        parcel->writeStrongBinder(IInterface::asBinder(self));
    }
}

static jlong nativeReadListenerFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    if (parcel == NULL) {
        jniThrowNullPointerException(env, NULL);
        return 0;
    }
    sp<gui::IScreenCaptureListener> listener =
            interface_cast<gui::IScreenCaptureListener>(parcel->readStrongBinder());
    if (listener == nullptr) {
        return 0;
    }
    listener->incStrong((void*)nativeCreateScreenCaptureListener);
    return reinterpret_cast<jlong>(listener.get());
}

void destroyNativeListener(void* ptr) {
    ScreenCaptureListenerWrapper* listener = reinterpret_cast<ScreenCaptureListenerWrapper*>(ptr);
    listener->decStrong((void*)nativeCreateScreenCaptureListener);
}

static jlong getNativeListenerFinalizer(JNIEnv* env, jclass clazz) {
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeListener));
}

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

static const JNINativeMethod sScreenCaptureMethods[] = {
        // clang-format off
   {"nativeCaptureDisplay",
            "(Landroid/window/ScreenCapture$DisplayCaptureArgs;Landroid/window/ScreenCapture$ScreenCaptureListener;)I",
    {"nativeCaptureDisplay", "(Landroid/window/ScreenCapture$DisplayCaptureArgs;J)I",
            (void*)nativeCaptureDisplay },
    {"nativeCaptureLayers",
            "(Landroid/window/ScreenCapture$LayerCaptureArgs;Landroid/window/ScreenCapture$ScreenCaptureListener;)I",
    {"nativeCaptureLayers",  "(Landroid/window/ScreenCapture$LayerCaptureArgs;J)I",
            (void*)nativeCaptureLayers },
    {"nativeCreateScreenCaptureListener", "(Ljava/util/function/Consumer;)J",
            (void*)nativeCreateScreenCaptureListener },
    {"nativeWriteListenerToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteListenerToParcel },
    {"nativeReadListenerFromParcel", "(Landroid/os/Parcel;)J",
            (void*)nativeReadListenerFromParcel },
    {"getNativeListenerFinalizer", "()J", (void*)getNativeListenerFinalizer },
        // clang-format on
};

@@ -293,12 +338,8 @@ int register_android_window_ScreenCapture(JNIEnv* env) {
    gLayerCaptureArgsClassInfo.childrenOnly =
            GetFieldIDOrDie(env, layerCaptureArgsClazz, "mChildrenOnly", "Z");

    jclass screenCaptureListenerClazz =
            FindClassOrDie(env, "android/window/ScreenCapture$ScreenCaptureListener");
    gScreenCaptureListenerClassInfo.clazz = MakeGlobalRefOrDie(env, screenCaptureListenerClazz);
    gScreenCaptureListenerClassInfo.onScreenCaptureComplete =
            GetMethodIDOrDie(env, screenCaptureListenerClazz, "onScreenCaptureComplete",
                             "(Landroid/window/ScreenCapture$ScreenshotHardwareBuffer;)V");
    jclass consumer = FindClassOrDie(env, "java/util/function/Consumer");
    gConsumerClassInfo.accept = GetMethodIDOrDie(env, consumer, "accept", "(Ljava/lang/Object;)V");

    jclass screenshotGraphicsBufferClazz =
            FindClassOrDie(env, "android/window/ScreenCapture$ScreenshotHardwareBuffer");
+34 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading