summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt47
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt15
7 files changed, 129 insertions, 29 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 5e7e0c97a147..9aedf0d1ee31 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -63,6 +63,7 @@ import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.approachLayout
+import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.layout.positionInRoot
@@ -250,10 +251,23 @@ constructor(
private fun Content() {
PlatformTheme(isDarkTheme = true) {
ProvideShortcutHelperIndication(interactionsConfig = interactionsConfig()) {
- if (viewModel.isQsVisibleAndAnyShadeExpanded) {
+ // TODO(b/389985793): Make sure that there is no coroutine work or recompositions
+ // happening when alwaysCompose is true but isQsVisibleAndAnyShadeExpanded is false.
+ if (alwaysCompose || viewModel.isQsVisibleAndAnyShadeExpanded) {
Box(
modifier =
- Modifier.graphicsLayer { alpha = viewModel.viewAlpha }
+ Modifier.thenIf(alwaysCompose) {
+ Modifier.layout { measurable, constraints ->
+ measurable.measure(constraints).run {
+ layout(width, height) {
+ if (viewModel.isQsVisibleAndAnyShadeExpanded) {
+ place(0, 0)
+ }
+ }
+ }
+ }
+ }
+ .graphicsLayer { alpha = viewModel.viewAlpha }
.thenIf(notificationScrimClippingParams.isEnabled) {
Modifier.notificationScrimClip {
notificationScrimClippingParams.params
@@ -331,12 +345,12 @@ constructor(
}
SceneTransitionLayout(state = sceneState, modifier = Modifier.fillMaxSize()) {
- scene(QuickSettings) {
+ scene(QuickSettings, alwaysCompose = alwaysCompose) {
LaunchedEffect(Unit) { viewModel.onQSOpen() }
Element(QuickSettings.rootElementKey, Modifier) { QuickSettingsElement() }
}
- scene(QuickQuickSettings) {
+ scene(QuickQuickSettings, alwaysCompose = alwaysCompose) {
LaunchedEffect(Unit) { viewModel.onQQSOpen() }
// Cannot pass the element modifier in because the top element has a `testTag`
// and this would overwrite it.
@@ -626,7 +640,20 @@ constructor(
) {
val Tiles =
@Composable {
- QuickQuickSettings(viewModel = viewModel.quickQuickSettingsViewModel)
+ QuickQuickSettings(
+ viewModel = viewModel.quickQuickSettingsViewModel,
+ listening = {
+ /*
+ * When always compose is false, this will always be true, and we'll be
+ * listening whenever this is composed.
+ * When always compose is true, we listen if we are visible and not
+ * fully expanded
+ */
+ !alwaysCompose ||
+ (viewModel.isQsVisibleAndAnyShadeExpanded &&
+ viewModel.expansionState.progress < 1f)
+ },
+ )
}
val Media =
@Composable {
@@ -726,6 +753,18 @@ constructor(
TileGrid(
viewModel = containerViewModel.tileGridViewModel,
modifier = Modifier.fillMaxWidth(),
+ listening = {
+ /*
+ * When always compose is false, this will always be true,
+ * and we'll be listening whenever this is composed.
+ * When always compose is true, we look a the second
+ * condition and we'll listen if QS is visible AND we are
+ * not fully collapsed.
+ */
+ !alwaysCompose ||
+ (viewModel.isQsVisibleAndAnyShadeExpanded &&
+ viewModel.expansionState.progress > 0f)
+ },
)
}
}
@@ -830,6 +869,7 @@ constructor(
println("qqsPositionOnScreen", rect)
}
println("QQS visible", qqsVisible.value)
+ println("Always composed", alwaysCompose)
if (::viewModel.isInitialized) {
printSection("View Model") { viewModel.dump(this@run, args) }
}
@@ -1177,3 +1217,6 @@ private fun interactionsConfig() =
// we are OK using this as our content is clipped and all corner radius are larger than this
surfaceCornerRadius = 28.dp,
)
+
+private inline val alwaysCompose
+ get() = Flags.alwaysComposeQsUiFragment()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
index 185ea93387a3..1fb884de620f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
@@ -27,7 +27,17 @@ import com.android.systemui.qs.pipeline.shared.TileSpec
/** A layout of tiles, indicating how they should be composed when showing in QS or in edit mode. */
interface GridLayout {
- @Composable fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier)
+
+ /**
+ * [listening] can be used to compose the grid but limit when tiles should be listening. It
+ * should be a function tracking a snapshot state.
+ */
+ @Composable
+ fun ContentScope.TileGrid(
+ tiles: List<TileViewModel>,
+ modifier: Modifier,
+ listening: () -> Boolean,
+ )
@Composable
fun EditTileGrid(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index a07120629d2b..feb4d41e49b6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -32,7 +32,6 @@ import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshotFlow
@@ -65,17 +64,16 @@ constructor(
@PaginatedBaseLayoutType private val delegateGridLayout: PaginatableGridLayout,
) : GridLayout by delegateGridLayout {
@Composable
- override fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
+ override fun ContentScope.TileGrid(
+ tiles: List<TileViewModel>,
+ modifier: Modifier,
+ listening: () -> Boolean,
+ ) {
val viewModel =
rememberViewModel(traceName = "PaginatedGridLayout-TileGrid") {
viewModelFactory.create()
}
- DisposableEffect(tiles) {
- val token = Any()
- tiles.forEach { it.startListening(token) }
- onDispose { tiles.forEach { it.stopListening(token) } }
- }
val columns = viewModel.columns
val rows = integerResource(R.integer.quick_settings_paginated_grid_num_rows)
@@ -122,7 +120,7 @@ constructor(
) {
val page = pages[it]
- with(delegateGridLayout) { TileGrid(tiles = page, modifier = Modifier) }
+ with(delegateGridLayout) { TileGrid(tiles = page, modifier = Modifier, listening) }
}
FooterBar(
buildNumberViewModelFactory = viewModel.buildNumberViewModelFactory,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index cdc03bb9be35..d20b360756d7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -18,7 +18,6 @@ package com.android.systemui.qs.panels.ui.compose
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
@@ -41,6 +40,7 @@ import com.android.systemui.res.R
fun ContentScope.QuickQuickSettings(
viewModel: QuickQuickSettingsViewModel,
modifier: Modifier = Modifier,
+ listening: () -> Boolean,
) {
val sizedTiles = viewModel.tileViewModels
@@ -51,11 +51,6 @@ fun ContentScope.QuickQuickSettings(
val spans by remember(sizedTiles) { derivedStateOf { sizedTiles.fastMap { it.width } } }
- DisposableEffect(tiles) {
- val token = Any()
- tiles.forEach { it.startListening(token) }
- onDispose { tiles.forEach { it.stopListening(token) } }
- }
val columns = viewModel.columns
Box(modifier = modifier) {
GridAnchor()
@@ -91,4 +86,6 @@ fun ContentScope.QuickQuickSettings(
}
}
}
+
+ TileListener(tiles, listening)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
index fd10f917106b..1858825f91ef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt
@@ -22,9 +22,13 @@ import com.android.compose.animation.scene.ContentScope
import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
@Composable
-fun ContentScope.TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
+fun ContentScope.TileGrid(
+ viewModel: TileGridViewModel,
+ modifier: Modifier = Modifier,
+ listening: () -> Boolean = { true },
+) {
val gridLayout = viewModel.gridLayout
val tiles = viewModel.tileViewModels
- with(gridLayout) { TileGrid(tiles, modifier) }
+ with(gridLayout) { TileGrid(tiles, modifier, listening) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt
new file mode 100644
index 000000000000..6fb8f1bb79a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.ui.compose
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.snapshotFlow
+import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+
+/**
+ * Use to have tiles start/stop listening when this is composed. Additionally, the listening state
+ * will be gated by [listeningEnabled].
+ */
+@Composable
+fun TileListener(tiles: List<TileViewModel>, listeningEnabled: () -> Boolean) {
+ LaunchedEffect(tiles) {
+ val token = Any()
+ try {
+ snapshotFlow { listeningEnabled() }
+ .collect { listening ->
+ tiles.forEach {
+ if (listening) {
+ it.startListening(token)
+ } else {
+ it.stopListening(token)
+ }
+ }
+ }
+ } finally {
+ tiles.forEach { it.stopListening(token) }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 0503049382a8..6236ada46374 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -17,7 +17,6 @@
package com.android.systemui.qs.panels.ui.compose.infinitegrid
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
@@ -34,6 +33,7 @@ import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
+import com.android.systemui.qs.panels.ui.compose.TileListener
import com.android.systemui.qs.panels.ui.compose.bounceableInfo
import com.android.systemui.qs.panels.ui.compose.rememberEditListState
import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
@@ -59,12 +59,11 @@ constructor(
) : PaginatableGridLayout {
@Composable
- override fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
- DisposableEffect(tiles) {
- val token = Any()
- tiles.forEach { it.startListening(token) }
- onDispose { tiles.forEach { it.stopListening(token) } }
- }
+ override fun ContentScope.TileGrid(
+ tiles: List<TileViewModel>,
+ modifier: Modifier,
+ listening: () -> Boolean,
+ ) {
val viewModel =
rememberViewModel(traceName = "InfiniteGridLayout.TileGrid") {
viewModelFactory.create()
@@ -116,6 +115,8 @@ constructor(
)
}
}
+
+ TileListener(tiles, listening)
}
@Composable