From e21011864c55ee2a4109f88a7bd80340207856dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaquim=20St=C3=A4hli?= Date: Thu, 14 Dec 2023 17:18:26 +0100 Subject: [PATCH] Update to AndroidX media3 1.2.0 (#364) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gaƫtan Muller --- gradle/libs.versions.toml | 4 +- .../demo/shared/ui/NavigationRoutes.kt | 1 + .../demo/ui/showcases/ShowCaseList.kt | 42 +++++---- .../demo/ui/showcases/ShowCaseNavigation.kt | 4 + .../updatable/UpdatableMediaItemView.kt | 35 ++++++++ .../updatable/UpdatableMediaItemViewModel.kt | 86 +++++++++++++++++++ .../src/main/res/values/strings.xml | 7 +- .../player/source/PillarboxMediaSource.kt | 17 ++++ 8 files changed, 171 insertions(+), 25 deletions(-) create mode 100644 pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/updatable/UpdatableMediaItemView.kt create mode 100644 pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/updatable/UpdatableMediaItemViewModel.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fa1b83288..1247634a3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,8 +17,8 @@ mockk = "1.12.5" junit = "4.13.2" androidJunit = "1.1.5" espresso = "3.5.1" -media3 = "1.1.1" -media = "1.6.0" +media3 = "1.2.0" +media = "1.7.0" guava = "31.1-android" navigation = "2.7.4" paging = "3.2.1" diff --git a/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/NavigationRoutes.kt b/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/NavigationRoutes.kt index b26d34fd2..0f651382e 100644 --- a/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/NavigationRoutes.kt +++ b/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/NavigationRoutes.kt @@ -19,6 +19,7 @@ object NavigationRoutes { const val playerSwap = "player_swap" const val exoPlayerSample = "exoplayer_sample" const val trackingSample = "tracking_sample" + const val updatableSample = "updatable_sample" const val homeLists = "home_lists" const val contentLists = "content_lists" diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/ShowCaseList.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/ShowCaseList.kt index 377cf5050..b66c7655e 100644 --- a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/ShowCaseList.kt +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/ShowCaseList.kt @@ -56,6 +56,7 @@ fun ShowCaseList(navController: NavController) { modifier = Modifier .verticalScroll(rememberScrollState()) .padding(horizontal = MaterialTheme.paddings.baseline) + .padding(bottom = MaterialTheme.paddings.baseline) ) { DemoListHeaderView( title = stringResource(R.string.layouts), @@ -98,11 +99,21 @@ fun ShowCaseList(navController: NavController) { } DemoListHeaderView( - title = stringResource(R.string.system_integration), + title = stringResource(R.string.integrations), modifier = titleModifier ) DemoListSectionView { + DemoListSectionView { + DemoListItemView( + title = stringResource(R.string.exoplayer_view), + modifier = itemModifier, + onClick = { navController.navigate(NavigationRoutes.exoPlayerSample) } + ) + } + + Divider() + DemoListItemView( title = stringResource(R.string.auto), modifier = itemModifier, @@ -114,7 +125,7 @@ fun ShowCaseList(navController: NavController) { } DemoListHeaderView( - title = stringResource(R.string.embeddings), + title = stringResource(R.string.misc), modifier = titleModifier ) @@ -132,31 +143,24 @@ fun ShowCaseList(navController: NavController) { modifier = itemModifier, onClick = { navController.navigate(NavigationRoutes.playerSwap) } ) - } - - DemoListHeaderView( - title = stringResource(R.string.exoplayer), - modifier = titleModifier - ) + Divider() - DemoListSectionView { DemoListItemView( - title = stringResource(R.string.exoplayer_view), + title = stringResource(R.string.tracker_example), modifier = itemModifier, - onClick = { navController.navigate(NavigationRoutes.exoPlayerSample) } + onClick = { navController.navigate(NavigationRoutes.trackingSample) } ) - } - DemoListHeaderView( - title = stringResource(R.string.tracking), - modifier = titleModifier - ) + Divider() - DemoListSectionView(modifier = Modifier.padding(bottom = MaterialTheme.paddings.baseline)) { DemoListItemView( - title = stringResource(R.string.tracker_example), + title = stringResource(R.string.update_media_item_example), modifier = itemModifier, - onClick = { navController.navigate(NavigationRoutes.trackingSample) } + onClick = { + navController.navigate( + NavigationRoutes.updatableSample + ) + } ) } } diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/ShowCaseNavigation.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/ShowCaseNavigation.kt index 84342a7ed..88554685f 100644 --- a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/ShowCaseNavigation.kt +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/ShowCaseNavigation.kt @@ -13,6 +13,7 @@ import ch.srgssr.pillarbox.demo.ui.showcases.adaptive.AdaptivePlayerHome import ch.srgssr.pillarbox.demo.ui.showcases.multiplayer.MultiPlayer import ch.srgssr.pillarbox.demo.ui.showcases.story.StoryHome import ch.srgssr.pillarbox.demo.ui.showcases.tracking.TrackingToggleSample +import ch.srgssr.pillarbox.demo.ui.showcases.updatable.UpdatableMediaItemView /** * Inject Showcases Navigation @@ -39,6 +40,9 @@ fun NavGraphBuilder.showCasesNavGraph(navController: NavController) { composable(NavigationRoutes.trackingSample, DemoPageView("tracking toggle", Levels)) { TrackingToggleSample() } + composable(NavigationRoutes.updatableSample, DemoPageView("updatable item", Levels)) { + UpdatableMediaItemView() + } } private val Levels = listOf("app", "pillarbox", "showcase") diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/updatable/UpdatableMediaItemView.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/updatable/UpdatableMediaItemView.kt new file mode 100644 index 000000000..47beeae41 --- /dev/null +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/updatable/UpdatableMediaItemView.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023. SRG SSR. All rights reserved. + * License information is available from the LICENSE file. + */ +package ch.srgssr.pillarbox.demo.ui.showcases.updatable + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.lifecycle.viewmodel.compose.viewModel +import ch.srgssr.pillarbox.ui.extension.currentMediaMetadataAsState +import ch.srgssr.pillarbox.ui.widget.player.PlayerSurface + +/** + * Updatable media item view + */ +@Composable +fun UpdatableMediaItemView() { + val updatableMediaItemViewModel: UpdatableMediaItemViewModel = viewModel() + val player = updatableMediaItemViewModel.player + val currentItem by player.currentMediaMetadataAsState() + PlayerSurface(player = player) { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopStart) { + Text( + color = Color.Green, + text = "${currentItem.title}" + ) + } + } +} diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/updatable/UpdatableMediaItemViewModel.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/updatable/UpdatableMediaItemViewModel.kt new file mode 100644 index 000000000..70f061c64 --- /dev/null +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/updatable/UpdatableMediaItemViewModel.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) SRG SSR. All rights reserved. + * License information is available from the LICENSE file. + */ +package ch.srgssr.pillarbox.demo.ui.showcases.updatable + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import androidx.media3.common.MediaItem +import androidx.media3.ui.PlayerNotificationManager +import ch.srgssr.pillarbox.demo.shared.data.DemoItem +import ch.srgssr.pillarbox.demo.shared.di.PlayerModule +import ch.srgssr.pillarbox.player.notification.PillarboxMediaDescriptionAdapter +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.util.Timer +import kotlin.concurrent.timer +import kotlin.time.Duration.Companion.seconds + +/** + * Updatable media item view model + * + * This demo demonstrate how to update an existing [MediaItem.mediaMetadata]. + * + * @constructor + * + * @param application The application + */ +class UpdatableMediaItemViewModel(application: Application) : AndroidViewModel(application) { + /** + * The player + */ + val player = PlayerModule.provideDefaultPlayer(application) + private val notificationManager: PlayerNotificationManager + private val timer: Timer + private val baseTitle = "Update title" + private var counter = 0 + + init { + player.prepare() + player.setMediaItem(DemoItem.OnDemandHorizontalVideo.toMediaItem()) + player.play() + notificationManager = PlayerNotificationManager.Builder(application, NOTIFICATION_ID, CHANNEL_ID) + .setChannelNameResourceId(androidx.media3.session.R.string.default_notification_channel_name) + .setMediaDescriptionAdapter(PillarboxMediaDescriptionAdapter(context = application, pendingIntent = null)) + .build() + notificationManager.setPlayer(player) + + timer = timer(name = "update-item", period = 3.seconds.inWholeMilliseconds) { + viewModelScope.launch(Dispatchers.Main) { + val currentMediaItem = player.currentMediaItem + currentMediaItem?.let { + // when localConfiguration is not null, it means the urn has loaded a playable media url. + if (it.localConfiguration != null) { + updateTitle(it, "$baseTitle - $counter") + counter++ + } + } + } + } + } + + private fun updateTitle(mediaItem: MediaItem, title: String) { + val updatedMediaItem = mediaItem.buildUpon() + .setMediaMetadata( + mediaItem.mediaMetadata.buildUpon() + .setTitle(title) + .build() + ) + .build() + player.replaceMediaItem(player.currentMediaItemIndex, updatedMediaItem) + } + + override fun onCleared() { + super.onCleared() + timer.cancel() + notificationManager.setPlayer(null) + player.release() + } + + companion object { + private const val CHANNEL_ID = "DemoChannel" + private const val NOTIFICATION_ID = 456 + } +} diff --git a/pillarbox-demo/src/main/res/values/strings.xml b/pillarbox-demo/src/main/res/values/strings.xml index 50a64b1b2..3e8af611e 100644 --- a/pillarbox-demo/src/main/res/values/strings.xml +++ b/pillarbox-demo/src/main/res/values/strings.xml @@ -11,10 +11,8 @@ MediaController (Android Auto) Resizable player Multi player - Embeddings - System integration - Exoplayer integration - Tracking + Misc + Integrations Tracking toggle sample Exoplayer View Enter a URL or URN @@ -25,4 +23,5 @@ Production Stage Test + Updatable media metadata diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/source/PillarboxMediaSource.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/source/PillarboxMediaSource.kt index 94c2d0e4a..c82017cc0 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/source/PillarboxMediaSource.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/source/PillarboxMediaSource.kt @@ -54,6 +54,23 @@ class PillarboxMediaSource( } } + /** + * Can update media item + * + * FIXME Test when using MediaController. + * + * @param mediaItem + * @return + */ + override fun canUpdateMediaItem(mediaItem: MediaItem): Boolean { + if (mediaItem.mediaId != this.mediaItem.mediaId || mediaItem.localConfiguration != this.mediaItem.localConfiguration) return false + return true + } + + override fun updateMediaItem(mediaItem: MediaItem) { + this.mediaItem = mediaItem + } + @Suppress("TooGenericExceptionCaught") override fun maybeThrowSourceInfoRefreshError() { pendingError?.let {