From 264fe69be73954b711eb55e10b5b3e1b57d6d2b1 Mon Sep 17 00:00:00 2001 From: Robert Stone Date: Wed, 7 Aug 2024 21:56:07 -0700 Subject: [PATCH] Cycle through subtitle messages under Android Auto --- .../resources/src/main/res/values/strings.xml | 5 ++++ .../org/videolan/vlc/MediaSessionCallback.kt | 9 ++++-- .../src/org/videolan/vlc/PlaybackService.kt | 30 +++++++++++++++---- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/application/resources/src/main/res/values/strings.xml b/application/resources/src/main/res/values/strings.xml index 0f652fdae..30d835665 100644 --- a/application/resources/src/main/res/values/strings.xml +++ b/application/resources/src/main/res/values/strings.xml @@ -85,6 +85,11 @@ Albums Tracks + + 1 Saved Bookmark + %d Saved Bookmarks + + 1 album %d albums diff --git a/application/vlc-android/src/org/videolan/vlc/MediaSessionCallback.kt b/application/vlc-android/src/org/videolan/vlc/MediaSessionCallback.kt index c18c8e082..2e82ef82b 100644 --- a/application/vlc-android/src/org/videolan/vlc/MediaSessionCallback.kt +++ b/application/vlc-android/src/org/videolan/vlc/MediaSessionCallback.kt @@ -181,7 +181,8 @@ internal class MediaSessionCallback(private val playbackService: PlaybackService val bookmark = it.addBookmark(playbackService.getTime()) val bookmarkName = context.getString(R.string.bookmark_default_name, Tools.millisToString(playbackService.getTime())) bookmark?.setName(bookmarkName) - playbackService.displayPlaybackMessage(R.string.saved, bookmarkName) + playbackService.displaySubtitleMessage(context.getString(R.string.saved, bookmarkName), + context.resources.getQuantityString(R.plurals.saved_bookmarks_quantity, it.bookmarks.size, it.bookmarks.size)) } } } @@ -306,8 +307,10 @@ internal class MediaSessionCallback(private val playbackService: PlaybackService } private fun checkForSeekFailure(forward: Boolean) { - if (playbackService.playlistManager.player.lastPosition == 0.0f && (forward || playbackService.getTime() > 0)) - playbackService.displayPlaybackMessage(R.string.unseekable_stream) + if (playbackService.playlistManager.player.lastPosition == 0.0f && (forward || playbackService.getTime() > 0)) { + val context = playbackService.applicationContext + playbackService.displaySubtitleMessage(context.getString(R.string.unseekable_stream)) + } } override fun onPlayFromUri(uri: Uri?, extras: Bundle?) = playbackService.loadUri(uri) diff --git a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt index f23027c3e..6dc34dcce 100644 --- a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt +++ b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt @@ -211,7 +211,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc private lateinit var artworkMap: MutableMap private val callbacks = mutableListOf() - private val subtitleMessage = ArrayDeque(1) + private val subtitleMessage = ArrayDeque>(1) private lateinit var cbActor: SendChannel var detectHeadset = true var headsetInserted = false @@ -1136,7 +1136,8 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc val length = length lastLength = length val chapterTitle = if (lastChaptersCount > 0) getCurrentChapter() else null - val displayMsg = subtitleMessage.poll() + val displayMsg = getSubtitleMessage() + displayMsg?.let { scheduler.scheduleAction(UPDATE_META, 5_000L) } val bob = withContext(Dispatchers.Default) { val carMode = isCarMode() val title = media.nowPlaying ?: media.title @@ -1322,6 +1323,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc } fun notifyTrackChanged() { + subtitleMessage.clear() updateMetadata() updateWidget() broadcastMetadata() @@ -1557,12 +1559,28 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc mediaSession.setPlaybackState(playbackState) } - fun displayPlaybackMessage(@StringRes resId: Int, vararg formatArgs: String) { - val ctx = this@PlaybackService - subtitleMessage.push(ctx.getString(resId, *formatArgs)) + fun displaySubtitleMessage(vararg messages: String) { + var endTime = System.currentTimeMillis() + subtitleMessage.clear() + messages.forEach { msg -> + endTime += 5000L + msg?.let { subtitleMessage.addLast(Pair(it, endTime)) } + } updateMetadata() } + private fun getSubtitleMessage(): String? { + return subtitleMessage.peek()?.let { + when { + System.currentTimeMillis() > it.second -> { + subtitleMessage.poll() + subtitleMessage.peek()?.first + } + else -> it.first + } + } + } + @MainThread fun load(media: MediaWrapper, position: Int = 0) = load(listOf(media), position) @@ -1824,6 +1842,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc currentToast = Toast.makeText(applicationContext, text, duration) currentToast?.show() } + UPDATE_META -> updateMetadata() END_MEDIASESSION -> if (::mediaSession.isInitialized) mediaSession.isActive = false } } @@ -1946,6 +1965,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner, CoroutineSc private const val SHOW_TOAST = "show_toast" private const val END_MEDIASESSION = "end_mediasession" + private const val UPDATE_META = "update_meta" val playerSleepTime by lazy(LazyThreadSafetyMode.NONE) { MutableLiveData().apply { value = null } }