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

Commit ba66b256 authored by Chavi Weingarten's avatar Chavi Weingarten
Browse files

Add JNI and public methods for TrustedPresentationCallback

Test: TrustedPresentationCallbackTest
Bug: 256993331
Change-Id: Iade93f73c55264886ef647e4fd24af614fe871d2
parent a49c09f3
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -51183,6 +51183,7 @@ package android.view {
    method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
    method public void apply();
    method @NonNull public android.view.SurfaceControl.Transaction clearFrameRate(@NonNull android.view.SurfaceControl);
    method @NonNull public android.view.SurfaceControl.Transaction clearTrustedPresentationCallback(@NonNull android.view.SurfaceControl);
    method public void close();
    method public int describeContents();
    method @NonNull public android.view.SurfaceControl.Transaction merge(@NonNull android.view.SurfaceControl.Transaction);
@@ -51203,6 +51204,7 @@ package android.view {
    method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
    method @NonNull public android.view.SurfaceControl.Transaction setPosition(@NonNull android.view.SurfaceControl, float, float);
    method @NonNull public android.view.SurfaceControl.Transaction setScale(@NonNull android.view.SurfaceControl, float, float);
    method @NonNull public android.view.SurfaceControl.Transaction setTrustedPresentationCallback(@NonNull android.view.SurfaceControl, @NonNull android.view.SurfaceControl.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
    method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean);
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.view.SurfaceControl.Transaction> CREATOR;
@@ -51212,6 +51214,10 @@ package android.view {
    method public void onTransactionCommitted();
  }
  public static class SurfaceControl.TrustedPresentationThresholds {
    ctor public SurfaceControl.TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int);
  }
  public class SurfaceControlViewHost {
    ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
    method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();
+181 −1
Original line number Diff line number Diff line
@@ -280,7 +280,12 @@ public final class SurfaceControl implements Parcelable {
    private static native void nativeSetDefaultApplyToken(IBinder token);
    private static native IBinder nativeGetDefaultApplyToken();
    private static native boolean nativeBootFinished();

    private static native long nativeCreateTpc(TrustedPresentationCallback callback);
    private static native long getNativeTrustedPresentationCallbackFinalizer();
    private static native void nativeSetTrustedPresentationCallback(long transactionObj,
            long nativeObject, long nativeTpc, TrustedPresentationThresholds thresholds);
    private static native void nativeClearTrustedPresentationCallback(long transactionObj,
            long nativeObject);

    /**
     * Transforms that can be applied to buffers as they are displayed to a window.
@@ -465,6 +470,8 @@ public final class SurfaceControl implements Parcelable {
    @GuardedBy("mLock")
    private int mHeight;

    private TrustedPresentationCallback mTrustedPresentationCallback;

    private WeakReference<View> mLocalOwnerView;

    static GlobalTransactionWrapper sGlobalTransaction;
@@ -2399,6 +2406,79 @@ public final class SurfaceControl implements Parcelable {
        void onTransactionCommitted();
    }

    /**
     * Threshold values that are sent with
     * {@link Transaction#setTrustedPresentationCallback(SurfaceControl,
     * TrustedPresentationThresholds, Executor, Consumer)}
     */
    public static class TrustedPresentationThresholds {
        private float mMinAlpha;
        private float mMinFractionRendered;
        private int mStabilityRequirementMs;

        /**
         * Creates a TrustedPresentationThresholds that's used when calling
         * {@link Transaction#setTrustedPresentationCallback(SurfaceControl,
         * TrustedPresentationThresholds, Executor, Consumer)}
         *
         * @param minAlpha               The min alpha the {@link SurfaceControl} is required to
         *                               have to be considered inside the threshold.
         * @param minFractionRendered    The min fraction of the SurfaceControl that was resented
         *                               to the user to be considered inside the threshold.
         * @param stabilityRequirementMs The time in milliseconds required for the
         *                               {@link SurfaceControl} to be in the threshold.
         * @throws IllegalArgumentException If threshold values are invalid.
         */
        public TrustedPresentationThresholds(
                @FloatRange(from = 0f, fromInclusive = false, to = 1f) float minAlpha,
                @FloatRange(from = 0f, fromInclusive = false, to = 1f) float minFractionRendered,
                @IntRange(from = 1) int stabilityRequirementMs) {
            mMinAlpha = minAlpha;
            mMinFractionRendered = minFractionRendered;
            mStabilityRequirementMs = stabilityRequirementMs;

            checkValid();
        }

        private void checkValid() {
            if (mMinAlpha <= 0 || mMinFractionRendered <= 0 || mStabilityRequirementMs < 1) {
                throw new IllegalArgumentException(
                        "TrustedPresentationThresholds values are invalid");
            }
        }
    }

    /**
     * Register a TrustedPresentationCallback for a particular SurfaceControl so it can be notified
     * when the specified Threshold has been crossed.
     *
     * @hide
     */
    public abstract static class TrustedPresentationCallback {
        private final long mNativeObject;

        private static final NativeAllocationRegistry sRegistry =
                NativeAllocationRegistry.createMalloced(
                        TrustedPresentationCallback.class.getClassLoader(),
                        getNativeTrustedPresentationCallbackFinalizer());

        private final Runnable mFreeNativeResources;

        private TrustedPresentationCallback() {
            mNativeObject = nativeCreateTpc(this);
            mFreeNativeResources = sRegistry.registerNativeAllocation(this, mNativeObject);
        }

        /**
         * Invoked when the SurfaceControl that this TrustedPresentationCallback was registered for
         * enters or exits the threshold bounds.
         *
         * @param inTrustedPresentationState true when the SurfaceControl entered the
         *                                   presentation state, false when it has left.
         */
        public abstract void onTrustedPresentationChanged(boolean inTrustedPresentationState);
    }

    /**
     * An atomic set of changes to a set of SurfaceControl.
     */
@@ -3776,6 +3856,106 @@ public final class SurfaceControl implements Parcelable {
            return this;
        }

        /**
         * Sets a callback to receive feedback about the presentation of a {@link SurfaceControl}.
         * When the {@link SurfaceControl} is presented according to the passed in
         * {@link TrustedPresentationThresholds}, it is said to "enter the state", and receives the
         * callback with {@code true}. When the conditions fall out of thresholds, it is then
         * said to leave the state.
         * <p>
         * There are a few simple thresholds:
         * <ul>
         *    <li>minAlpha: Lower bound on computed alpha</li>
         *    <li>minFractionRendered: Lower bounds on fraction of pixels that were rendered</li>
         *    <li>stabilityThresholdMs: A time that alpha and fraction rendered must remain within
         *    bounds before we can "enter the state" </li>
         * </ul>
         * <p>
         * The fraction of pixels rendered is a computation based on scale, crop
         * and occlusion. The calculation may be somewhat counterintuitive, so we
         * can work through an example. Imagine we have a SurfaceControl with a 100x100 buffer
         * which is occluded by (10x100) pixels on the left, and cropped by (100x10) pixels
         * on the top. Furthermore imagine this SurfaceControl is scaled by 0.9 in both dimensions.
         * (c=crop,o=occluded,b=both,x=none)
         *
         * <blockquote>
         * <table>
         *   <caption></caption>
         *   <tr><td>b</td><td>c</td><td>c</td><td>c</td></tr>
         *   <tr><td>o</td><td>x</td><td>x</td><td>x</td></tr>
         *   <tr><td>o</td><td>x</td><td>x</td><td>x</td></tr>
         *   <tr><td>o</td><td>x</td><td>x</td><td>x</td></tr>
         * </table>
         * </blockquote>
         *
         *<p>
         * We first start by computing fr=xscale*yscale=0.9*0.9=0.81, indicating
         * that "81%" of the pixels were rendered. This corresponds to what was 100
         * pixels being displayed in 81 pixels. This is somewhat of an abuse of
         * language, as the information of merged pixels isn't totally lost, but
         * we err on the conservative side.
         * <p>
         * We then repeat a similar process for the crop and covered regions and
         * accumulate the results: fr = fr * (fractionNotCropped) * (fractionNotCovered)
         * So for this example we would get 0.9*0.9*0.9*0.9=0.65...
         * <p>
         * Notice that this is not completely accurate, as we have double counted
         * the region marked as b. However we only wanted a "lower bound" and so it
         * is ok to err in this direction. Selection of the threshold will ultimately
         * be somewhat arbitrary, and so there are some somewhat arbitrary decisions in
         * this API as well.
         * <p>
         * @param sc         The {@link SurfaceControl} to set the
         *                   {@link TrustedPresentationCallback} on
         * @param thresholds The {@link TrustedPresentationThresholds} that will specify when the to
         *                   invoke the callback.
         * @param executor   The {@link Executor} where the callback will be invoked on.
         * @param listener   The {@link Consumer} that will receive the callbacks when entered or
         *                   exited the threshold.
         * @return This transaction
         * @see TrustedPresentationThresholds
         */
        @NonNull
        public Transaction setTrustedPresentationCallback(@NonNull SurfaceControl sc,
                @NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor,
                @NonNull Consumer<Boolean> listener) {
            checkPreconditions(sc);
            TrustedPresentationCallback tpc = new TrustedPresentationCallback() {
                @Override
                public void onTrustedPresentationChanged(boolean inTrustedPresentationState) {
                    executor.execute(
                            () -> listener.accept(inTrustedPresentationState));
                }
            };

            if (sc.mTrustedPresentationCallback != null) {
                sc.mTrustedPresentationCallback.mFreeNativeResources.run();
            }

            nativeSetTrustedPresentationCallback(mNativeObject, sc.mNativeObject,
                    tpc.mNativeObject, thresholds);
            sc.mTrustedPresentationCallback = tpc;
            return this;
        }

        /**
         * Clears the {@link TrustedPresentationCallback} for a specific {@link SurfaceControl}
         *
         * @param sc The SurfaceControl that the {@link TrustedPresentationCallback} should be
         *           cleared from
         * @return This transaction
         */
        @NonNull
        public Transaction clearTrustedPresentationCallback(@NonNull SurfaceControl sc) {
            checkPreconditions(sc);
            nativeClearTrustedPresentationCallback(mNativeObject, sc.mNativeObject);
            if (sc.mTrustedPresentationCallback != null) {
                sc.mTrustedPresentationCallback.mFreeNativeResources.run();
                sc.mTrustedPresentationCallback = null;
            }
            return this;
        }

        /**
         * Writes the transaction to parcel, clearing the transaction as if it had been applied so
         * it can be used to store future transactions. It's the responsibility of the parcel
+127 −0
Original line number Diff line number Diff line
@@ -246,6 +246,17 @@ static struct {
    jmethodID invokeReleaseCallback;
} gSurfaceControlClassInfo;

static struct {
    jclass clazz;
    jfieldID mMinAlpha;
    jfieldID mMinFractionRendered;
    jfieldID mStabilityRequirementMs;
} gTrustedPresentationThresholdsClassInfo;

static struct {
    jmethodID onTrustedPresentationChanged;
} gTrustedPresentationCallbackClassInfo;

constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
    switch (colorMode) {
        case ui::ColorMode::DISPLAY_P3:
@@ -328,6 +339,47 @@ private:
    }
};

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

    ~TrustedPresentationCallbackWrapper() {
        getenv()->DeleteGlobalRef(mTrustedPresentationCallback);
    }

    void onTrustedPresentationChanged(bool inTrustedPresentationState) {
        JNIEnv* env = getenv();
        env->CallVoidMethod(mTrustedPresentationCallback,
                            gTrustedPresentationCallbackClassInfo.onTrustedPresentationChanged,
                            inTrustedPresentationState);
    }

    void addCallbackRef(const sp<SurfaceComposerClient::PresentationCallbackRAII>& callbackRef) {
        mCallbackRef = callbackRef;
    }

    static void onTrustedPresentationChangedThunk(void* context, bool inTrustedPresentationState) {
        TrustedPresentationCallbackWrapper* listener =
                reinterpret_cast<TrustedPresentationCallbackWrapper*>(context);
        listener->onTrustedPresentationChanged(inTrustedPresentationState);
    }

private:
    jobject mTrustedPresentationCallback;
    JavaVM* mVm;
    sp<SurfaceComposerClient::PresentationCallbackRAII> mCallbackRef;

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

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

static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
@@ -1806,6 +1858,42 @@ static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlo
                                                 context);
}

static void nativeSetTrustedPresentationCallback(JNIEnv* env, jclass clazz, jlong transactionObj,
                                                 jlong nativeObject,
                                                 jlong trustedPresentationCallbackObject,
                                                 jobject trustedPresentationThresholds) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
    auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);

    TrustedPresentationThresholds thresholds;
    thresholds.minAlpha = env->GetFloatField(trustedPresentationThresholds,
                                             gTrustedPresentationThresholdsClassInfo.mMinAlpha);
    thresholds.minFractionRendered =
            env->GetFloatField(trustedPresentationThresholds,
                               gTrustedPresentationThresholdsClassInfo.mMinFractionRendered);
    thresholds.stabilityRequirementMs =
            env->GetIntField(trustedPresentationThresholds,
                             gTrustedPresentationThresholdsClassInfo.mStabilityRequirementMs);

    sp<SurfaceComposerClient::PresentationCallbackRAII> callbackRef;
    TrustedPresentationCallbackWrapper* wrapper =
            reinterpret_cast<TrustedPresentationCallbackWrapper*>(
                    trustedPresentationCallbackObject);
    transaction->setTrustedPresentationCallback(ctrl,
                                                TrustedPresentationCallbackWrapper::
                                                        onTrustedPresentationChangedThunk,
                                                thresholds, wrapper, callbackRef);
    wrapper->addCallbackRef(callbackRef);
}

static void nativeClearTrustedPresentationCallback(JNIEnv* env, jclass clazz, jlong transactionObj,
                                                   jlong nativeObject) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
    auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);

    transaction->clearTrustedPresentationCallback(ctrl);
}

class JankDataListenerWrapper : public JankDataListener {
public:
    JankDataListenerWrapper(JNIEnv* env, jobject onJankDataListenerObject) {
@@ -1919,6 +2007,21 @@ static jboolean nativeBootFinished(JNIEnv* env, jclass clazz) {
    return error == OK ? JNI_TRUE : JNI_FALSE;
}

jlong nativeCreateTpc(JNIEnv* env, jclass clazz, jobject trustedPresentationCallback) {
    return reinterpret_cast<jlong>(
            new TrustedPresentationCallbackWrapper(env, trustedPresentationCallback));
}

void destroyNativeTpc(void* ptr) {
    TrustedPresentationCallbackWrapper* callback =
            reinterpret_cast<TrustedPresentationCallbackWrapper*>(ptr);
    delete callback;
}

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

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

SurfaceControl* android_view_SurfaceControl_getNativeSurfaceControl(JNIEnv* env,
@@ -2145,6 +2248,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
             (void*)nativeSetDropInputMode },
    {"nativeAddTransactionCommittedListener", "(JLandroid/view/SurfaceControl$TransactionCommittedListener;)V",
            (void*) nativeAddTransactionCommittedListener },
    {"nativeSetTrustedPresentationCallback", "(JJJLandroid/view/SurfaceControl$TrustedPresentationThresholds;)V",
            (void*) nativeSetTrustedPresentationCallback },
    {"nativeClearTrustedPresentationCallback", "(JJ)V",
            (void*) nativeClearTrustedPresentationCallback },
    {"nativeSanitize", "(J)V",
            (void*) nativeSanitize },
    {"nativeSetDestinationFrame", "(JJIIII)V",
@@ -2155,6 +2262,9 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
                (void*)nativeGetDefaultApplyToken },
    {"nativeBootFinished", "()Z",
            (void*)nativeBootFinished },
    {"nativeCreateTpc", "(Landroid/view/SurfaceControl$TrustedPresentationCallback;)J",
            (void*)nativeCreateTpc},
    {"getNativeTrustedPresentationCallbackFinalizer", "()J", (void*)getNativeTrustedPresentationCallbackFinalizer },
        // clang-format on
};

@@ -2381,6 +2491,23 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    gTransactionClassInfo.mNativeObject =
            GetFieldIDOrDie(env, gTransactionClassInfo.clazz, "mNativeObject", "J");

    jclass trustedPresentationThresholdsClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$TrustedPresentationThresholds");
    gTrustedPresentationThresholdsClassInfo.clazz =
            MakeGlobalRefOrDie(env, trustedPresentationThresholdsClazz);
    gTrustedPresentationThresholdsClassInfo.mMinAlpha =
            GetFieldIDOrDie(env, trustedPresentationThresholdsClazz, "mMinAlpha", "F");
    gTrustedPresentationThresholdsClassInfo.mMinFractionRendered =
            GetFieldIDOrDie(env, trustedPresentationThresholdsClazz, "mMinFractionRendered", "F");
    gTrustedPresentationThresholdsClassInfo.mStabilityRequirementMs =
            GetFieldIDOrDie(env, trustedPresentationThresholdsClazz, "mStabilityRequirementMs",
                            "I");

    jclass trustedPresentationCallbackClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$TrustedPresentationCallback");
    gTrustedPresentationCallbackClassInfo.onTrustedPresentationChanged =
            GetMethodIDOrDie(env, trustedPresentationCallbackClazz, "onTrustedPresentationChanged",
                             "(Z)V");
    return err;
}