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

Commit 80aa374d authored by Fabián Kozynski's avatar Fabián Kozynski
Browse files

Fix scrim clipping

It was not reacting properly to changes in enabled

Also, add a table log for future debug

Test: manual
Test: logs
Fixes: 406248870
Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Change-Id: Ie418082d0097e7e13bf368c208fdccad721ec6d0
parent f592160b
Loading
Loading
Loading
Loading
+64 −27
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ import com.android.systemui.keyboard.shortcut.ui.composable.InteractionsConfig
import com.android.systemui.keyboard.shortcut.ui.composable.ProvideShortcutHelperIndication
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.setSnapshotBinding
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.plugins.qs.QS
import com.android.systemui.plugins.qs.QSContainerController
@@ -132,6 +133,7 @@ import com.android.systemui.qs.composefragment.ui.toEditMode
import com.android.systemui.qs.composefragment.viewmodel.QSFragmentComposeViewModel
import com.android.systemui.qs.flags.QSComposeFragment
import com.android.systemui.qs.footer.ui.compose.FooterActions
import com.android.systemui.qs.panels.shared.model.QSFragmentComposeClippingTableLog
import com.android.systemui.qs.panels.ui.compose.EditMode
import com.android.systemui.qs.panels.ui.compose.QuickQuickSettings
import com.android.systemui.qs.panels.ui.compose.TileGrid
@@ -163,6 +165,7 @@ class QSFragmentCompose
@Inject
constructor(
    private val qsFragmentComposeViewModelFactory: QSFragmentComposeViewModel.Factory,
    @QSFragmentComposeClippingTableLog private val qsClippingTableLogBuffer: TableLogBuffer,
    private val dumpManager: DumpManager,
) : LifecycleFragment(), QS, Dumpable {

@@ -183,8 +186,12 @@ constructor(
    // Inside object for namespacing
    private val notificationScrimClippingParams =
        object {
            var isEnabled by mutableStateOf(false)
            var params by mutableStateOf(NotificationScrimClipParams())
            var clipData by mutableStateOf(false to NotificationScrimClipParams())
            private val isEnabled
                get() = clipData.first

            private val params
                get() = clipData.second

            fun dump(pw: IndentingPrintWriter) {
                pw.printSection("NotificationScrimClippingParams") {
@@ -241,12 +248,12 @@ constructor(
        val frame =
            FrameLayoutTouchPassthrough(
                context,
                { notificationScrimClippingParams.isEnabled },
                snapshotFlow { notificationScrimClippingParams.params },
                snapshotFlow { notificationScrimClippingParams.clipData },
                // Only allow scrolling when we are fully expanded. That way, we don't intercept
                // swipes in lockscreen (when somehow QS is receiving touches).
                { (scrollState.canScrollForward && viewModel.isQsFullyExpanded) || isCustomizing },
                viewModel::emitMotionEventForFalsingSwipeNested,
                qsClippingTableLogBuffer,
            )
        frame.addView(
            composeView,
@@ -520,8 +527,8 @@ constructor(
        visible: Boolean,
        fullWidth: Boolean,
    ) {
        notificationScrimClippingParams.isEnabled = visible
        notificationScrimClippingParams.params =
        notificationScrimClippingParams.clipData =
            visible to
                NotificationScrimClipParams(
                    top,
                    bottom,
@@ -1056,17 +1063,15 @@ private const val EDIT_MODE_TIME_MILLIS = 500
 */
private class FrameLayoutTouchPassthrough(
    context: Context,
    private val clippingEnabledProvider: () -> Boolean,
    private val clippingParams: Flow<NotificationScrimClipParams>,
    private val clippingData: Flow<Pair<Boolean, NotificationScrimClipParams>>,
    private val canScrollForwardQs: () -> Boolean,
    private val emitMotionEventForFalsing: () -> Unit,
    private val logBuffer: TableLogBuffer,
) : FrameLayout(context) {

    init {
        repeatWhenAttached {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                clippingParams.collect { currentClipParams = it }
            }
            repeatOnLifecycle(Lifecycle.State.STARTED) { clippingData.collect { clipData = it } }
        }
    }

@@ -1074,33 +1079,53 @@ private class FrameLayoutTouchPassthrough(
    private var lastWidth = -1
        set(value) {
            if (field != value) {
                logBuffer.logChange(columnName = COL_WIDTH, value = value, isInitial = false)
                field = value
                updateClippingPath()
            }
        }

    private var currentClipParams = NotificationScrimClipParams()
    // [first] is enabled and [second] is the clipping params
    private var clipData = false to NotificationScrimClipParams()
        set(value) {
            if (field != value) {
                logBuffer.logDiffs(
                    columnPrefix = PREFIX_PARAMS,
                    prevVal = field.second,
                    newVal = value.second,
                )
                if (field.first != value.first) {
                    logBuffer.logChange(
                        columnName = COL_CLIP_ENABLED,
                        value = value.first,
                        isInitial = false,
                    )
                }
                field = value
                updateClippingPath()
            }
        }

    private val clipEnabled
        get() = clipData.first

    private val clipParams
        get() = clipData.second

    private fun updateClippingPath() {
        currentClippingPath.rewind()
        if (clippingEnabledProvider()) {
            val right = width + currentClipParams.rightInset
            val left = -currentClipParams.leftInset
            val top = currentClipParams.top
            val bottom = currentClipParams.bottom
        if (clipEnabled) {
            val right = width + clipParams.rightInset
            val left = -clipParams.leftInset
            val top = clipParams.top
            val bottom = clipParams.bottom
            currentClippingPath.addRoundRect(
                left.toFloat(),
                top.toFloat(),
                right.toFloat(),
                bottom.toFloat(),
                currentClipParams.radius.toFloat(),
                currentClipParams.radius.toFloat(),
                clipParams.radius.toFloat(),
                clipParams.radius.toFloat(),
                Path.Direction.CW,
            )
        }
@@ -1114,7 +1139,12 @@ private class FrameLayoutTouchPassthrough(

    override fun dispatchDraw(canvas: Canvas) {
        if (!currentClippingPath.isEmpty) {
            logBuffer.logChange(columnName = COL_CLIP_APPLIED, value = true, isInitial = false)
            canvas.translate(0f, -translationY)
            canvas.clipOutPath(currentClippingPath)
            canvas.translate(0f, translationY)
        } else {
            logBuffer.logChange(columnName = COL_CLIP_APPLIED, value = false, isInitial = false)
        }
        super.dispatchDraw(canvas)
    }
@@ -1125,7 +1155,7 @@ private class FrameLayoutTouchPassthrough(
        child: View?,
        outLocalPoint: PointF?,
    ): Boolean {
        return if (clippingEnabledProvider() && y + translationY > currentClipParams.top) {
        return if (clipEnabled && y + translationY > clipParams.top) {
            false
        } else {
            super.isTransformedTouchPointInView(x, y, child, outLocalPoint)
@@ -1187,6 +1217,13 @@ private class FrameLayoutTouchPassthrough(
        }
        return super.onInterceptTouchEvent(ev)
    }

    private companion object {
        const val COL_CLIP_ENABLED = "enabled"
        const val COL_CLIP_APPLIED = "applied"
        const val COL_WIDTH = "width"
        const val PREFIX_PARAMS = "params"
    }
}

private fun Modifier.gesturesDisabled(disabled: Boolean) =
+38 −1
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.systemui.qs.composefragment.ui

import com.android.systemui.log.table.Diffable
import com.android.systemui.log.table.TableRowLogger

/** Params for [notificationScrimClip]. */
data class NotificationScrimClipParams(
    val top: Int = 0,
@@ -23,4 +26,38 @@ data class NotificationScrimClipParams(
    val leftInset: Int = 0,
    val rightInset: Int = 0,
    val radius: Int = 0,
)
) : Diffable<NotificationScrimClipParams> {
    override fun logDiffs(prevVal: NotificationScrimClipParams, row: TableRowLogger) {
        if (top != prevVal.top) {
            row.logChange(Columns.COL_TOP, top)
        }
        if (bottom != prevVal.bottom) {
            row.logChange(Columns.COL_BOTTOM, bottom)
        }
        if (leftInset != prevVal.leftInset) {
            row.logChange(Columns.COL_LEFT_INSET, leftInset)
        }
        if (rightInset != prevVal.rightInset) {
            row.logChange(Columns.COL_RIGHT_INSET, rightInset)
        }
        if (radius != prevVal.radius) {
            row.logChange(Columns.COL_RADIUS, radius)
        }
    }

    override fun logFull(row: TableRowLogger) {
        row.logChange(Columns.COL_TOP, top)
        row.logChange(Columns.COL_BOTTOM, bottom)
        row.logChange(Columns.COL_LEFT_INSET, leftInset)
        row.logChange(Columns.COL_RIGHT_INSET, rightInset)
        row.logChange(Columns.COL_RADIUS, radius)
    }
}

private object Columns {
    const val COL_TOP = "top"
    const val COL_BOTTOM = "bottom"
    const val COL_LEFT_INSET = "left_inset"
    const val COL_RIGHT_INSET = "right_inset"
    const val COL_RADIUS = "radius"
}
+10 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepositoryImpl
import com.android.systemui.qs.panels.domain.interactor.EditTilesResetInteractor
@@ -29,6 +31,7 @@ import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType
import com.android.systemui.qs.panels.shared.model.PanelsLog
import com.android.systemui.qs.panels.shared.model.QSFragmentComposeClippingTableLog
import com.android.systemui.qs.panels.ui.compose.GridLayout
import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
import com.android.systemui.qs.panels.ui.compose.PaginatedGridLayout
@@ -74,6 +77,13 @@ interface PanelsModule {
            return factory.create("PanelsLog", 50)
        }

        @Provides
        @SysUISingleton
        @QSFragmentComposeClippingTableLog
        fun providesQSFragmentComposeClippingLog(factory: TableLogBufferFactory): TableLogBuffer {
            return factory.create("QSFragmentComposeClippingTableLog", 100)
        }

        @Provides
        @IntoSet
        fun provideGridLayout(gridLayout: InfiniteGridLayout): Pair<GridLayoutType, GridLayout> {
+24 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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 com.android.systemui.qs.panels.shared.model

import javax.inject.Qualifier

@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class QSFragmentComposeClippingTableLog