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

Commit ea5bd2a6 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Fix performance of clip" into main

parents db35019d d9055e5c
Loading
Loading
Loading
Loading
+13 −25
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ import com.android.systemui.plugins.qs.QSContainerController
import com.android.systemui.qs.composefragment.SceneKeys.QuickQuickSettings
import com.android.systemui.qs.composefragment.SceneKeys.QuickSettings
import com.android.systemui.qs.composefragment.SceneKeys.toIdleSceneKey
import com.android.systemui.qs.composefragment.ui.NotificationScrimClipParams
import com.android.systemui.qs.composefragment.ui.notificationScrimClip
import com.android.systemui.qs.composefragment.ui.quickQuickSettingsToQuickSettings
import com.android.systemui.qs.composefragment.viewmodel.QSFragmentComposeViewModel
@@ -149,20 +150,12 @@ constructor(
    private val notificationScrimClippingParams =
        object {
            var isEnabled by mutableStateOf(false)
            var leftInset by mutableStateOf(0)
            var rightInset by mutableStateOf(0)
            var top by mutableStateOf(0)
            var bottom by mutableStateOf(0)
            var radius by mutableStateOf(0)
            var params by mutableStateOf(NotificationScrimClipParams())

            fun dump(pw: IndentingPrintWriter) {
                pw.printSection("NotificationScrimClippingParams") {
                    pw.println("isEnabled", isEnabled)
                    pw.println("leftInset", "${leftInset}px")
                    pw.println("rightInset", "${rightInset}px")
                    pw.println("top", "${top}px")
                    pw.println("bottom", "${bottom}px")
                    pw.println("radius", "${radius}px")
                    pw.println("params", params)
                }
            }
        }
@@ -216,7 +209,7 @@ constructor(
            FrameLayoutTouchPassthrough(
                context,
                { notificationScrimClippingParams.isEnabled },
                { notificationScrimClippingParams.top },
                { notificationScrimClippingParams.params.top },
            )
        frame.addView(
            composeView,
@@ -237,13 +230,7 @@ constructor(
                    Modifier.windowInsetsPadding(WindowInsets.navigationBars).thenIf(
                        notificationScrimClippingParams.isEnabled
                    ) {
                        Modifier.notificationScrimClip(
                            notificationScrimClippingParams.leftInset,
                            notificationScrimClippingParams.top,
                            notificationScrimClippingParams.rightInset,
                            notificationScrimClippingParams.bottom,
                            notificationScrimClippingParams.radius,
                        )
                        Modifier.notificationScrimClip { notificationScrimClippingParams.params }
                    },
            ) {
                val isEditing by
@@ -445,13 +432,14 @@ constructor(
        fullWidth: Boolean,
    ) {
        notificationScrimClippingParams.isEnabled = visible
        notificationScrimClippingParams.top = top
        notificationScrimClippingParams.bottom = bottom
        // Full width means that QS will show in the entire width allocated to it (for example
        // phone) vs. showing in a narrower column (for example, tablet portrait).
        notificationScrimClippingParams.leftInset = if (fullWidth) 0 else leftInset
        notificationScrimClippingParams.rightInset = if (fullWidth) 0 else rightInset
        notificationScrimClippingParams.radius = cornerRadius
        notificationScrimClippingParams.params =
            NotificationScrimClipParams(
                top,
                bottom,
                if (fullWidth) 0 else leftInset,
                if (fullWidth) 0 else rightInset,
                cornerRadius,
            )
    }

    override fun isFullyCollapsed(): Boolean {
+44 −58
Original line number Diff line number Diff line
@@ -31,83 +31,59 @@ import androidx.compose.ui.platform.InspectorInfo
 * ([ClipOp.Difference]) a `RoundRect(-leftInset, top, width + rightInset, bottom, radius, radius)`
 * from the QS container.
 */
fun Modifier.notificationScrimClip(
    leftInset: Int,
    top: Int,
    rightInset: Int,
    bottom: Int,
    radius: Int
): Modifier {
    return this then NotificationScrimClipElement(leftInset, top, rightInset, bottom, radius)
fun Modifier.notificationScrimClip(clipParams: () -> NotificationScrimClipParams): Modifier {
    return this then NotificationScrimClipElement(clipParams)
}

private class NotificationScrimClipNode(
    var leftInset: Float,
    var top: Float,
    var rightInset: Float,
    var bottom: Float,
    var radius: Float,
) : DrawModifierNode, Modifier.Node() {
private class NotificationScrimClipNode(var clipParams: () -> NotificationScrimClipParams) :
    DrawModifierNode, Modifier.Node() {
    private val path = Path()

    var invalidated = true
    private var lastClipParams = NotificationScrimClipParams()

    override fun ContentDrawScope.draw() {
        if (invalidated) {
        val newClipParams = clipParams()
        if (newClipParams != lastClipParams) {
            lastClipParams = newClipParams
            applyClipParams(path, lastClipParams)
        }
        clipPath(path, ClipOp.Difference) { this@draw.drawContent() }
    }

    private fun ContentDrawScope.applyClipParams(
        path: Path,
        clipParams: NotificationScrimClipParams,
    ) {
        with(clipParams) {
            path.rewind()
            path
                .asAndroidPath()
                .addRoundRect(
                    -leftInset,
                    top,
                    -leftInset.toFloat(),
                    top.toFloat(),
                    size.width + rightInset,
                    bottom,
                    radius,
                    radius,
                    android.graphics.Path.Direction.CW
                    bottom.toFloat(),
                    radius.toFloat(),
                    radius.toFloat(),
                    android.graphics.Path.Direction.CW,
                )
            invalidated = false
        }
        clipPath(path, ClipOp.Difference) { this@draw.drawContent() }
    }
}

private data class NotificationScrimClipElement(
    val leftInset: Int,
    val top: Int,
    val rightInset: Int,
    val bottom: Int,
    val radius: Int,
) : ModifierNodeElement<NotificationScrimClipNode>() {
private data class NotificationScrimClipElement(val clipParams: () -> NotificationScrimClipParams) :
    ModifierNodeElement<NotificationScrimClipNode>() {
    override fun create(): NotificationScrimClipNode {
        return NotificationScrimClipNode(
            leftInset.toFloat(),
            top.toFloat(),
            rightInset.toFloat(),
            bottom.toFloat(),
            radius.toFloat(),
        )
        return NotificationScrimClipNode(clipParams)
    }

    override fun update(node: NotificationScrimClipNode) {
        val changed =
            node.leftInset != leftInset.toFloat() ||
                node.top != top.toFloat() ||
                node.rightInset != rightInset.toFloat() ||
                node.bottom != bottom.toFloat() ||
                node.radius != radius.toFloat()
        if (changed) {
            node.leftInset = leftInset.toFloat()
            node.top = top.toFloat()
            node.rightInset = rightInset.toFloat()
            node.bottom = bottom.toFloat()
            node.radius = radius.toFloat()
            node.invalidated = true
        }
        node.clipParams = clipParams
    }

    override fun InspectorInfo.inspectableProperties() {
        name = "notificationScrimClip"
        with(clipParams()) {
            properties["leftInset"] = leftInset
            properties["top"] = top
            properties["rightInset"] = rightInset
@@ -115,3 +91,13 @@ private data class NotificationScrimClipElement(
            properties["radius"] = radius
        }
    }
}

/** Params for [notificationScrimClip]. */
data class NotificationScrimClipParams(
    val top: Int = 0,
    val bottom: Int = 0,
    val leftInset: Int = 0,
    val rightInset: Int = 0,
    val radius: Int = 0,
)