[Android] Add notifications for MediaBrowser clients on medialibrary updates
Robert Stone
git at videolan.org
Mon Dec 20 07:38:11 UTC 2021
vlc-android | branch: master | Robert Stone <rhstone at gmail.com> | Sun Dec 12 22:32:41 2021 -0800| [5e76ec34b1d7ef901d0b9c3479ae8fab406ac0b1] | committer: Nicolas Pomepuy
Add notifications for MediaBrowser clients on medialibrary updates
> https://code.videolan.org/videolan/vlc-android/commit/5e76ec34b1d7ef901d0b9c3479ae8fab406ac0b1
---
.../src/org/videolan/vlc/MediaBrowserCallback.kt | 150 +++++++++++++++++++++
.../src/org/videolan/vlc/PlaybackService.kt | 12 ++
.../org/videolan/vlc/media/MediaSessionBrowser.kt | 2 +-
3 files changed, 163 insertions(+), 1 deletion(-)
diff --git a/application/vlc-android/src/org/videolan/vlc/MediaBrowserCallback.kt b/application/vlc-android/src/org/videolan/vlc/MediaBrowserCallback.kt
new file mode 100644
index 000000000..44992b3e7
--- /dev/null
+++ b/application/vlc-android/src/org/videolan/vlc/MediaBrowserCallback.kt
@@ -0,0 +1,150 @@
+/*
+ *****************************************************************************
+ * MediaBrowserCallback.kt
+ *****************************************************************************
+ * Copyright © 2021 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+package org.videolan.vlc
+
+import androidx.lifecycle.lifecycleScope
+import kotlinx.coroutines.channels.SendChannel
+import org.videolan.medialibrary.interfaces.Medialibrary
+import org.videolan.tools.conflatedActor
+import org.videolan.tools.safeOffer
+
+/**
+ * @see org.videolan.vlc.viewmodels.ICallBackHandler
+ */
+interface IMediaBrowserCallback {
+ fun registerHistoryCallback(function: () -> Unit)
+ fun registerMediaCallback(function: () -> Unit)
+ fun removeCallbacks()
+}
+
+/**
+ *@see org.videolan.vlc.viewmodels.CallBackDelegate
+ */
+class MediaBrowserCallback(private val playbackService: PlaybackService) : IMediaBrowserCallback,
+ Medialibrary.MediaCb,
+ Medialibrary.ArtistsCb,
+ Medialibrary.AlbumsCb,
+ Medialibrary.GenresCb,
+ Medialibrary.PlaylistsCb,
+ Medialibrary.HistoryCb {
+
+ private val medialibrary = Medialibrary.getInstance()
+ private lateinit var historyActor: SendChannel<Unit>
+ private lateinit var refreshActor: SendChannel<Unit>
+
+ override fun registerHistoryCallback(refresh: () -> Unit) {
+ historyActor = playbackService.lifecycleScope.conflatedActor { refresh() }
+ medialibrary.addHistoryCb(this)
+ }
+
+ override fun onHistoryModified() {
+ historyActor.safeOffer(Unit)
+ }
+
+ override fun registerMediaCallback(refresh: () -> Unit) {
+ refreshActor = playbackService.lifecycleScope.conflatedActor { refresh() }
+ medialibrary.addMediaCb(this)
+ medialibrary.addArtistsCb(this)
+ medialibrary.addAlbumsCb(this)
+ medialibrary.addGenreCb(this)
+ medialibrary.addPlaylistCb(this)
+ }
+
+ override fun onMediaAdded() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onMediaDeleted(id: LongArray?) {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onMediaModified() {
+ /* Intentionally Ignored */
+ }
+
+ override fun onMediaConvertedToExternal(id: LongArray?) {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onArtistsAdded() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onArtistsModified() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onArtistsDeleted() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onAlbumsAdded() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onAlbumsModified() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onAlbumsDeleted() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onGenresAdded() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onGenresModified() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onGenresDeleted() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onPlaylistsAdded() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onPlaylistsModified() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun onPlaylistsDeleted() {
+ refreshActor.safeOffer(Unit)
+ }
+
+ override fun removeCallbacks() {
+ if (::refreshActor.isInitialized) {
+ medialibrary.removeMediaCb(this)
+ medialibrary.removeArtistsCb(this)
+ medialibrary.removeAlbumsCb(this)
+ medialibrary.removeGenreCb(this)
+ medialibrary.removePlaylistCb(this)
+ refreshActor.close()
+ }
+ if (::historyActor.isInitialized) {
+ medialibrary.removeHistoryCb(this)
+ historyActor.close()
+ }
+ }
+}
\ No newline at end of file
diff --git a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
index f2b7def4d..0dc5f8ed6 100644
--- a/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
+++ b/application/vlc-android/src/org/videolan/vlc/PlaybackService.kt
@@ -109,6 +109,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner {
private var detectHeadset = true
private lateinit var wakeLock: PowerManager.WakeLock
private val audioFocusHelper by lazy { VLCAudioFocusHelper(this) }
+ private lateinit var browserCallback: MediaBrowserCallback
// Playback management
internal lateinit var mediaSession: MediaSessionCompat
@@ -119,6 +120,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner {
private var lastLength = 0L
private var lastChapter = 0
private var lastChaptersCount = 0
+ private var lastParentId = ""
private var widget = 0
/**
* Last widget position update timestamp
@@ -551,6 +553,14 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner {
medialibrary = Medialibrary.getInstance()
artworkMap = HashMap<String,Uri>()
+ browserCallback = MediaBrowserCallback(this)
+ browserCallback.registerMediaCallback { if (lastParentId.isNotEmpty()) notifyChildrenChanged(lastParentId) }
+ browserCallback.registerHistoryCallback {
+ when (lastParentId) {
+ MediaSessionBrowser.ID_HOME, MediaSessionBrowser.ID_HISTORY -> notifyChildrenChanged(lastParentId)
+ }
+ }
+
detectHeadset = settings.getBoolean("enable_headset_detection", true)
// Make sure the audio player will acquire a wake-lock while playing. If we don't do
@@ -651,6 +661,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner {
dispatcher.onServicePreSuperOnDestroy()
super.onDestroy()
handler.removeCallbacksAndMessages(null)
+ browserCallback.removeCallbacks()
if (this::mediaSession.isInitialized) mediaSession.release()
//Call it once mediaSession is null, to not publish playback state
stop(systemExit = true)
@@ -1611,6 +1622,7 @@ class PlaybackService : MediaBrowserServiceCompat(), LifecycleOwner {
override fun onLoadChildren(parentId: String, result: Result<List<MediaBrowserCompat.MediaItem>>) {
result.detach()
+ lastParentId = parentId
lifecycleScope.launch(start = CoroutineStart.UNDISPATCHED) {
awaitMedialibraryStarted()
lifecycleScope.launch(Dispatchers.IO) {
diff --git a/application/vlc-android/src/org/videolan/vlc/media/MediaSessionBrowser.kt b/application/vlc-android/src/org/videolan/vlc/media/MediaSessionBrowser.kt
index c2a098a48..f22f82c6d 100644
--- a/application/vlc-android/src/org/videolan/vlc/media/MediaSessionBrowser.kt
+++ b/application/vlc-android/src/org/videolan/vlc/media/MediaSessionBrowser.kt
@@ -160,7 +160,7 @@ class MediaSessionBrowser : ExtensionManagerActivity {
const val ID_NO_PLAYLIST = "$ID_ROOT/error/playlist"
// Top-level menu
- private const val ID_HOME = "$ID_ROOT/home"
+ const val ID_HOME = "$ID_ROOT/home"
const val ID_PLAYLIST = "$ID_ROOT/playlist"
private const val ID_LIBRARY = "$ID_ROOT/l"
const val ID_STREAM = "$ID_ROOT/stream"
More information about the Android
mailing list