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

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

Group media and QQS in SingleShade

This allows to expand them together. Also, it simplifies
SingleShadeMeasurePolicy.

Drive by fix of media additional actions element: use the debugName as
the identity so they actually can be matched.

Test: manual, media in portrait and landscape
Fixes: 439628547
Flag: com.android.systemui.scene_container
Change-Id: Ida1e11a7c2a242ce755b75bd82219f2c01ffa314
parent 21492f3d
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.tween
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
import com.android.systemui.media.remedia.ui.compose.Media
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.shared.ui.QuickSettings
import com.android.systemui.shade.ui.composable.Shade
@@ -41,8 +40,7 @@ fun TransitionBuilder.toShadeSceneTransition(durationScale: Double = 1.0) {
    fade(Shade.Elements.BackgroundScrim)

    val qsTranslation = -ShadeHeader.Dimensions.CollapsedHeightForTransitions * 0.66f
    translate(QuickSettings.Elements.QuickQuickSettings, y = qsTranslation)
    translate(Media.Elements.mediaCarousel, y = qsTranslation)
    translate(QuickSettings.Elements.QuickQuickSettingsAndMedia, y = qsTranslation)
    translate(Notifications.Elements.NotificationScrim, Edge.Top, false)
}

+66 −46
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.shade.ui.composable
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -251,10 +252,9 @@ private fun ContentScope.SingleShade(
    val shadeHorizontalPadding =
        dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
    val shadeMeasurePolicy =
        remember(mediaInRow, cutout, cutoutInsets) {
        remember(cutout, cutoutInsets) {
            val cutoutLocation = cutout().location
            SingleShadeMeasurePolicy(
                isMediaInRow = mediaInRow,
                onNotificationsTopChanged = { maxNotifScrimTop = it },
                cutoutInsetsProvider = {
                    if (cutoutLocation == CutoutLocation.CENTER) {
@@ -292,12 +292,14 @@ private fun ContentScope.SingleShade(
                val qqsLayoutPaddingBottom = 16.dp
                val qsHorizontalMargin =
                    shadeHorizontalPadding + dimensionResource(id = R.dimen.qs_horizontal_margin)
                Box(
                    Modifier.element(QuickSettings.Elements.QuickQuickSettings)
                        .layoutId(SingleShadeMeasurePolicy.LayoutId.QuickSettings)
                        .padding(horizontal = qsHorizontalMargin)
                MediaAndQqsLayout(
                    modifier =
                        Modifier.element(QuickSettings.Elements.QuickQuickSettingsAndMedia)
                            .layoutId(SingleShadeMeasurePolicy.LayoutId.MediaAndQqs)
                            .padding(bottom = qqsLayoutPaddingBottom)
                ) {
                            .padding(horizontal = qsHorizontalMargin),
                    tiles = {
                        Box {
                            val qqsViewModel =
                                rememberViewModel(traceName = "shade_scene_qqs") {
                                    viewModel.quickQuickSettingsViewModel.create()
@@ -310,20 +312,11 @@ private fun ContentScope.SingleShade(
                                )
                            }
                        }
                    },
                    media =
                        @Composable {
                            if (viewModel.isQsEnabled && viewModel.showMedia) {
                    Element(
                        key = Media.Elements.mediaCarousel,
                        modifier =
                            Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Media)
                                .padding(
                                    end = qsHorizontalMargin,
                                    // Only apply padding at the start if not in row, if in row, we
                                    // have
                                    // the end padding of qs.
                                    start = if (mediaInRow) 0.dp else qsHorizontalMargin,
                                )
                                .padding(bottom = qqsLayoutPaddingBottom),
                    ) {
                                Element(key = Media.Elements.mediaCarousel, modifier = Modifier) {
                                    Media(
                                        viewModelFactory = viewModel.mediaViewModelFactory,
                                        presentationStyle =
@@ -337,6 +330,9 @@ private fun ContentScope.SingleShade(
                                    )
                                }
                            }
                        },
                    mediaInRow = mediaInRow,
                )

                NotificationScrollingStack(
                    shadeSession = shadeSession,
@@ -367,6 +363,30 @@ private fun ContentScope.SingleShade(
    }
}

@Composable
private fun MediaAndQqsLayout(
    tiles: @Composable () -> Unit,
    media: @Composable () -> Unit,
    mediaInRow: Boolean,
    modifier: Modifier = Modifier,
) {
    if (mediaInRow) {
        Row(
            modifier = modifier,
            horizontalArrangement = spacedBy(dimensionResource(R.dimen.qs_tile_margin_vertical)),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            Box(modifier = Modifier.weight(1f)) { tiles() }
            Box(modifier = Modifier.weight(1f)) { media() }
        }
    } else {
        Column(modifier = modifier, verticalArrangement = spacedBy(16.dp)) {
            tiles()
            media()
        }
    }
}

@Composable
private fun ContentScope.SplitShade(
    notificationStackScrollView: NotificationScrollView,
+10 −74
Original line number Diff line number Diff line
@@ -27,21 +27,18 @@ import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.offset
import androidx.compose.ui.util.fastFirstOrNull
import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy.LayoutId
import kotlin.math.max

/**
 * Lays out elements from the [LayoutId] in the shade. This policy supports the case when the QS and
 * UMO share the same row and when they should be one below another.
 */
class SingleShadeMeasurePolicy(
    private val isMediaInRow: Boolean,
    private val onNotificationsTopChanged: (Int) -> Unit,
    private val cutoutInsetsProvider: () -> WindowInsets?,
) : MeasurePolicy {

    enum class LayoutId {
        QuickSettings,
        Media,
        MediaAndQqs,
        Notifications,
        ShadeHeader,
    }
@@ -59,14 +56,10 @@ class SingleShadeMeasurePolicy(
            measurables
                .fastFirstOrNull { it.layoutId == LayoutId.ShadeHeader }
                ?.measure(constraintsWithCutout)
        val mediaPlaceable =
        val mediaAndQqsPlaceable =
            measurables
                .fastFirstOrNull { it.layoutId == LayoutId.Media }
                ?.measure(constraintsWithCutout.mediaConstraints(isMediaInRow))
        val quickSettingsPlaceable =
            measurables
                .fastFirstOrNull { it.layoutId == LayoutId.QuickSettings }
                ?.measure(constraintsWithCutout.qsTilesConstraints(isMediaInRow))
                .fastFirstOrNull { it.layoutId == LayoutId.MediaAndQqs }
                ?.measure(constraintsWithCutout)
        val notificationsPlaceable =
            measurables
                .fastFirstOrNull { it.layoutId == LayoutId.Notifications }
@@ -75,10 +68,8 @@ class SingleShadeMeasurePolicy(
        val notificationsTop =
            calculateNotificationsTop(
                statusBarHeaderPlaceable = shadeHeaderPlaceable,
                quickSettingsPlaceable = quickSettingsPlaceable,
                mediaPlaceable = mediaPlaceable,
                mediaAndQqsPlaceable = mediaAndQqsPlaceable,
                insetsTop = insetsTop,
                isMediaInRow = isMediaInRow,
            )
        onNotificationsTopChanged(notificationsTop)

@@ -86,36 +77,10 @@ class SingleShadeMeasurePolicy(
            shadeHeaderPlaceable?.placeRelative(x = insetsLeft, y = insetsTop)
            val statusBarHeaderHeight = shadeHeaderPlaceable?.height ?: 0

            val quickSettingsHeight = quickSettingsPlaceable?.height ?: 0
            val quickSettingsOffset =
                if (isMediaInRow && mediaPlaceable != null) {
                    max((mediaPlaceable.height - quickSettingsHeight) / 2, 0)
                } else {
                    0
                }

            quickSettingsPlaceable?.placeRelative(
                x = insetsLeft,
                y = insetsTop + statusBarHeaderHeight + quickSettingsOffset,
            )

            if (mediaPlaceable != null) {
                if (isMediaInRow) {
                    // mediaPlaceable height ranges from 0 to qsHeight. We want it to be centered
                    // vertically when it's smaller than the QS
                    val mediaCenteringOffset =
                        max((quickSettingsHeight - mediaPlaceable.height) / 2, 0)
                    mediaPlaceable.placeRelative(
                        x = insetsLeft + constraintsWithCutout.maxWidth / 2,
                        y = insetsTop + statusBarHeaderHeight + mediaCenteringOffset,
                    )
                } else {
                    mediaPlaceable.placeRelative(
            mediaAndQqsPlaceable?.placeRelative(
                x = insetsLeft,
                        y = insetsTop + statusBarHeaderHeight + quickSettingsHeight,
                y = insetsTop + statusBarHeaderHeight,
            )
                }
            }

            // Notifications don't need to accommodate for horizontal insets
            notificationsPlaceable?.placeRelative(x = 0, y = notificationsTop)
@@ -124,42 +89,13 @@ class SingleShadeMeasurePolicy(

    private fun calculateNotificationsTop(
        statusBarHeaderPlaceable: Placeable?,
        quickSettingsPlaceable: Placeable?,
        mediaPlaceable: Placeable?,
        mediaAndQqsPlaceable: Placeable?,
        insetsTop: Int,
        isMediaInRow: Boolean,
    ): Int {
        val mediaHeight = mediaPlaceable?.height ?: 0
        val statusBarHeaderHeight = statusBarHeaderPlaceable?.height ?: 0
        val quickSettingsHeight = quickSettingsPlaceable?.height ?: 0
        val mediaAndQqsHeight = mediaAndQqsPlaceable?.height ?: 0

        return insetsTop +
            statusBarHeaderHeight +
            if (isMediaInRow) {
                max(quickSettingsHeight, mediaHeight)
            } else {
                quickSettingsHeight + mediaHeight
            }
    }

    private fun Constraints.halfWidthConstraints(): Constraints {
        return copy(maxWidth = maxWidth / 2)
    }

    private fun Constraints.mediaConstraints(isMediaInRow: Boolean): Constraints {
        return if (isMediaInRow) {
            halfWidthConstraints()
        } else {
            this
        }
    }

    private fun Constraints.qsTilesConstraints(isMediaInRow: Boolean): Constraints {
        return if (isMediaInRow) {
            halfWidthConstraints()
        } else {
            this
        }
        return insetsTop + statusBarHeaderHeight + mediaAndQqsHeight
    }

    private fun MeasureScope.applyCutout(
+2 −1
Original line number Diff line number Diff line
@@ -1541,7 +1541,8 @@ object Media {
        val mediaCarousel = ElementKey("media_carousel")

        fun additionalActionButton(index: Int): ElementKey {
            return ElementKey("additional_action_$index")
            val name = "additional_action_$index"
            return ElementKey(debugName = name, identity = name)
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ object QuickSettings {

        val TileElementMatcher = ElementKey.withIdentity { it is TileIdentity }

        val QuickQuickSettings = ElementKey("QuickQuickSettings")
        val QuickQuickSettingsAndMedia = ElementKey("QuickQuickSettingsAndMedia")
        val SplitShadeQuickSettings = ElementKey("SplitShadeQuickSettings")
    }