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

Commit 1842162b authored by Ale Nijamkin's avatar Ale Nijamkin
Browse files

[flexiglass] alwaysCompose QS scene

This is a performance optimization where we make content in the QS scene
(single shade) always compose (e.g. compose but
remain invisible, even when not current content). This helps with the
heavy cost of composing this content, which is burdened by a lot of
Text.

Note that this CL doesn't change the default minActiveState of the
rememberViewModel calls in either class. The default of STARTED is safe
because it will only be achieved when the transition to the content is
complete.

The CL also makes TileListener utilize LaunchedEffectWithLifecycle
instead of just LaunchedEffect so tiles don't listen forever.

Bug: 430488243
Fix: 435719827
Test: manually verified that I can navigate to the scene and that its interactive to touch
Test: turned on verbose logging for QSLog and filtered for "listening"
watched it switch from false to true when opening QQS and then QS and
from true back to false as I closed QS and collapsed the shade
Flag: com.android.systemui.scene_container

Change-Id: Ifccb459b47f3f4d1da334fe41bac427ba3e0c230
parent 43426fbe
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -86,7 +86,10 @@ import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.constrainHeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.compose.currentStateAsState
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
@@ -317,6 +320,27 @@ fun ContentScope.NotificationScrollingStack(
    supportNestedScrolling: Boolean,
    onEmptySpaceClick: (() -> Unit)? = null,
) {
    val lifecycleState by LocalLifecycleOwner.current.lifecycle.currentStateAsState()
    if (!lifecycleState.isAtLeast(Lifecycle.State.STARTED)) {
        // Some scenes or overlays that use this Composable may be using alwaysCompose=true which
        // will cause them to compose everything but not be visible. Because this Composable has
        // many side effects that push UI state upstream to its view-model, interactors, and
        // repositories and because the repositories are shared across callers of this Composable,
        // the cleanest way to prevent always-composing but invisible scenes/overlays from polluting
        // the shared state with bogus values is to prevent this entire Composable from actually
        // composing at all.
        //
        // Note that this optimization is very wide and is actively contradicting the point of
        // alwaysCompose=true (which attempts to pre-compose as much as it can), the initial use of
        // alwaysCompose=true is to always compose QS content, not notifications.
        //
        // Should a more granular optimization be preferred, we can let this Composable compose but
        // dive deeper into it and make sure that all of the side effects that send state upstream
        // to its view-model are properly taking lifecycle state into account.
        Box(modifier)
        return
    }

    val composeViewRoot = LocalView.current
    val coroutineScope = shadeSession.sessionCoroutineScope(key = "NotificationScrollingStack")
    val density = LocalDensity.current
+1 −1
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ constructor(

    override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions

    override val alwaysCompose: Boolean = false
    override val alwaysCompose: Boolean = true

    override suspend fun onActivated(): Nothing {
        actionsViewModel.activate()
+2 −2
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@
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.compose.lifecycle.LaunchedEffectWithLifecycle
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel

/**
@@ -27,7 +27,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
 */
@Composable
fun TileListener(tiles: List<TileViewModel>, listeningEnabled: () -> Boolean) {
    LaunchedEffect(tiles) {
    LaunchedEffectWithLifecycle(tiles) {
        val token = Any()
        try {
            snapshotFlow { listeningEnabled() }