diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index e37e7147..5e3af81e 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -1087,6 +1087,26 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { private val DOWNLOADS_ROOT = "__DOWNLOADS__" private val CONTINUE_ROOT = "__CONTINUE__" private lateinit var browseTree: BrowseTree + private val browseTreeInitListeners = mutableListOf<() -> Unit>() + + private fun waitForBrowseTree(cb: () -> Unit) + { + if (this::browseTree.isInitialized) + { + cb() + } + else + { + browseTreeInitListeners += cb + } + } + + private fun onBrowseTreeInitialized() + { + // Called after browseTree is assigned for the first time + browseTreeInitListeners.forEach { it.invoke() } + browseTreeInitListeners.clear() + } // Only allowing android auto or similar to access media browser service // normal loading of audiobooks is handled in webview (not natively) @@ -1257,6 +1277,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { mediaManager.serverLibraries, mediaManager.allLibraryPersonalizationsDone ) + onBrowseTreeInitialized() val children = browseTree[parentMediaId]?.map { item -> Log.d(tag, "Found top menu item: ${item.description.title}") @@ -1291,6 +1312,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { mediaManager.serverLibraries, mediaManager.allLibraryPersonalizationsDone ) + onBrowseTreeInitialized() val children = browseTree[parentMediaId]?.map { item -> Log.d(tag, "Found top menu item: ${item.description.title}") @@ -1303,22 +1325,40 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { AbsLogger.info(tag, "onLoadChildren: Android auto data loaded") result.sendResult(children as MutableList?) } - } else if (parentMediaId == LIBRARIES_ROOT || parentMediaId == RECENTLY_ROOT) { + } else if (parentMediaId == LIBRARIES_ROOT || parentMediaId == RECENTLY_ROOT) + { Log.d(tag, "First load done: $firstLoadDone") - if (!firstLoadDone) { + if (!firstLoadDone) + { result.sendResult(null) return } - // Wait until top-menu is initialized - while (!this::browseTree.isInitialized) {} - val children = - browseTree[parentMediaId]?.map { item -> - Log.d(tag, "[MENU: $parentMediaId] Showing list item ${item.description.title}") - MediaBrowserCompat.MediaItem( - item.description, - MediaBrowserCompat.MediaItem.FLAG_BROWSABLE - ) - } + + if (!this::browseTree.isInitialized) + { + // ✅ good: detach and wait for init + result.detach() + waitForBrowseTree { + val children = browseTree[parentMediaId]?.map { item -> + Log.d(tag, "[MENU: $parentMediaId] Showing list item ${item.description.title}") + MediaBrowserCompat.MediaItem( + item.description, + MediaBrowserCompat.MediaItem.FLAG_BROWSABLE + ) + } + result.sendResult(children as MutableList?) + } + return + } + + // Already initialized: just return + val children = browseTree[parentMediaId]?.map { item -> + Log.d(tag, "[MENU: $parentMediaId] Showing list item ${item.description.title}") + MediaBrowserCompat.MediaItem( + item.description, + MediaBrowserCompat.MediaItem.FLAG_BROWSABLE + ) + } result.sendResult(children as MutableList?) } else if (mediaManager.getIsLibrary(parentMediaId)) { // Load library items for library Log.d(tag, "Loading items for library $parentMediaId")