From 453365fcd62db309a3dd75590c2ff224a01dc1ab Mon Sep 17 00:00:00 2001 From: Robbie Van Gorkom Date: Sat, 3 Sep 2022 18:16:12 -0700 Subject: [PATCH] Fix buttons for Android Auto (and probably wear too). --- .../audiobookshelf/app/data/DeviceClasses.kt | 2 +- .../app/player/MediaSessionCallback.kt | 2 + .../app/player/PlayerConstants.kt | 2 + .../app/player/PlayerNotificationService.kt | 70 +++++++++++++++---- .../main/res/drawable-anydpi/skip_next_24.xml | 15 ++++ .../res/drawable-anydpi/skip_previous_24.xml | 15 ++++ .../src/main/res/drawable/skip_next_24.xml | 10 +++ .../main/res/drawable/skip_previous_24.xml | 10 +++ android/app/src/main/res/values/strings.xml | 2 + 9 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 android/app/src/main/res/drawable-anydpi/skip_next_24.xml create mode 100644 android/app/src/main/res/drawable-anydpi/skip_previous_24.xml create mode 100644 android/app/src/main/res/drawable/skip_next_24.xml create mode 100644 android/app/src/main/res/drawable/skip_previous_24.xml diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt index b81c67da..00c05051 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DeviceClasses.kt @@ -39,7 +39,7 @@ data class DeviceSettings( @get:JsonIgnore val jumpBackwardsTimeMs get() = (jumpBackwardsTime ?: default().jumpBackwardsTime) * 1000L @get:JsonIgnore - val jumpForwardTimeMs get() = (jumpForwardTime ?: default().jumpBackwardsTime) * 1000L + val jumpForwardTimeMs get() = (jumpForwardTime ?: default().jumpForwardTime) * 1000L } data class DeviceData( diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt b/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt index 63460461..7fbdcadd 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt @@ -239,6 +239,8 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi when (action) { CUSTOM_ACTION_JUMP_FORWARD -> onFastForward() CUSTOM_ACTION_JUMP_BACKWARD -> onRewind() + CUSTOM_ACTION_SKIP_FORWARD -> onSkipToNext() + CUSTOM_ACTION_SKIP_BACKWARD -> onSkipToPrevious() } } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerConstants.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerConstants.kt index 407425f8..cbf9f76e 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerConstants.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerConstants.kt @@ -2,3 +2,5 @@ package com.audiobookshelf.app.player const val CUSTOM_ACTION_JUMP_FORWARD = "com.audiobookshelf.customAction.jump_forward"; const val CUSTOM_ACTION_JUMP_BACKWARD = "com.audiobookshelf.customAction.jump_backward"; +const val CUSTOM_ACTION_SKIP_FORWARD = "com.audiobookshelf.customAction.skip_forward"; +const val CUSTOM_ACTION_SKIP_BACKWARD = "com.audiobookshelf.customAction.skip_backward"; 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 92a0cdde..0f2c3e6e 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 @@ -45,6 +45,8 @@ import kotlin.concurrent.schedule const val SLEEP_TIMER_WAKE_UP_EXPIRATION = 120000L // 2m +const val PLAYER_CAST = "cast-player"; +const val PLAYER_EXO = "exo-player"; class PlayerNotificationService : MediaBrowserServiceCompat() { @@ -256,6 +258,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { mediaSessionConnector = MediaSessionConnector(mediaSession) val queueNavigator: TimelineQueueNavigator = object : TimelineQueueNavigator(mediaSession) { + override fun getSupportedQueueNavigatorActions(player: Player): Long { + return PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PAUSE + } + override fun getMediaDescription(player: Player, windowIndex: Int): MediaDescriptionCompat { if (currentPlaybackSession == null) { Log.e(tag,"Playback session is not set - returning blank MediaDescriptionCompat") @@ -296,11 +302,6 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { mediaSessionConnector.setQueueNavigator(queueNavigator) mediaSessionConnector.setPlaybackPreparer(MediaSessionPlaybackPreparer(this)) - mediaSessionConnector.setCustomActionProviders( - JumpForwardCustomActionProvider(), - JumpBackwardCustomActionProvider(), - ) - mediaSession.setCallback(MediaSessionCallback(this)) initializeMPlayer() @@ -343,19 +344,34 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } isClosed = false + val customActionProviders = mutableListOf( + JumpBackwardCustomActionProvider(), + JumpForwardCustomActionProvider(), + ) + val metadata = playbackSession.getMediaMetadataCompat() + mediaSession.setMetadata(metadata) + val mediaItems = playbackSession.getMediaItems() val playbackRateToUse = playbackRate ?: initialPlaybackRate ?: 1f initialPlaybackRate = playbackRate + if (playbackSession.mediaPlayer != PLAYER_CAST && mediaItems.size > 1) { + customActionProviders.addAll(listOf( + SkipBackwardCustomActionProvider(), + SkipForwardCustomActionProvider(), + )); + } + mediaSessionConnector.setCustomActionProviders(*customActionProviders.toTypedArray()); + playbackSession.mediaPlayer = getMediaPlayer() - if (playbackSession.mediaPlayer == "cast-player" && playbackSession.isLocal) { + if (playbackSession.mediaPlayer == PLAYER_CAST && playbackSession.isLocal) { Log.w(tag, "Cannot cast local media item - switching player") currentPlaybackSession = null switchToPlayer(false) playbackSession.mediaPlayer = getMediaPlayer() } - if (playbackSession.mediaPlayer == "cast-player") { + if (playbackSession.mediaPlayer == PLAYER_CAST) { // If cast-player is the first player to be used mediaSessionConnector.setPlayer(castPlayer) playerNotificationManager.setPlayer(castPlayer) @@ -366,10 +382,6 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { clientEventEmitter?.onPlaybackSession(playbackSession) - val metadata = playbackSession.getMediaMetadataCompat() - mediaSession.setMetadata(metadata) - val mediaItems = playbackSession.getMediaItems() - if (mediaItems.isEmpty()) { Log.e(tag, "Invalid playback session no media items to play") currentPlaybackSession = null @@ -751,7 +763,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } fun getMediaPlayer():String { - return if(currentPlayer == castPlayer) "cast-player" else "exo-player" + return if(currentPlayer == castPlayer) PLAYER_CAST else PLAYER_EXO } fun getDeviceInfo(): DeviceInfo { @@ -1011,5 +1023,39 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { ).build() } } + + inner class SkipForwardCustomActionProvider : CustomActionProvider { + override fun onCustomAction(player: Player, action: String, extras: Bundle?) { + /* + This does not appear to ever get called. Instead, MediaSessionCallback.onCustomAction() is + responsible to reacting to a custom action. + */ + } + + override fun getCustomAction(player: Player): PlaybackStateCompat.CustomAction? { + return PlaybackStateCompat.CustomAction.Builder( + CUSTOM_ACTION_SKIP_FORWARD, + getContext().getString(R.string.action_skip_forward), + R.drawable.skip_next_24 + ).build() + } + } + + inner class SkipBackwardCustomActionProvider : CustomActionProvider { + override fun onCustomAction(player: Player, action: String, extras: Bundle?) { + /* + This does not appear to ever get called. Instead, MediaSessionCallback.onCustomAction() is + responsible to reacting to a custom action. + */ + } + + override fun getCustomAction(player: Player): PlaybackStateCompat.CustomAction? { + return PlaybackStateCompat.CustomAction.Builder( + CUSTOM_ACTION_SKIP_BACKWARD, + getContext().getString(R.string.action_skip_backward), + R.drawable.skip_previous_24 + ).build() + } + } } diff --git a/android/app/src/main/res/drawable-anydpi/skip_next_24.xml b/android/app/src/main/res/drawable-anydpi/skip_next_24.xml new file mode 100644 index 00000000..8c8a7482 --- /dev/null +++ b/android/app/src/main/res/drawable-anydpi/skip_next_24.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/android/app/src/main/res/drawable-anydpi/skip_previous_24.xml b/android/app/src/main/res/drawable-anydpi/skip_previous_24.xml new file mode 100644 index 00000000..ee35a179 --- /dev/null +++ b/android/app/src/main/res/drawable-anydpi/skip_previous_24.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/android/app/src/main/res/drawable/skip_next_24.xml b/android/app/src/main/res/drawable/skip_next_24.xml new file mode 100644 index 00000000..d84d1d37 --- /dev/null +++ b/android/app/src/main/res/drawable/skip_next_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/app/src/main/res/drawable/skip_previous_24.xml b/android/app/src/main/res/drawable/skip_previous_24.xml new file mode 100644 index 00000000..3149ba4f --- /dev/null +++ b/android/app/src/main/res/drawable/skip_previous_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index dee17c07..c47bb9d8 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -8,4 +8,6 @@ Simple widget for audiobookshelf playback Jump Forward Jump Backward + Skip Forward + Skip Backward