diff --git a/android/app/src/main/kotlin/com/novasonic/app/MusicService.kt b/android/app/src/main/kotlin/com/novasonic/app/MusicService.kt index 11b4b26..34ae55e 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/MusicService.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/MusicService.kt @@ -102,6 +102,8 @@ class MusicService : MediaSessionService() { // ExoPlayer drops those commands when its queue has only one item (single-track model), // which makes Media3 hide the skip buttons in the notification. JS still owns queue // logic — the MediaSession callback intercepts the commands and delegates to JS. + // seekToNext* are no-oped here so ExoPlayer never tries to advance its single-item + // queue; JS handles all actual navigation via stateListener callbacks. val sessionPlayer = object : ForwardingPlayer(player) { override fun getAvailableCommands(): Player.Commands = super.getAvailableCommands().buildUpon() @@ -118,6 +120,11 @@ class MusicService : MediaSessionService() { Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM -> true else -> super.isCommandAvailable(command) } + + override fun seekToNext() {} + override fun seekToNextMediaItem() {} + override fun seekToPrevious() {} + override fun seekToPreviousMediaItem() {} } // Tapping the notification opens the app directly to the Now Playing screen. @@ -145,12 +152,14 @@ class MusicService : MediaSessionService() { Player.COMMAND_SEEK_TO_NEXT, Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM -> { stateListener?.onSkipToNext() - androidx.media3.session.SessionResult.RESULT_ERROR_NOT_SUPPORTED + // Return SUCCESS so Media3 keeps the button enabled in the notification. + // The ForwardingPlayer no-ops seekToNext so ExoPlayer does nothing. + androidx.media3.session.SessionResult.RESULT_SUCCESS } Player.COMMAND_SEEK_TO_PREVIOUS, Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM -> { stateListener?.onSkipToPrevious() - androidx.media3.session.SessionResult.RESULT_ERROR_NOT_SUPPORTED + androidx.media3.session.SessionResult.RESULT_SUCCESS } else -> androidx.media3.session.SessionResult.RESULT_SUCCESS }