diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/PlaybackSession.kt b/android/app/src/main/java/com/audiobookshelf/app/data/PlaybackSession.kt index e2903bd9..c0765f12 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/PlaybackSession.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/PlaybackSession.kt @@ -1,6 +1,11 @@ package com.audiobookshelf.app.data +import android.content.Context +import android.graphics.Bitmap +import android.graphics.ImageDecoder import android.net.Uri +import android.os.Build +import android.provider.MediaStore import android.support.v4.media.MediaMetadataCompat import com.audiobookshelf.app.device.DeviceManager import com.audiobookshelf.app.player.MediaProgressSyncData @@ -118,7 +123,7 @@ class PlaybackSession( } @JsonIgnore - fun getMediaMetadataCompat(): MediaMetadataCompat { + fun getMediaMetadataCompat(ctx: Context): MediaMetadataCompat { val metadataBuilder = MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_TITLE, displayTitle) .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, displayTitle) @@ -130,6 +135,20 @@ class PlaybackSession( .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION, displayAuthor) .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, id) .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getCoverUri().toString()) + .putString(MediaMetadataCompat.METADATA_KEY_ART_URI, getCoverUri().toString()) + + // Local covers get bitmap + if (localLibraryItem?.coverContentUrl != null) { + val bitmap = if (Build.VERSION.SDK_INT < 28) { + MediaStore.Images.Media.getBitmap(ctx.contentResolver, getCoverUri()) + } else { + val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, getCoverUri()) + ImageDecoder.decodeBitmap(source) + } + metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap) + metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmap) + } + return metadataBuilder.build() } @@ -143,6 +162,7 @@ class PlaybackSession( .setSubtitle(displayAuthor) .setAlbumTitle(displayAuthor) .setDescription(displayAuthor) + .setArtworkUri(getCoverUri()) val contentUri = this.getContentUri(audioTrack) metadataBuilder.setMediaUri(contentUri) diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/AbMediaDescriptionAdapter.kt b/android/app/src/main/java/com/audiobookshelf/app/player/AbMediaDescriptionAdapter.kt index 2b31e6ba..e981cc51 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/AbMediaDescriptionAdapter.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/AbMediaDescriptionAdapter.kt @@ -2,7 +2,10 @@ package com.audiobookshelf.app.player import android.app.PendingIntent import android.graphics.Bitmap +import android.graphics.ImageDecoder import android.net.Uri +import android.os.Build +import android.provider.MediaStore import android.support.v4.media.session.MediaControllerCompat import android.util.Log import com.audiobookshelf.app.R @@ -42,13 +45,25 @@ class AbMediaDescriptionAdapter constructor(private val controller: MediaControl // `getCurrentLargeIcon` don't cause the bitmap to be recreated. currentIconUri = albumArtUri Log.d(tag, "ART $currentIconUri") - serviceScope.launch { - currentBitmap = albumArtUri?.let { - resolveUriAsBitmap(it) + + if (currentIconUri.toString().startsWith("content://")) { + currentBitmap = if (Build.VERSION.SDK_INT < 28) { + MediaStore.Images.Media.getBitmap(playerNotificationService.contentResolver, currentIconUri) + } else { + val source: ImageDecoder.Source = ImageDecoder.createSource(playerNotificationService.contentResolver, currentIconUri!!) + ImageDecoder.decodeBitmap(source) } - currentBitmap?.let { callback.onBitmap(it) } + currentBitmap + } else { + serviceScope.launch { + currentBitmap = albumArtUri?.let { + resolveUriAsBitmap(it) + } + currentBitmap?.let { callback.onBitmap(it) } + } + null } - null + } else { currentBitmap } 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 f5ac838c..63d3f826 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 @@ -13,6 +13,7 @@ import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest import android.os.* +import android.provider.MediaStore import android.support.v4.media.MediaBrowserCompat import android.support.v4.media.MediaDescriptionCompat import android.support.v4.media.MediaMetadataCompat @@ -274,6 +275,17 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { val coverUri = currentPlaybackSession!!.getCoverUri() + var bitmap:Bitmap? = null + // Local covers get bitmap + if (currentPlaybackSession!!.localLibraryItem?.coverContentUrl != null) { + bitmap = if (Build.VERSION.SDK_INT < 28) { + MediaStore.Images.Media.getBitmap(ctx.contentResolver, coverUri) + } else { + val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, coverUri) + ImageDecoder.decodeBitmap(source) + } + } + // Fix for local images crashing on Android 11 for specific devices // https://stackoverflow.com/questions/64186578/android-11-mediastyle-notification-crash/64232958#64232958 try { @@ -294,6 +306,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { .setTitle(currentPlaybackSession!!.displayTitle) .setIconUri(coverUri) + bitmap?.let { + mediaDescriptionBuilder.setIconBitmap(it) + } + return mediaDescriptionBuilder.build() } } @@ -356,7 +372,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { JumpBackwardCustomActionProvider(), JumpForwardCustomActionProvider(), ) - val metadata = playbackSession.getMediaMetadataCompat() + val metadata = playbackSession.getMediaMetadataCompat(ctx) mediaSession.setMetadata(metadata) val mediaItems = playbackSession.getMediaItems() val playbackRateToUse = playbackRate ?: initialPlaybackRate ?: 1f