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

Commit 61a6e9df authored by burakov's avatar burakov
Browse files

[bc25] Overlays migration: Deprecation of the shade scenes.

This CL deprecates the notifications and quick settings shade scenes,
which are being replaced by the respective overlays.

Entry points (via user actions), scene family resolutions, and
transition definitions will be updated in follow-up CLs. Once those are
done we'll be able to delete the shade scenes.

Summary of additional changes in this CL:
* Simplify the OverlayShade composable by removing the concept of
  backgroundScene and removing its dedicated view-model.
* Add NotificationsShadeSceneContentViewModel.
* Move all rendering of QS content to the QS overlay.
* Clicking on the scrim in legacy shade scenes has no effect anymore.

Bug: 356596436
Flag: com.android.systemui.dual_shade
Flag: com.android.systemui.scene_container
Test: Added unit tests for the new view-model and updated existing ones.
Test: Existing unit tests still pass.
Change-Id: I0c6a9bfb842c18cc33608b20c12af3c4b6bb8726
parent 53bc4e7b
Loading
Loading
Loading
Loading
+13 −15
Original line number Diff line number Diff line
@@ -27,20 +27,17 @@ import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel
import com.android.systemui.scene.session.ui.composable.SaveableSession
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.ui.composable.Overlay
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import dagger.Lazy
import java.util.Optional
import javax.inject.Inject

@SysUISingleton
@@ -48,9 +45,7 @@ class NotificationsShadeOverlay
@Inject
constructor(
    private val actionsViewModelFactory: NotificationsShadeOverlayActionsViewModel.Factory,
    private val overlayShadeViewModelFactory: OverlayShadeViewModel.Factory,
    private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
    private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
    private val contentViewModelFactory: NotificationsShadeOverlayContentViewModel.Factory,
    private val tintedIconManagerFactory: TintedIconManager.Factory,
    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
    private val statusBarIconController: StatusBarIconController,
@@ -72,19 +67,22 @@ constructor(
    override fun ContentScope.Content(
        modifier: Modifier,
    ) {
        val viewModel =
            rememberViewModel("NotificationsShadeOverlay-viewModel") {
                contentViewModelFactory.create()
            }
        val placeholderViewModel =
            rememberViewModel("NotificationsShadeOverlay-notifPlaceholderViewModel") {
                viewModel.notificationsPlaceholderViewModelFactory.create()
            }

        OverlayShade(
            modifier = modifier,
            viewModelFactory = overlayShadeViewModelFactory,
            lockscreenContent = { Optional.empty() },
            onScrimClicked = viewModel::onScrimClicked,
        ) {
            Column {
                val placeholderViewModel =
                    rememberViewModel("NotificationsShadeOverlay") {
                        notificationsPlaceholderViewModelFactory.create()
                    }

                ExpandedShadeHeader(
                    viewModelFactory = shadeHeaderViewModelFactory,
                    viewModelFactory = viewModel.shadeHeaderViewModelFactory,
                    createTintedIconManager = tintedIconManagerFactory::create,
                    createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
                    statusBarIconController = statusBarIconController,
+1 −7
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeSceneActionsViewModel
@@ -37,14 +36,12 @@ import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import dagger.Lazy
import java.util.Optional
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow

@@ -53,7 +50,6 @@ class NotificationsShadeScene
@Inject
constructor(
    private val actionsViewModelFactory: NotificationsShadeSceneActionsViewModel.Factory,
    private val overlayShadeViewModelFactory: OverlayShadeViewModel.Factory,
    private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
    private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
    private val tintedIconManagerFactory: TintedIconManager.Factory,
@@ -61,7 +57,6 @@ constructor(
    private val statusBarIconController: StatusBarIconController,
    private val shadeSession: SaveableSession,
    private val stackScrollView: Lazy<NotificationScrollView>,
    private val lockscreenContent: Lazy<Optional<LockscreenContent>>,
) : ExclusiveActivatable(), ComposableScene {

    override val key = Scenes.NotificationsShade
@@ -88,8 +83,7 @@ constructor(

        OverlayShade(
            modifier = modifier,
            viewModelFactory = overlayShadeViewModelFactory,
            lockscreenContent = lockscreenContent,
            onScrimClicked = {},
        ) {
            Column {
                ExpandedShadeHeader(
+78 −3
Original line number Diff line number Diff line
@@ -16,14 +16,32 @@

package com.android.systemui.qs.ui.composable

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.qs.panels.ui.compose.EditMode
import com.android.systemui.qs.panels.ui.compose.TileGrid
import com.android.systemui.qs.ui.viewmodel.QuickSettingsContainerViewModel
import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayActionsViewModel
import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayContentViewModel
import com.android.systemui.scene.shared.model.Overlays
@@ -32,7 +50,6 @@ import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import java.util.Optional
import javax.inject.Inject

@SysUISingleton
@@ -62,10 +79,10 @@ constructor(
    ) {
        val viewModel =
            rememberViewModel("QuickSettingsShadeOverlay") { contentViewModelFactory.create() }

        OverlayShade(
            modifier = modifier,
            viewModelFactory = viewModel.overlayShadeViewModelFactory,
            lockscreenContent = { Optional.empty() },
            onScrimClicked = viewModel::onScrimClicked,
        ) {
            Column {
                ExpandedShadeHeader(
@@ -83,3 +100,61 @@ constructor(
        }
    }
}

@Composable
fun ShadeBody(
    viewModel: QuickSettingsContainerViewModel,
) {
    val isEditing by viewModel.editModeViewModel.isEditing.collectAsStateWithLifecycle()

    AnimatedContent(
        targetState = isEditing,
        transitionSpec = { fadeIn(tween(500)) togetherWith fadeOut(tween(500)) }
    ) { editing ->
        if (editing) {
            EditMode(
                viewModel = viewModel.editModeViewModel,
                modifier = Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding)
            )
        } else {
            QuickSettingsLayout(
                viewModel = viewModel,
                modifier = Modifier.sysuiResTag("quick_settings_panel")
            )
        }
    }
}

@Composable
private fun QuickSettingsLayout(
    viewModel: QuickSettingsContainerViewModel,
    modifier: Modifier = Modifier,
) {
    Column(
        verticalArrangement = Arrangement.spacedBy(QuickSettingsShade.Dimensions.Padding),
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding),
    ) {
        BrightnessSliderContainer(
            viewModel = viewModel.brightnessSliderViewModel,
            modifier =
                Modifier.fillMaxWidth()
                    .height(QuickSettingsShade.Dimensions.BrightnessSliderHeight),
        )
        TileGrid(
            viewModel = viewModel.tileGridViewModel,
            modifier =
                Modifier.fillMaxWidth().heightIn(max = QuickSettingsShade.Dimensions.GridMaxHeight),
            viewModel.editModeViewModel::startEditing,
        )
    }
}

object QuickSettingsShade {

    object Dimensions {
        val Padding = 16.dp
        val BrightnessSliderHeight = 64.dp
        val GridMaxHeight = 800.dp
    }
}
+2 −92
Original line number Diff line number Diff line
@@ -16,40 +16,18 @@

package com.android.systemui.qs.ui.composable

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.qs.panels.ui.compose.EditMode
import com.android.systemui.qs.panels.ui.compose.TileGrid
import com.android.systemui.qs.ui.composable.QuickSettingsShade.Transitions.QuickSettingsLayoutEnter
import com.android.systemui.qs.ui.composable.QuickSettingsShade.Transitions.QuickSettingsLayoutExit
import com.android.systemui.qs.ui.viewmodel.QuickSettingsContainerViewModel
import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneActionsViewModel
import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneContentViewModel
import com.android.systemui.scene.shared.model.Scenes
@@ -59,8 +37,6 @@ import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import dagger.Lazy
import java.util.Optional
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow

@@ -70,7 +46,6 @@ class QuickSettingsShadeScene
constructor(
    private val actionsViewModelFactory: QuickSettingsShadeSceneActionsViewModel.Factory,
    private val contentViewModelFactory: QuickSettingsShadeSceneContentViewModel.Factory,
    private val lockscreenContent: Lazy<Optional<LockscreenContent>>,
    private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
    private val tintedIconManagerFactory: TintedIconManager.Factory,
    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
@@ -96,10 +71,10 @@ constructor(
    ) {
        val viewModel =
            rememberViewModel("QuickSettingsShadeScene") { contentViewModelFactory.create() }

        OverlayShade(
            viewModelFactory = viewModel.overlayShadeViewModelFactory,
            lockscreenContent = lockscreenContent,
            modifier = modifier,
            onScrimClicked = {},
        ) {
            Column {
                ExpandedShadeHeader(
@@ -117,68 +92,3 @@ constructor(
        }
    }
}

@Composable
fun ShadeBody(
    viewModel: QuickSettingsContainerViewModel,
) {
    val isEditing by viewModel.editModeViewModel.isEditing.collectAsStateWithLifecycle()

    AnimatedContent(
        targetState = isEditing,
        transitionSpec = { QuickSettingsLayoutEnter togetherWith QuickSettingsLayoutExit }
    ) { editing ->
        if (editing) {
            EditMode(
                viewModel = viewModel.editModeViewModel,
                modifier = Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding)
            )
        } else {
            QuickSettingsLayout(
                viewModel = viewModel,
                modifier = Modifier.sysuiResTag("quick_settings_panel")
            )
        }
    }
}

@Composable
private fun QuickSettingsLayout(
    viewModel: QuickSettingsContainerViewModel,
    modifier: Modifier = Modifier,
) {
    Column(
        verticalArrangement = Arrangement.spacedBy(QuickSettingsShade.Dimensions.Padding),
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding),
    ) {
        BrightnessSliderContainer(
            viewModel = viewModel.brightnessSliderViewModel,
            modifier =
                Modifier.fillMaxWidth()
                    .height(QuickSettingsShade.Dimensions.BrightnessSliderHeight),
        )
        TileGrid(
            viewModel = viewModel.tileGridViewModel,
            modifier =
                Modifier.fillMaxWidth().heightIn(max = QuickSettingsShade.Dimensions.GridMaxHeight),
            viewModel.editModeViewModel::startEditing,
        )
    }
}

object QuickSettingsShade {

    object Dimensions {
        val Padding = 16.dp
        val BrightnessSliderHeight = 64.dp
        val GridMaxHeight = 800.dp
    }

    object Transitions {
        val QuickSettingsLayoutEnter: EnterTransition = fadeIn(tween(500))
        val QuickSettingsLayoutExit: ExitTransition = fadeOut(tween(500))
        val QuickSettingsEditorEnter: EnterTransition = fadeIn(tween(500))
        val QuickSettingsEditorExit: ExitTransition = fadeOut(tween(500))
    }
}
+4 −24
Original line number Diff line number Diff line
@@ -40,46 +40,26 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexContentPicker
import com.android.compose.animation.scene.SceneScope
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
import com.android.systemui.util.kotlin.getOrNull
import dagger.Lazy
import java.util.Optional

/** The overlay shade renders a lightweight shade UI container on top of a background scene. */

/** Renders a lightweight shade UI container, as an overlay. */
@Composable
fun SceneScope.OverlayShade(
    viewModelFactory: OverlayShadeViewModel.Factory,
    lockscreenContent: Lazy<Optional<LockscreenContent>>,
    onScrimClicked: () -> Unit,
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit,
) {
    val viewModel = rememberViewModel("OverlayShade") { viewModelFactory.create() }
    val backgroundScene by viewModel.backgroundScene.collectAsStateWithLifecycle()

    Box(modifier) {
        if (backgroundScene == Scenes.Lockscreen) {
            // Lockscreen content is optionally injected, because variants of System UI without a
            // lockscreen cannot provide it.
            val lockscreenContentOrNull = lockscreenContent.get().getOrNull()
            lockscreenContentOrNull?.apply { Content(Modifier.fillMaxSize()) }
        }

        Scrim(onClicked = viewModel::onScrimClicked)
        Scrim(onClicked = onScrimClicked)

        Box(
            modifier = Modifier.fillMaxSize().panelPadding(),
Loading