Fix mediaOffset for QQS flexiglass

The problem is that the tiles in the QQS are centered inside of a
container, that has an offset on the bottom. This change centers
MediaCarousel in the QS and applies a corresponding offset to it. More
details and a picture is in the bug.

Flag: com.android.systemui.scene_container
Fixes: 360130533
Test: manual on foldable: observe media carousel in all possible configurations
Change-Id: I58187f9f7219a1a7f9c3f71c818fe0e51d22cebd
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index a6d5c1c..e9c5c03 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -29,6 +29,8 @@
 import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.viewinterop.AndroidView
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -45,6 +47,7 @@
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Expanding
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.UnsquishingQQS
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.UnsquishingQS
+import com.android.systemui.res.R
 import com.android.systemui.scene.shared.model.Scenes
 
 object QuickSettings {
@@ -73,10 +76,21 @@
         val MediaLandscapeTopOffset = ValueKey("MediaLandscapeTopOffset")
 
         object MediaOffset {
-            val InQQS = 0.dp
             // Brightness + padding
             val InQS = 92.dp
             val Default = 0.dp
+
+            @Composable
+            fun inQqs(isMediaInRow: Boolean): Dp {
+                return if (isMediaInRow) {
+                    // Tiles are laid out in a center of a container, that has this
+                    // margin on the bottom. This compensates this margin, so that the Media
+                    // Carousel can be properly centered
+                    -dimensionResource(id = R.dimen.qqs_layout_padding_bottom) / 2
+                } else {
+                    0.dp
+                }
+            }
         }
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index ef415b1..219c4cf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -70,7 +70,7 @@
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
-import com.android.compose.animation.scene.animateSceneDpAsState
+import com.android.compose.animation.scene.animateContentDpAsState
 import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.modifiers.padding
@@ -101,7 +101,6 @@
 import com.android.systemui.qs.ui.composable.BrightnessMirror
 import com.android.systemui.qs.ui.composable.QuickSettings
 import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset
-import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaOffset.InQQS
 import com.android.systemui.res.R
 import com.android.systemui.scene.session.ui.composable.SaveableSession
 import com.android.systemui.scene.shared.model.Scenes
@@ -292,7 +291,11 @@
     // Media is visible and we are in landscape on a small height screen
     val mediaInRow = isMediaVisible && isLandscape()
     val mediaOffset by
-        animateSceneDpAsState(value = InQQS, key = MediaLandscapeTopOffset, canOverflow = false)
+        animateContentDpAsState(
+            value = QuickSettings.SharedValues.MediaOffset.inQqs(mediaInRow),
+            key = MediaLandscapeTopOffset,
+            canOverflow = false,
+        )
 
     val navBarHeight = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
index 6275ac3..352d29e2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt
@@ -90,19 +90,28 @@
                 y = insetsTop + shadeHeaderPlaceable.height,
             )
 
-            if (isMediaInRow) {
-                mediaPlaceable?.placeRelative(
-                    x = insetsLeft + constraintsWithCutout.maxWidth / 2,
-                    y = mediaOffset() + insetsTop + shadeHeaderPlaceable.height,
-                    zIndex = mediaZIndex(),
-                )
-            } else {
-                mediaPlaceable?.placeRelative(
-                    x = insetsLeft,
-                    y = insetsTop + shadeHeaderPlaceable.height + quickSettingsPlaceable.height,
-                    zIndex = mediaZIndex(),
-                )
-            }
+            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 =
+                        (quickSettingsPlaceable.height - mediaPlaceable.height) / 2
+                    mediaPlaceable.placeRelative(
+                        x = insetsLeft + constraintsWithCutout.maxWidth / 2,
+                        y =
+                            insetsTop +
+                                shadeHeaderPlaceable.height +
+                                mediaCenteringOffset +
+                                mediaOffset(),
+                        zIndex = mediaZIndex(),
+                    )
+                } else {
+                    mediaPlaceable.placeRelative(
+                        x = insetsLeft,
+                        y = insetsTop + shadeHeaderPlaceable.height + quickSettingsPlaceable.height,
+                        zIndex = mediaZIndex(),
+                    )
+                }
 
             // Notifications don't need to accommodate for horizontal insets
             notificationsPlaceable.placeRelative(x = 0, y = notificationsTop)