diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a920a5b0..4aca42b6 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -92,6 +92,16 @@ + + + + diff --git a/android/app/src/main/java/com/audiobookshelf/app/MediaPlayerWidget.kt b/android/app/src/main/java/com/audiobookshelf/app/MediaPlayerWidget.kt index dbd98c75..79477aa1 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/MediaPlayerWidget.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/MediaPlayerWidget.kt @@ -77,7 +77,7 @@ internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManage views.setOnClickPendingIntent(R.id.widgetBackground, wholeWidgetClickPI) - val imageUri = playbackSession?.getCoverUri() ?: Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon) + val imageUri = playbackSession?.getCoverUri(context) ?: Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon) val awt: AppWidgetTarget = object : AppWidgetTarget(context.applicationContext, R.id.widgetAlbumArt, views, appWidgetId) { override fun onResourceReady(resource: Bitmap, transition: Transition?) { super.onResourceReady(resource, transition) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt index bbddbf77..f0ed55b4 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt @@ -258,9 +258,9 @@ data class PodcastEpisode( var localEpisodeId:String? // For Android Auto server episodes with local copy ) { @JsonIgnore - fun getMediaDescription(libraryItem:LibraryItemWrapper, progress:MediaProgressWrapper?, ctx: Context?): MediaDescriptionCompat { + fun getMediaDescription(libraryItem:LibraryItemWrapper, progress:MediaProgressWrapper?, ctx: Context): MediaDescriptionCompat { val coverUri = if (libraryItem is LocalLibraryItem) { - libraryItem.getCoverUri() + libraryItem.getCoverUri(ctx) } else { (libraryItem as LibraryItem).getCoverUri() } 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 ffd70c03..b509c65d 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 @@ -83,7 +83,7 @@ data class LocalFolder( ) open class LibraryItemWrapper(var id:String) { @JsonIgnore - open fun getMediaDescription(progress:MediaProgressWrapper?, ctx: Context?): MediaDescriptionCompat { return MediaDescriptionCompat.Builder().build() } + open fun getMediaDescription(progress:MediaProgressWrapper?, ctx: Context): MediaDescriptionCompat { return MediaDescriptionCompat.Builder().build() } } @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/LibraryItem.kt b/android/app/src/main/java/com/audiobookshelf/app/data/LibraryItem.kt index cc44cc17..9411b62b 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/LibraryItem.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/LibraryItem.kt @@ -58,7 +58,7 @@ class LibraryItem( } @JsonIgnore - override fun getMediaDescription(progress:MediaProgressWrapper?, ctx: Context?): MediaDescriptionCompat { + override fun getMediaDescription(progress:MediaProgressWrapper?, ctx: Context): MediaDescriptionCompat { val extras = Bundle() if (localLibraryItemId != null) { diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/LocalLibraryItem.kt b/android/app/src/main/java/com/audiobookshelf/app/data/LocalLibraryItem.kt index f52d45df..d290b4fd 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/LocalLibraryItem.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/LocalLibraryItem.kt @@ -9,6 +9,8 @@ import android.os.Bundle import android.provider.MediaStore import android.support.v4.media.MediaDescriptionCompat import android.util.Log +import androidx.core.content.FileProvider +import androidx.core.net.toFile import androidx.media.utils.MediaConstants import com.audiobookshelf.app.BuildConfig import com.audiobookshelf.app.R @@ -46,7 +48,10 @@ class LocalLibraryItem( val isPodcast get() = mediaType == "podcast" @JsonIgnore - fun getCoverUri(): Uri { + fun getCoverUri(ctx:Context): Uri { + if (coverContentUrl?.startsWith("file:") == true) { + return FileProvider.getUriForFile(ctx, "com.audiobookshelf.app.fileprovider", Uri.parse(coverContentUrl).toFile()) + } return if (coverContentUrl != null) Uri.parse(coverContentUrl) else Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon) } @@ -107,18 +112,16 @@ class LocalLibraryItem( } @JsonIgnore - override fun getMediaDescription(progress:MediaProgressWrapper?, ctx:Context?): MediaDescriptionCompat { - val coverUri = getCoverUri() + override fun getMediaDescription(progress:MediaProgressWrapper?, ctx:Context): MediaDescriptionCompat { + val coverUri = getCoverUri(ctx) var bitmap:Bitmap? = null if (coverContentUrl != null) { - ctx?.let { - bitmap = if (Build.VERSION.SDK_INT < 28) { - MediaStore.Images.Media.getBitmap(it.contentResolver, coverUri) - } else { - val source: ImageDecoder.Source = ImageDecoder.createSource(it.contentResolver, coverUri) - ImageDecoder.decodeBitmap(source) - } + 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) } } 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 06a1c923..2a5d4d74 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 @@ -6,6 +6,8 @@ import android.net.Uri import android.os.Build import android.provider.MediaStore import android.support.v4.media.MediaMetadataCompat +import androidx.core.content.FileProvider +import androidx.core.net.toFile import com.audiobookshelf.app.BuildConfig import com.audiobookshelf.app.R import com.audiobookshelf.app.device.DeviceManager @@ -138,8 +140,15 @@ class PlaybackSession( } @JsonIgnore - fun getCoverUri(): Uri { - if (localLibraryItem?.coverContentUrl != null) return Uri.parse(localLibraryItem?.coverContentUrl) ?: Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon) + fun getCoverUri(ctx:Context): Uri { + if (localLibraryItem?.coverContentUrl != null) { + var coverUri = Uri.parse(localLibraryItem?.coverContentUrl.toString()) + if (coverUri.toString().startsWith("file:")) { + coverUri = FileProvider.getUriForFile(ctx, "com.audiobookshelf.app.fileprovider", coverUri.toFile()) + } + + return coverUri ?: Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon) + } if (coverPath == null) return Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon) return Uri.parse("$serverAddress/api/items/$libraryItemId/cover?token=${DeviceManager.token}") @@ -153,6 +162,8 @@ class PlaybackSession( @JsonIgnore fun getMediaMetadataCompat(ctx: Context): MediaMetadataCompat { + val coverUri = getCoverUri(ctx) + val metadataBuilder = MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_TITLE, displayTitle) .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, displayTitle) @@ -163,16 +174,16 @@ class PlaybackSession( .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, displayAuthor) .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()) - .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, getCoverUri().toString()) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, coverUri.toString()) + .putString(MediaMetadataCompat.METADATA_KEY_ART_URI, coverUri.toString()) + .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, coverUri.toString()) // Local covers get bitmap if (localLibraryItem?.coverContentUrl != null) { val bitmap = if (Build.VERSION.SDK_INT < 28) { - MediaStore.Images.Media.getBitmap(ctx.contentResolver, getCoverUri()) + MediaStore.Images.Media.getBitmap(ctx.contentResolver, coverUri) } else { - val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, getCoverUri()) + val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, coverUri) ImageDecoder.decodeBitmap(source) } metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap) @@ -183,7 +194,9 @@ class PlaybackSession( } @JsonIgnore - fun getExoMediaMetadata(): MediaMetadata { + fun getExoMediaMetadata(ctx:Context): MediaMetadata { + val coverUri = getCoverUri(ctx) + val metadataBuilder = MediaMetadata.Builder() .setTitle(displayTitle) .setDisplayTitle(displayTitle) @@ -192,18 +205,18 @@ class PlaybackSession( .setSubtitle(displayAuthor) .setAlbumTitle(displayAuthor) .setDescription(displayAuthor) - .setArtworkUri(getCoverUri()) + .setArtworkUri(coverUri) .setMediaType(MediaMetadata.MEDIA_TYPE_AUDIO_BOOK) return metadataBuilder.build() } @JsonIgnore - fun getMediaItems():List { + fun getMediaItems(ctx:Context):List { val mediaItems:MutableList = mutableListOf() for (audioTrack in audioTracks) { - val mediaMetadata = this.getExoMediaMetadata() + val mediaMetadata = this.getExoMediaMetadata(ctx) val mediaUri = this.getContentUri(audioTrack) val mimeType = audioTrack.mimeType 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 cabf36dd..3885c5f7 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 @@ -9,10 +9,7 @@ import android.graphics.Color import android.graphics.ImageDecoder import android.hardware.Sensor import android.hardware.SensorManager -import android.net.ConnectivityManager -import android.net.Network -import android.net.NetworkCapabilities -import android.net.NetworkRequest +import android.net.* import android.os.* import android.provider.MediaStore import android.provider.Settings @@ -292,7 +289,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { return MediaDescriptionCompat.Builder().build() } - val coverUri = currentPlaybackSession!!.getCoverUri() + val coverUri = currentPlaybackSession!!.getCoverUri(ctx) var bitmap: Bitmap? = null // Local covers get bitmap @@ -398,7 +395,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { val metadata = playbackSession.getMediaMetadataCompat(ctx) mediaSession.setMetadata(metadata) - val mediaItems = playbackSession.getMediaItems() + val mediaItems = playbackSession.getMediaItems(ctx) val playbackRateToUse = playbackRate ?: initialPlaybackRate ?: 1f initialPlaybackRate = playbackRate @@ -501,7 +498,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { } private fun setMediaSessionConnectorCustomActions(playbackSession:PlaybackSession) { - val mediaItems = playbackSession.getMediaItems() + val mediaItems = playbackSession.getMediaItems(ctx) val customActionProviders = mutableListOf( JumpBackwardCustomActionProvider(), JumpForwardCustomActionProvider(), diff --git a/android/app/src/main/res/xml/file_paths.xml b/android/app/src/main/res/xml/file_paths.xml index 782d63b9..e0098196 100644 --- a/android/app/src/main/res/xml/file_paths.xml +++ b/android/app/src/main/res/xml/file_paths.xml @@ -1,5 +1,4 @@ - - - + +