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

Commit cddc3b71 authored by Surbhi Kadam's avatar Surbhi Kadam Committed by Vinit Nayak
Browse files

Adds corner rounding capability in ViewRootImpl

This registers a callback with SurfaceFlinger to receive
the computed corner radii for the view. Also, adds ability
to ThreadedRenderer for clipping the corners

Bug: 372620947
Flag:com.android.graphics.surfaceflinger.flags.set_client_drawn_corner_radii
Test: presubmit; manual

Change-Id: I451e113c54d1b925d91430cd55326b770982d825
parent 57f25dbf
Loading
Loading
Loading
Loading
+23 −48
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.gui.BorderSettings;
import android.gui.BoxShadowSettings;
@@ -171,11 +172,11 @@ public final class SurfaceControl implements Parcelable {
    private static native void nativeSetCornerRadius(
            long transactionObj, long nativeObject, float topLeft, float topRight,
                                float bottomLeft, float bottomRight);
    private static native void nativeSetClientDrawnCornerRadius(long transactionObj,
            long nativeObject, float clientDrawnCornerRadius);
    private static native void nativeSetClientDrawnCornerRadius(
            long transactionObj, long nativeObject, float topLeft, float topRight,
                                                float bottomLeft, float bottomRight);
                                                float bottomLeft, float bottomRight,
                                                float cropTop, float cropLeft,
                                                float cropBottom, float cropRight);
    private static native void nativeSetBackgroundBlurRadius(long transactionObj, long nativeObject,
            int blurRadius);
    private static native void nativeSetBackgroundBlurScale(long transactionObj, long nativeObject,
@@ -3589,18 +3590,6 @@ public final class SurfaceControl implements Parcelable {
            return this;
        }

        /**
         * Adds a callback that is called after WindowInfosListeners from the systems server are
         * complete. This is primarily used to ensure that InputDispatcher::setInputWindowsLocked
         * has been called before running the added callback.
         *
         * @hide
         */
        public Transaction addWindowInfosReportedListener(@NonNull Runnable listener) {
            nativeAddWindowInfosReportedListener(mNativeObject, listener);
            return this;
        }

        /**
         * Adds a transaction barrier.
         *
@@ -3617,6 +3606,19 @@ public final class SurfaceControl implements Parcelable {
            return this;
        }


        /**
         * Adds a callback that is called after WindowInfosListeners from the systems server are
         * complete. This is primarily used to ensure that InputDispatcher::setInputWindowsLocked
         * has been called before running the added callback.
         *
         * @hide
         */
        public Transaction addWindowInfosReportedListener(@NonNull Runnable listener) {
            nativeAddWindowInfosReportedListener(mNativeObject, listener);
            return this;
        }

        /**
         * Specify how the buffer associated with this Surface is mapped in to the
         * parent coordinate space. The source frame will be scaled to fit the destination
@@ -3869,39 +3871,10 @@ public final class SurfaceControl implements Parcelable {
            return this;
        }

        /**
         * Disables corner radius of a {@link SurfaceControl}. When the radius set by
         * {@link Transaction#setCornerRadius(SurfaceControl, float)} is equal to
         * clientDrawnCornerRadius the corner radius drawn by SurfaceFlinger is disabled.
         *
         * @param sc SurfaceControl
         * @param clientDrawnCornerRadius Corner radius drawn by the client
         * @return Itself.
         * @hide
         */
        @NonNull
        public Transaction setClientDrawnCornerRadius(@NonNull SurfaceControl sc,
                                                            float clientDrawnCornerRadius) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                        "setClientDrawnCornerRadius", this, sc, "clientDrawnCornerRadius="
                        + clientDrawnCornerRadius);
            }
            if (Flags.ignoreCornerRadiusAndShadows()) {
                nativeSetClientDrawnCornerRadius(mNativeObject, sc.mNativeObject,
                                                                clientDrawnCornerRadius);
            } else {
                Log.w(TAG, "setClientDrawnCornerRadius was called but"
                            + "ignore_corner_radius_and_shadows flag is disabled");
            }

            return this;
        }

        /**
         * Disables corner radius of a {@link SurfaceControl}. When the radius set by {@link
         * Transaction#setCornerRadius(SurfaceControl, float)} is equal to clientDrawnCornerRadius
         * and the crop set by the client matches the bounds in SurfaceFlinger,
         * the corner radius drawn by SurfaceFlinger is disabled.
         *
         * @hide
@@ -3909,7 +3882,7 @@ public final class SurfaceControl implements Parcelable {
        @NonNull
        public Transaction setClientDrawnCornerRadius(
                @NonNull SurfaceControl sc, float topLeft, float topRight,
                    float bottomLeft, float bottomRight) {
                    float bottomLeft, float bottomRight, RectF crop) {
            checkPreconditions(sc);
            if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
                SurfaceControlRegistry.getProcessInstance()
@@ -3920,7 +3893,8 @@ public final class SurfaceControl implements Parcelable {
                                "topLeft=" + topLeft
                                + " , topRight=" + topRight
                                + ", bottomLeft=" + bottomLeft
                                + " , bottomRight=" + bottomRight);
                                + " , bottomRight=" + bottomRight
                                + ", crop=" + crop);
            }
            if (!com.android.graphics.surfaceflinger.flags.Flags.setClientDrawnCornerRadii()) {
                Log.w(TAG, "setClientDrawnCornerRadius was called but"
@@ -3929,7 +3903,8 @@ public final class SurfaceControl implements Parcelable {
            }

            nativeSetClientDrawnCornerRadius(mNativeObject, sc.mNativeObject,
                                            topLeft, topRight, bottomLeft, bottomRight);
                                            topLeft, topRight, bottomLeft, bottomRight,
                                            crop.left, crop.top, crop.right, crop.bottom);

            return this;
        }
+33 −0
Original line number Diff line number Diff line
@@ -24,15 +24,19 @@ import android.content.res.TypedArray;
import android.graphics.BLASTBufferQueue;
import android.graphics.FrameInfo;
import android.graphics.HardwareRenderer;
import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.RenderNode;
import android.os.Trace;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
import android.view.ViewRootImpl.CornerRadii;
import android.view.animation.AnimationUtils;

import com.android.internal.R;
@@ -257,6 +261,9 @@ public final class ThreadedRenderer extends HardwareRenderer {
    private boolean mEnabled;
    private boolean mRequested = true;

    private CornerRadii mCornerRadii;
    private Outline mOutline;

    /**
     * This child class exists to break ownership cycles. ViewRootImpl owns a ThreadedRenderer
     * which owns a WebViewOverlayProvider. WebViewOverlayProvider will in turn be set as
@@ -534,9 +541,35 @@ public final class ThreadedRenderer extends HardwareRenderer {

        mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);

        setCornerRadius(mCornerRadii);
        setLightCenter(attachInfo);
    }

    RectF getRoundedClipBounds() {
        return new RectF(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
    }

    void setCornerRadius(CornerRadii radii) {
        if (radii == null || radii.isEmpty()) {
            mRootNode.setClipToOutline(false);
            return;
        }
        mCornerRadii = radii;
        if (mOutline == null) {
            mOutline = new Outline();
        }
        Path path = new Path();
        RectF rect = new RectF(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
        float[] cwRadii = {mCornerRadii.topLeft, mCornerRadii.topLeft,
                mCornerRadii.topRight, mCornerRadii.topRight,
                mCornerRadii.bottomRight, mCornerRadii.bottomRight,
                mCornerRadii.bottomLeft, mCornerRadii.bottomLeft};
        path.addRoundRect(rect, cwRadii, Path.Direction.CW);
        mOutline.setPath(path);
        mRootNode.setOutline(mOutline);
        mRootNode.setClipToOutline(true);
    }

    /**
     * Whether or not the renderer owns the SurfaceControl's opacity. If true, use
     * {@link #setSurfaceControlOpaque(boolean)} to update the opacity
+67 −1
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ import static android.internal.perfetto.protos.Inputmethodeditor.InputMethodClie
import static android.internal.perfetto.protos.Inputmethodeditor.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION;
import static com.android.graphics.surfaceflinger.flags.Flags.setClientDrawnCornerRadii;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.alwaysSeqIdLayout;
@@ -1159,6 +1160,8 @@ public final class ViewRootImpl implements ViewParent,
    private int mFrameRateCategoryNormalCount = 0;
    private int mFrameRateCategoryLowCount = 0;
    private CornerRadii mCornerRadii = new CornerRadii();
    /*
     * the variables below are used to determine whther a dVRR feature should be enabled
     */
@@ -1208,6 +1211,28 @@ public final class ViewRootImpl implements ViewParent,
                }
            }
        };
    private BLASTBufferQueue.CornerRadiiCallback mCornerRadiiCallback =
            new BLASTBufferQueue.CornerRadiiCallback() {
                @Override
                public void onCornerRadiiChanged(float[] cornerRadii) {
                    if (cornerRadii != null && cornerRadii.length == 4) {
                        CornerRadii newCornerRadii = new CornerRadii();
                        newCornerRadii.topLeft = cornerRadii[0];
                        newCornerRadii.topRight = cornerRadii[1];
                        newCornerRadii.bottomLeft = cornerRadii[2];
                        newCornerRadii.bottomRight = cornerRadii[3];
                        if (!mCornerRadii.equals(newCornerRadii)) {
                            mCornerRadii = newCornerRadii;
                            invalidate();
                        }
                    } else {
                        Log.wtf(TAG, "Corner radii received is null or invalid"
                                + (cornerRadii == null ? "null" : "length " + cornerRadii.length));
                    }
                }
            };
    private final Rect mChildBoundingInsets = new Rect();
    private boolean mChildBoundingInsetsChanged = false;
@@ -2826,6 +2851,7 @@ public final class ViewRootImpl implements ViewParent,
                mWindowAttributes.format);
        mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
        mBlastBufferQueue.setWaitForBufferReleaseCallback(mChoreographer::onWaitForBufferRelease);
        mBlastBufferQueue.setCornerRadiiCallback(mCornerRadiiCallback);
        Surface blastSurface;
        if (addSchandleToVriSurface()) {
            blastSurface = mBlastBufferQueue.createSurfaceWithHandle();
@@ -4143,6 +4169,16 @@ public final class ViewRootImpl implements ViewParent,
                            mWindowAttributes.surfaceInsets);
                    mNeedsRendererSetup = false;
                }
                if (setClientDrawnCornerRadii() && !mCornerRadii.isEmpty()
                                            && mSurfaceControl.isValid()) {
                    applyTransactionOnDraw(mTransaction
                            .setClientDrawnCornerRadius(mSurfaceControl, mCornerRadii.topLeft,
                            mCornerRadii.topRight, mCornerRadii.bottomLeft,
                            mCornerRadii.bottomRight,
                            threadedRenderer.getRoundedClipBounds()));
                    threadedRenderer.setCornerRadius(mCornerRadii);
                }
            }
            // TODO: In the CL "ViewRootImpl: Fix issue with early draw report in
@@ -9757,7 +9793,8 @@ public final class ViewRootImpl implements ViewParent,
                && params.surfaceInsets.bottom == 0
                // Don't make surface opaque when resizing to reduce the amount of
                // artifacts shown in areas the app isn't drawing content to.
                && !dragResizing) {
                && !dragResizing
                && mCornerRadii.isEmpty()) {
            opaque = true;
        }
@@ -10151,6 +10188,35 @@ public final class ViewRootImpl implements ViewParent,
        }
    }
    static final class CornerRadii {
        public float topLeft;
        public float topRight;
        public float bottomRight;
        public float bottomLeft;
        boolean isEmpty() {
            return topLeft == 0 && topRight == 0
                    && bottomRight == 0 && bottomLeft == 0;
        }
        @Override
        public boolean equals(Object o) {
            if (!(o instanceof CornerRadii)) {
                return false;
            }
            CornerRadii cr = (CornerRadii) o;
            return topLeft == cr.topLeft &&
                   topRight == cr.topRight &&
                   bottomRight == cr.bottomRight &&
                   bottomLeft == cr.bottomLeft;
        }
        @Override
        public int hashCode() {
            return Objects.hash(topLeft, topRight, bottomRight, bottomLeft);
        }
    }
    GfxInfo getGfxInfo() {
        GfxInfo info = new GfxInfo();
        if (mView != null) {
+67 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <android_runtime/android_view_Surface.h>
#include <android_util_Binder.h>
#include <gui/BLASTBufferQueue.h>
#include <gui/CornerRadii.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <nativehelper/JNIHelp.h>
@@ -121,6 +122,52 @@ private:
    jobject mWaitForBufferReleaseObject;
};

struct {
    jmethodID onCornerRadiiChanged;
} gCornerRadiiCallback;

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

    ~CornerRadiiCallbackWrapper() {
        if (mCornerRadiiCallbackObject != nullptr) {
            getenv(mVm)->DeleteGlobalRef(mCornerRadiiCallbackObject);
            mCornerRadiiCallbackObject = nullptr;
        }
    }

    void onCornerRadiiChanged(const gui::CornerRadii cornerRadii) {
        JNIEnv* env = getenv(mVm);
        ScopedLocalRef<jfloatArray> javaCornerRadiiArray(env, env->NewFloatArray(4));
        if (javaCornerRadiiArray == nullptr) {
            ALOGE("Failed to create new Java float array for cornerRadii");
            return;
        }

        jfloat tempCornerRadii[4];
        tempCornerRadii[0] = cornerRadii.topLeft.x;
        tempCornerRadii[1] = cornerRadii.topRight.x;
        tempCornerRadii[2] = cornerRadii.bottomLeft.x;
        tempCornerRadii[3] = cornerRadii.bottomRight.x;

        env->SetFloatArrayRegion(javaCornerRadiiArray.get(), 0, 4, tempCornerRadii);
        getenv(mVm)->CallVoidMethod(mCornerRadiiCallbackObject,
                                    gCornerRadiiCallback.onCornerRadiiChanged,
                                    javaCornerRadiiArray.get());

        DieIfException(env, "Uncaught exception in CornerRadiiCallback.");
    }

private:
    JavaVM* mVm;
    jobject mCornerRadiiCallbackObject;
};

static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
                          jboolean updateDestinationFrame) {
    ScopedUtfChars name(env, jName);
@@ -251,6 +298,19 @@ static void nativeSetApplyToken(JNIEnv* env, jclass clazz, jlong ptr, jobject ap
    return queue->setApplyToken(std::move(token));
}

static void nativeSetCornerRadiiCallback(JNIEnv* env, jclass clazz, jlong ptr,
                                         jobject cornerRadiiCallback) {
    auto queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
    if (cornerRadiiCallback == nullptr) {
        queue->setCornerRadiiCallback(nullptr);
    } else {
        auto wrapper = sp<CornerRadiiCallbackWrapper>::make(env, cornerRadiiCallback);
        queue->setCornerRadiiCallback([wrapper](const gui::CornerRadii cornerRadii) {
            wrapper->onCornerRadiiChanged(cornerRadii);
        });
    }
}

static void nativeSetWaitForBufferReleaseCallback(JNIEnv* env, jclass clazz, jlong ptr,
                                                  jobject waitForBufferReleaseCallback) {
    auto queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
@@ -287,6 +347,9 @@ static const JNINativeMethod gMethods[] = {
        {"nativeSetWaitForBufferReleaseCallback",
         "(JLandroid/graphics/BLASTBufferQueue$WaitForBufferReleaseCallback;)V",
         (void*)nativeSetWaitForBufferReleaseCallback},
        {"nativeSetCornerRadiiCallback",
         "(JLandroid/graphics/BLASTBufferQueue$CornerRadiiCallback;)V",
         (void*)nativeSetCornerRadiiCallback},
        // clang-format on
};

@@ -312,6 +375,10 @@ int register_android_graphics_BLASTBufferQueue(JNIEnv* env) {
            FindClassOrDie(env, "android/graphics/BLASTBufferQueue$WaitForBufferReleaseCallback");
    gWaitForBufferReleaseCallback.onWaitForBufferRelease =
            GetMethodIDOrDie(env, waitForBufferReleaseClass, "onWaitForBufferRelease", "(J)V");
    jclass cornerRadiiCallbackClass =
            FindClassOrDie(env, "android/graphics/BLASTBufferQueue$CornerRadiiCallback");
    gCornerRadiiCallback.onCornerRadiiChanged =
            GetMethodIDOrDie(env, cornerRadiiCallbackClass, "onCornerRadiiChanged", "([F)V");

    return 0;
}
+7 −15
Original line number Diff line number Diff line
@@ -1178,21 +1178,15 @@ static void nativeSetCornerRadius(JNIEnv* env, jclass clazz, jlong transactionOb
    transaction->setCornerRadius(ctrl, gui::CornerRadii(tl, tr, bl, br));
}

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

    auto ctrl = SpFromRawPtr<SurfaceControl>(nativeObject);
    transaction->setClientDrawnCornerRadius(ctrl, clientDrawnCornerRadius);
}

static void nativeSetClientDrawnCornerRadius(JNIEnv* env, jclass clazz, jlong transactionObj,
                                             jlong nativeObject, jfloat tl, jfloat tr, jfloat bl,
                                             jfloat br) {
                                             jfloat br, jfloat cropTop, jfloat cropLeft,
                                             jfloat cropRight, jfloat cropBottom) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);

    auto ctrl = SpFromRawPtr<SurfaceControl>(nativeObject);
    transaction->setClientDrawnCornerRadius(ctrl, gui::CornerRadii(tl, tr, bl, br));
    FloatRect crop(cropLeft, cropTop, cropRight, cropBottom);
    transaction->setClientDrawnCornerRadius(ctrl, gui::CornerRadii(tl, tr, bl, br), crop);
}

static void nativeSetBackgroundBlurRadius(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -2693,11 +2687,9 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
    {"nativeSetCornerRadius", "(JJFFFF)V",
            (void*)(void (*)(JNIEnv*, jclass, jlong, jlong, jfloat, jfloat,
                                        jfloat, jfloat))nativeSetCornerRadius },
    {"nativeSetClientDrawnCornerRadius", "(JJF)V",
            (void*)(void (*)(JNIEnv*, jclass, jlong, jlong, jfloat))
                                        nativeSetClientDrawnCornerRadius },
    {"nativeSetClientDrawnCornerRadius", "(JJFFFF)V",
            (void*)(void (*)(JNIEnv*, jclass, jlong, jlong, jfloat, jfloat, jfloat, jfloat))
    {"nativeSetClientDrawnCornerRadius", "(JJFFFFFFFF)V",
            (void*)(void (*)(JNIEnv*, jclass, jlong, jlong, jfloat, jfloat, jfloat, jfloat,
                                        jfloat, jfloat, jfloat, jfloat))
                                        nativeSetClientDrawnCornerRadius },
    {"nativeSetBackgroundBlurRadius", "(JJI)V",
            (void*)nativeSetBackgroundBlurRadius },
Loading