Loading packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +13 −25 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) } } } Loading Loading @@ -216,7 +209,7 @@ constructor( FrameLayoutTouchPassthrough( context, { notificationScrimClippingParams.isEnabled }, { notificationScrimClippingParams.top }, { notificationScrimClippingParams.params.top }, ) frame.addView( composeView, Loading @@ -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 Loading Loading @@ -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 { Loading packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt +44 −58 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, ) Loading
packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +13 −25 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) } } } Loading Loading @@ -216,7 +209,7 @@ constructor( FrameLayoutTouchPassthrough( context, { notificationScrimClippingParams.isEnabled }, { notificationScrimClippingParams.top }, { notificationScrimClippingParams.params.top }, ) frame.addView( composeView, Loading @@ -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 Loading Loading @@ -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 { Loading
packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/NotificationScrimClip.kt +44 −58 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, )