Merge "[Media] Demo app changes." into main
diff --git a/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/Dependencies.kt b/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/Dependencies.kt
new file mode 100644
index 0000000..bb8f00b
--- /dev/null
+++ b/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/Dependencies.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.demo
+
+import androidx.compose.runtime.Composable
+
+data class Dependencies(
+    /** A [Composable] that can render the media player/controls UI element. */
+    val mediaPlayer:
+        (@Composable
+        (
+            presentationStyle: DemoMediaPresentationStyle, onVisibilityChange: (Boolean) -> Unit,
+        ) -> Unit)? =
+        null
+)
diff --git a/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/LocalDependencies.kt b/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/LocalDependencies.kt
new file mode 100644
index 0000000..414c739
--- /dev/null
+++ b/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/LocalDependencies.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.demo
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.compositionLocalOf
+
+val LocalDependencies = compositionLocalOf { Dependencies() }
+
+@Composable
+fun WithLocalDependencies(dependencies: Dependencies, content: @Composable () -> Unit) {
+    CompositionLocalProvider(LocalDependencies provides dependencies, content)
+}
diff --git a/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/MediaPlayer.kt b/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/MediaPlayer.kt
index e2e6595..3f167b3 100644
--- a/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/MediaPlayer.kt
+++ b/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/MediaPlayer.kt
@@ -119,46 +119,74 @@
 
 @Composable
 fun ContentScope.MediaPlayer(
-    isSmall: Boolean,
+    presentationStyle: DemoMediaPresentationStyle,
     isPlaying: Boolean,
     onIsPlayingChange: (Boolean) -> Unit,
+    onVisibilityChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
 ) {
-    val key =
-        if (isSmall) MediaPlayer.Elements.SmallMediaPlayer else MediaPlayer.Elements.MediaPlayer
-    MovableElement(
-        key,
-        modifier
-            .fillMaxWidth()
-            .height(
-                if (isSmall) MediaPlayer.Dimensions.HeightSmall
-                else MediaPlayer.Dimensions.HeightLarge
-            ),
-    ) {
-        content {
-            Box(
-                Modifier.background(
-                        MaterialTheme.colorScheme.tertiary,
-                        MediaPlayer.Shapes.Background,
-                    )
-                    .padding(8.dp)
-            ) {
-                FilledIconButton(
-                    onClick = { onIsPlayingChange(!isPlaying) },
-                    Modifier.align(Alignment.CenterEnd),
-                    colors =
-                        IconButtonDefaults.filledIconButtonColors(
-                            MaterialTheme.colorScheme.onTertiary
-                        ),
+    val injectedContentOrNull = LocalDependencies.current.mediaPlayer
+    if (injectedContentOrNull != null) {
+        Element(
+            key =
+                if (presentationStyle != DemoMediaPresentationStyle.Compact) {
+                    MediaPlayer.Elements.MediaPlayer
+                } else {
+                    MediaPlayer.Elements.SmallMediaPlayer
+                },
+            modifier = modifier.fillMaxWidth(),
+        ) {
+            injectedContentOrNull(presentationStyle, onVisibilityChange)
+        }
+    } else {
+        val isSmall = presentationStyle == DemoMediaPresentationStyle.Compact
+        val key =
+            if (isSmall) {
+                MediaPlayer.Elements.SmallMediaPlayer
+            } else {
+                MediaPlayer.Elements.MediaPlayer
+            }
+
+        MovableElement(
+            key,
+            modifier
+                .fillMaxWidth()
+                .height(
+                    if (isSmall) MediaPlayer.Dimensions.HeightSmall
+                    else MediaPlayer.Dimensions.HeightLarge
+                ),
+        ) {
+            content {
+                Box(
+                    Modifier.background(
+                            MaterialTheme.colorScheme.tertiary,
+                            MediaPlayer.Shapes.Background,
+                        )
+                        .padding(8.dp)
                 ) {
-                    val color = MaterialTheme.colorScheme.tertiary
-                    if (isPlaying) {
-                        Icon(Icons.Default.Pause, null, tint = color)
-                    } else {
-                        Icon(Icons.Default.PlayArrow, null, tint = color)
+                    FilledIconButton(
+                        onClick = { onIsPlayingChange(!isPlaying) },
+                        Modifier.align(Alignment.CenterEnd),
+                        colors =
+                            IconButtonDefaults.filledIconButtonColors(
+                                MaterialTheme.colorScheme.onTertiary
+                            ),
+                    ) {
+                        val color = MaterialTheme.colorScheme.tertiary
+                        if (isPlaying) {
+                            Icon(Icons.Default.Pause, null, tint = color)
+                        } else {
+                            Icon(Icons.Default.PlayArrow, null, tint = color)
+                        }
                     }
                 }
             }
         }
     }
 }
+
+enum class DemoMediaPresentationStyle {
+    Default,
+    Compressed,
+    Compact,
+}
diff --git a/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/SystemUi.kt b/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/SystemUi.kt
index 6cf875c..740a66d 100644
--- a/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/SystemUi.kt
+++ b/samples/SceneTransitionLayoutDemo/src/com/android/compose/animation/scene/demo/SystemUi.kt
@@ -481,22 +481,29 @@
                 LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory(),
             ) {
                 var isMediaPlayerPlaying by remember { mutableStateOf(false) }
-                val mediaPlayer: (@Composable ContentScope.(isSmall: Boolean) -> Unit)? =
+                val mediaPlayer:
+                    (@Composable
+                    ContentScope.(presentationStyle: DemoMediaPresentationStyle) -> Unit)? =
                     if (configuration.showMediaPlayer) {
-                        { isSmall ->
+                        { presentationStyle ->
                             MediaPlayer(
-                                isSmall = isSmall,
+                                presentationStyle = presentationStyle,
                                 isPlaying = isMediaPlayerPlaying,
                                 onIsPlayingChange = { isMediaPlayerPlaying = it },
+                                onVisibilityChange = { isVisible ->
+                                    onConfigurationChange(
+                                        configuration.copy(showMediaPlayer = isVisible)
+                                    )
+                                },
                             )
                         }
                     } else {
                         null
                     }
-                val largeMediaPlayer: (@Composable ContentScope.() -> Unit)? =
-                    mediaPlayer?.let { { it(/* isSmall= */ false) } }
-                val smallMediaPlayer: (@Composable ContentScope.() -> Unit)? =
-                    mediaPlayer?.let { { it(/* isSmall= */ true) } }
+                val defaultMediaPlayer: (@Composable ContentScope.() -> Unit)? =
+                    mediaPlayer?.let { { it(DemoMediaPresentationStyle.Default) } }
+                val compactMediaPlayer: (@Composable ContentScope.() -> Unit)? =
+                    mediaPlayer?.let { { it(DemoMediaPresentationStyle.Compact) } }
 
                 val qsPager: (@Composable ContentScope.() -> Unit) = {
                     QuickSettingsPager(
@@ -561,7 +568,7 @@
                                             configuration.notificationsInLockscreen
                                     )
                                 },
-                                mediaPlayer = largeMediaPlayer,
+                                mediaPlayer = defaultMediaPlayer,
                                 isDismissable = isLockscreenDismissable,
                                 onToggleDismissable = {
                                     isLockscreenDismissable = !isLockscreenDismissable
@@ -584,7 +591,7 @@
                                             configuration.notificationsInLockscreen
                                     )
                                 },
-                                mediaPlayer = largeMediaPlayer,
+                                mediaPlayer = defaultMediaPlayer,
                                 isDismissable = isLockscreenDismissable,
                                 onToggleDismissable = {
                                     isLockscreenDismissable = !isLockscreenDismissable
@@ -624,7 +631,7 @@
                         ) {
                             QuickSettings(
                                 qsPager,
-                                mediaPlayer = largeMediaPlayer,
+                                mediaPlayer = defaultMediaPlayer,
                                 ::onSettingsButtonClicked,
                                 ::onPowerButtonClicked,
                             )
@@ -640,7 +647,7 @@
                                         overscrollEffect = overscrollEffect,
                                     )
                                 },
-                                mediaPlayer = largeMediaPlayer,
+                                mediaPlayer = defaultMediaPlayer,
                                 quickSettingsTiles,
                                 nQuickSettingsColumns,
                             )
@@ -655,7 +662,7 @@
                                         maxNotificationCount = configuration.notificationsInShade
                                     )
                                 },
-                                mediaPlayer = largeMediaPlayer,
+                                mediaPlayer = defaultMediaPlayer,
                                 quickSettingsTiles,
                                 nQuickSettingsSplitShadeRows,
                                 nQuickSettingsColumns,
@@ -674,7 +681,7 @@
                             alignment = Alignment.TopEnd,
                             effectFactory = overlayEffectFactory,
                         ) {
-                            QuickSettingsShade(qsPager, smallMediaPlayer)
+                            QuickSettingsShade(qsPager, compactMediaPlayer)
                         }
 
                         overlay(
@@ -690,7 +697,7 @@
                                     } else {
                                         { Clock(MaterialTheme.colorScheme.onSurfaceVariant) }
                                     },
-                                mediaPlayer = largeMediaPlayer,
+                                mediaPlayer = defaultMediaPlayer,
                                 notificationList = {
                                     NotificationList(
                                         maxNotificationCount = configuration.notificationsInShade,