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

Commit 04cc957e authored by Beth Thibodeau's avatar Beth Thibodeau
Browse files

Add media carousel to quick settings scene

Also update other scenes to simplify common code

Bug: 296122467
Test: QuickSettingsSceneViewModelTest
Test: manual, with flags on/off
Flag: ACONFIG com.android.systemui.media_in_scene_container DEVELOPMENT
Change-Id: I860d73d7846da0a105ee1da53fbbc966f45a6fbe
parent c18024b3
Loading
Loading
Loading
Loading
+8 −25
Original line number Diff line number Diff line
@@ -17,21 +17,14 @@
package com.android.systemui.keyguard.ui.composable.section

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.dimensionResource
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.keyguard.ui.viewmodel.MediaCarouselViewModel
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.res.R
import com.android.systemui.util.animation.MeasurementInput
import javax.inject.Inject
import javax.inject.Named

@@ -43,29 +36,19 @@ constructor(
    private val mediaCarouselViewModel: MediaCarouselViewModel,
) {

    @Composable
    fun SceneScope.MediaCarousel(modifier: Modifier = Modifier) {
        if (!mediaCarouselViewModel.isMediaVisible) {
            return
        }

    private fun isVisible(): Boolean {
        if (mediaCarouselController.mediaFrame == null) {
            return
            return false
        }
        return mediaCarouselViewModel.isMediaVisible
    }

        val mediaHeight = dimensionResource(R.dimen.qs_media_session_height_expanded)
        // TODO(b/312714128): MediaPlayer background size is not as expected.
    @Composable
    fun SceneScope.KeyguardMediaCarousel() {
        MediaCarousel(
            modifier =
                modifier.height(mediaHeight).fillMaxWidth().onSizeChanged { size ->
                    // Notify controller to size the carousel for the
                    // current space
                    mediaHost.measurementInput = MeasurementInput(size.width, size.height)
                    mediaCarouselController.setSceneContainerSize(size.width, size.height)
                },
            isVisible = ::isVisible,
            mediaHost = mediaHost,
            layoutWidth = 0, // Layout width is not used.
            layoutHeight = with(LocalDensity.current) { mediaHeight.toPx() }.toInt(),
            modifier = Modifier.fillMaxWidth(),
            carouselController = mediaCarouselController,
        )
    }
+1 −1
Original line number Diff line number Diff line
@@ -125,7 +125,7 @@ constructor(
                    onTopChanged = burnIn.onSmartspaceTopChanged,
                )
            }
            with(mediaCarouselSection) { MediaCarousel() }
            with(mediaCarouselSection) { KeyguardMediaCarousel() }
        }
    }

+31 −3
Original line number Diff line number Diff line
@@ -18,14 +18,20 @@ package com.android.systemui.media.controls.ui.composable

import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.contains
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.res.R
import com.android.systemui.util.animation.MeasurementInput

private object MediaCarousel {
@@ -36,18 +42,40 @@ private object MediaCarousel {

@Composable
fun SceneScope.MediaCarousel(
    isVisible: () -> Boolean,
    mediaHost: MediaHost,
    modifier: Modifier = Modifier,
    layoutWidth: Int,
    layoutHeight: Int,
    carouselController: MediaCarouselController,
) {
    if (!isVisible()) {
        return
    }

    val density = LocalDensity.current
    val mediaHeight = dimensionResource(R.dimen.qs_media_session_height_expanded)

    val layoutWidth = 0
    val layoutHeight = with(density) { mediaHeight.toPx() }.toInt()

    // Notify controller to size the carousel for the current space
    mediaHost.measurementInput = MeasurementInput(layoutWidth, layoutHeight)
    carouselController.setSceneContainerSize(layoutWidth, layoutHeight)

    AndroidView(
        modifier = modifier.element(MediaCarousel.Elements.Content),
        modifier =
            modifier
                .element(MediaCarousel.Elements.Content)
                .height(mediaHeight)
                .fillMaxWidth()
                .layout { measurable, constraints ->
                    val placeable = measurable.measure(constraints)

                    // Notify controller to size the carousel for the current space
                    mediaHost.measurementInput = MeasurementInput(placeable.width, placeable.height)
                    carouselController.setSceneContainerSize(placeable.width, placeable.height)

                    layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
                },
        factory = { context ->
            FrameLayout(context).apply {
                val mediaFrame = carouselController.mediaFrame
+18 −0
Original line number Diff line number Diff line
@@ -67,6 +67,10 @@ import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.media.controls.ui.controller.MediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.notifications.ui.composable.NotificationScrollingStack
import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility
import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
@@ -82,6 +86,7 @@ import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import javax.inject.Inject
import javax.inject.Named
import kotlin.math.roundToInt
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -98,6 +103,8 @@ constructor(
    private val tintedIconManagerFactory: TintedIconManager.Factory,
    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
    private val statusBarIconController: StatusBarIconController,
    private val mediaCarouselController: MediaCarouselController,
    @Named(MediaModule.QS_PANEL) private val mediaHost: MediaHost,
) : ComposableScene {
    override val key = Scenes.QuickSettings

@@ -118,6 +125,8 @@ constructor(
            createTintedIconManager = tintedIconManagerFactory::create,
            createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
            statusBarIconController = statusBarIconController,
            mediaCarouselController = mediaCarouselController,
            mediaHost = mediaHost,
            modifier = modifier,
        )
    }
@@ -130,6 +139,8 @@ private fun SceneScope.QuickSettingsScene(
    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
    statusBarIconController: StatusBarIconController,
    mediaCarouselController: MediaCarouselController,
    mediaHost: MediaHost,
    modifier: Modifier = Modifier,
) {
    val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState()
@@ -282,6 +293,13 @@ private fun SceneScope.QuickSettingsScene(
                        isSplitShade = false,
                        modifier = Modifier.sysuiResTag("expanded_qs_scroll_view"),
                    )

                    MediaCarousel(
                        isVisible = viewModel::isMediaVisible,
                        mediaHost = mediaHost,
                        modifier = Modifier.fillMaxWidth(),
                        carouselController = mediaCarouselController,
                    )
                }
            }

+7 −40
Original line number Diff line number Diff line
@@ -50,11 +50,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexScenePicker
@@ -85,7 +83,6 @@ import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.ui.StatusBarIconController
import com.android.systemui.statusbar.phone.ui.TintedIconManager
import com.android.systemui.util.animation.MeasurementInput
import javax.inject.Inject
import javax.inject.Named
import kotlin.math.roundToInt
@@ -243,10 +240,11 @@ private fun SceneScope.SingleShade(
                                )
                            }

                            MediaIfVisible(
                                viewModel = viewModel,
                                mediaCarouselController = mediaCarouselController,
                            MediaCarousel(
                                isVisible = viewModel::isMediaVisible,
                                mediaHost = mediaHost,
                                modifier = Modifier.fillMaxWidth(),
                                carouselController = mediaCarouselController,
                            )

                            Spacer(modifier = Modifier.height(16.dp))
@@ -406,11 +404,11 @@ private fun SceneScope.SplitShade(
                                )
                            }

                            MediaIfVisible(
                                viewModel = viewModel,
                                mediaCarouselController = mediaCarouselController,
                            MediaCarousel(
                                isVisible = viewModel::isMediaVisible,
                                mediaHost = mediaHost,
                                modifier = Modifier.fillMaxWidth(),
                                carouselController = mediaCarouselController,
                            )
                        }
                        FooterActionsWithAnimatedVisibility(
@@ -437,34 +435,3 @@ private fun SceneScope.SplitShade(
        }
    }
}

@Composable
private fun SceneScope.MediaIfVisible(
    viewModel: ShadeSceneViewModel,
    mediaCarouselController: MediaCarouselController,
    mediaHost: MediaHost,
    modifier: Modifier = Modifier,
) {
    if (viewModel.isMediaVisible()) {
        val density = LocalDensity.current
        val mediaHeight = dimensionResource(R.dimen.qs_media_session_height_expanded)

        MediaCarousel(
            modifier =
                modifier.height(mediaHeight).fillMaxWidth().layout { measurable, constraints ->
                    val placeable = measurable.measure(constraints)

                    // Notify controller to size the carousel for the
                    // current space
                    mediaHost.measurementInput = MeasurementInput(placeable.width, placeable.height)
                    mediaCarouselController.setSceneContainerSize(placeable.width, placeable.height)

                    layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
                },
            mediaHost = mediaHost,
            layoutWidth = 0,
            layoutHeight = with(density) { mediaHeight.toPx() }.toInt(),
            carouselController = mediaCarouselController,
        )
    }
}
Loading