diff --git a/app/src/main/java/com/github/libretube/extensions/SetMetadata.kt b/app/src/main/java/com/github/libretube/extensions/SetMetadata.kt new file mode 100644 index 000000000..3887eb04f --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/SetMetadata.kt @@ -0,0 +1,31 @@ +package com.github.libretube.extensions + +import android.content.res.Resources +import android.graphics.BitmapFactory +import android.support.v4.media.MediaMetadataCompat +import androidx.core.net.toUri +import androidx.core.os.bundleOf +import androidx.media3.common.MediaItem +import androidx.media3.common.MediaMetadata +import com.github.libretube.R +import com.github.libretube.api.obj.Streams + +fun MediaItem.Builder.setMetadata(streams: Streams) = apply { + val appIcon = BitmapFactory.decodeResource( + Resources.getSystem(), + R.drawable.ic_launcher_monochrome, + ) + val extras = bundleOf( + MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON to appIcon, + MediaMetadataCompat.METADATA_KEY_TITLE to streams.title, + MediaMetadataCompat.METADATA_KEY_ARTIST to streams.uploader, + ) + setMediaMetadata( + MediaMetadata.Builder() + .setTitle(streams.title) + .setArtist(streams.uploader) + .setArtworkUri(streams.thumbnailUrl.toUri()) + .setExtras(extras) + .build() + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt b/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt index acc6fbb3c..1d0a90545 100644 --- a/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt +++ b/app/src/main/java/com/github/libretube/services/OnlinePlayerService.kt @@ -27,6 +27,7 @@ import com.github.libretube.constants.PLAYER_NOTIFICATION_ID import com.github.libretube.db.DatabaseHolder.Database import com.github.libretube.db.obj.WatchPosition import com.github.libretube.extensions.TAG +import com.github.libretube.extensions.setMetadata import com.github.libretube.extensions.toID import com.github.libretube.helpers.PlayerHelper import com.github.libretube.helpers.PlayerHelper.checkForSegments @@ -294,8 +295,7 @@ class OnlinePlayerService : LifecycleService() { * Sets the [MediaItem] with the [streams] into the [player] */ private fun setMediaItem() { - val streams = streams - streams ?: return + val streams = streams ?: return val uri = if (streams.audioStreams.isNotEmpty()) { PlayerHelper.getAudioSource(this, streams.audioStreams) @@ -305,6 +305,7 @@ class OnlinePlayerService : LifecycleService() { val mediaItem = MediaItem.Builder() .setUri(ProxyHelper.rewriteUrl(uri)) + .setMetadata(streams) .build() player?.setMediaItem(mediaItem) } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index b8c295b07..7afbdfef0 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -121,6 +121,7 @@ import retrofit2.HttpException import java.io.IOException import java.util.* import java.util.concurrent.Executors +import com.github.libretube.extensions.setMetadata import kotlin.math.abs @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @@ -1246,10 +1247,11 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions { } private fun setMediaSource(uri: Uri, mimeType: String) { - val mediaItem: MediaItem = MediaItem.Builder() + val mediaItem = MediaItem.Builder() .setUri(uri) .setMimeType(mimeType) .setSubtitleConfigurations(subtitles) + .setMetadata(streams) .build() exoPlayer.setMediaItem(mediaItem) } diff --git a/app/src/main/java/com/github/libretube/util/NowPlayingNotification.kt b/app/src/main/java/com/github/libretube/util/NowPlayingNotification.kt index 4cd9ae2c9..ddca94adb 100644 --- a/app/src/main/java/com/github/libretube/util/NowPlayingNotification.kt +++ b/app/src/main/java/com/github/libretube/util/NowPlayingNotification.kt @@ -6,13 +6,9 @@ import android.app.PendingIntent.FLAG_UPDATE_CURRENT import android.content.Context import android.content.Intent import android.graphics.Bitmap -import android.graphics.BitmapFactory import android.os.Build import android.os.Bundle -import android.support.v4.media.MediaDescriptionCompat -import android.support.v4.media.MediaMetadataCompat import android.support.v4.media.session.MediaSessionCompat -import android.util.Log import androidx.annotation.DrawableRes import androidx.core.app.NotificationCompat import androidx.core.app.PendingIntentCompat @@ -22,7 +18,6 @@ import androidx.core.os.bundleOf import androidx.media3.common.Player import androidx.media3.exoplayer.ExoPlayer import androidx.media3.session.CommandButton -import androidx.media3.session.DefaultMediaNotificationProvider import androidx.media3.session.MediaSession import androidx.media3.session.SessionCommand import androidx.media3.session.SessionResult @@ -36,7 +31,6 @@ import com.github.libretube.helpers.ImageHelper import com.github.libretube.helpers.PlayerHelper import com.github.libretube.obj.PlayerNotificationData import com.github.libretube.ui.activities.MainActivity -import com.google.common.collect.ImmutableList import com.google.common.util.concurrent.ListenableFuture @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) @@ -102,10 +96,10 @@ class NowPlayingNotification( player: Player, callback: PlayerNotificationManager.BitmapCallback, ): Bitmap? { - if (DataSaverMode.isEnabled(context)) return null - + // On Android 13 and up, the metadata is responsible for the thumbnail + if (DataSaverMode.isEnabled(context) || + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) return null if (bitmap == null) enqueueThumbnailRequest(callback) - return bitmap } @@ -119,7 +113,7 @@ class NowPlayingNotification( // online image notificationData?.thumbnailPath?.let { path -> ImageHelper.getDownloadedImage(context, path)?.let { - bitmap = processThumbnailBitmap(it) + bitmap = ImageHelper.getSquareBitmap(it) callback.onBitmap(bitmap!!) } return @@ -128,7 +122,7 @@ class NowPlayingNotification( val request = ImageRequest.Builder(context) .data(notificationData?.thumbnailUrl) .target { - bitmap = processThumbnailBitmap(it.toBitmap()) + bitmap = ImageHelper.getSquareBitmap(it.toBitmap()) callback.onBitmap(bitmap!!) } .build() @@ -159,17 +153,6 @@ class NowPlayingNotification( } } - /** - * Returns the bitmap on Android 13+, for everything below scaled down to a square - */ - private fun processThumbnailBitmap(bitmap: Bitmap): Bitmap { - return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - ImageHelper.getSquareBitmap(bitmap) - } else { - bitmap - } - } - private fun createNotificationAction( drawableRes: Int, actionName: String, @@ -260,24 +243,6 @@ class NowPlayingNotification( createMediaSessionAction(R.drawable.ic_forward_md, FORWARD), ) - private fun getMediaDescription(): MediaDescriptionCompat { - val appIcon = BitmapFactory.decodeResource( - context.resources, - R.drawable.ic_launcher_monochrome, - ) - val extras = bundleOf( - MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON to appIcon, - MediaMetadataCompat.METADATA_KEY_TITLE to notificationData?.title, - MediaMetadataCompat.METADATA_KEY_ARTIST to notificationData?.uploaderName, - ) - return MediaDescriptionCompat.Builder() - .setTitle(notificationData?.title) - .setSubtitle(notificationData?.uploaderName) - .setIconBitmap(appIcon) - .setExtras(extras) - .build() - } - private fun handlePlayerAction(action: String) { when (action) { NEXT -> { @@ -324,19 +289,6 @@ class NowPlayingNotification( } } - class NotificationProvider(val context: Context) : DefaultMediaNotificationProvider(context) { - override fun getMediaButtons( - session: MediaSession, - playerCommands: Player.Commands, - customLayout: ImmutableList, - showPauseButton: Boolean, - ): ImmutableList { - val buttons = super.getMediaButtons(session, playerCommands, customLayout, showPauseButton) - buttons.removeFirst() - return buttons - } - } - /** * Initializes the [playerNotification] attached to the [player] and shows it. */