Fixed crash happening due to recycled bitmap in notification.

This commit is contained in:
Koen J
2025-12-01 09:31:08 +01:00
parent 5cdac1405e
commit 767a8befaa
@@ -172,21 +172,26 @@ class MediaPlaybackService : Service() {
} }
fun closeMediaSession() { fun closeMediaSession() {
Logger.v(TAG, "closeMediaSession"); Logger.v(TAG, "closeMediaSession")
stopForeground(STOP_FOREGROUND_REMOVE); stopForeground(STOP_FOREGROUND_REMOVE)
abandonAudioFocus() abandonAudioFocus()
val notifManager = _notificationManager; val notifManager = _notificationManager
Logger.i(TAG, "Cancelling playback notification (notifManager: ${notifManager != null})"); Logger.i(TAG, "Cancelling playback notification (notifManager: ${notifManager != null})")
notifManager?.cancel(MEDIA_NOTIF_ID); notifManager?.cancel(MEDIA_NOTIF_ID)
_notif_last_video = null;
_notif_last_bitmap = null;
_mediaSession = null;
if(_instance == this) _notif_last_video = null
_instance = null; _notif_last_bitmap = null
this.stopSelf();
_mediaSession?.isActive = false
_mediaSession?.release()
_mediaSession = null
if (_instance == this)
_instance = null
stopSelf()
} }
fun updateMediaSession(videoUpdated: IPlatformVideo?) { fun updateMediaSession(videoUpdated: IPlatformVideo?) {
@@ -206,20 +211,14 @@ class MediaPlaybackService : Service() {
if(_notificationChannel == null || _mediaSession == null) if(_notificationChannel == null || _mediaSession == null)
setupNotificationRequirements(); setupNotificationRequirements();
_mediaSession?.setMetadata( updateMediaMetadata(video, lastBitmap)
MediaMetadataCompat.Builder()
.putString(MediaMetadata.METADATA_KEY_ARTIST, video.author.name)
.putString(MediaMetadata.METADATA_KEY_TITLE, video.name)
.putLong(MediaMetadata.METADATA_KEY_DURATION, video.duration * 1000)
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, lastBitmap)
.build());
val thumbnail = video.thumbnails.getHQThumbnail(); val thumbnail = video.thumbnails.getHQThumbnail();
_notif_last_video = video; _notif_last_video = video;
if(isUpdating) if(isUpdating)
notifyMediaSession(video, _notif_last_bitmap); notifyMediaSession(video, _notif_last_bitmap?.takeIf { !it.isRecycled });
else if(thumbnail != null) { else if(thumbnail != null) {
notifyMediaSession(video, null); notifyMediaSession(video, null);
val tag = video; val tag = video;
@@ -227,16 +226,21 @@ class MediaPlaybackService : Service() {
.load(thumbnail) .load(thumbnail)
.into(object: CustomTarget<Bitmap>() { .into(object: CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap,transition: Transition<in Bitmap>?) { override fun onResourceReady(resource: Bitmap,transition: Transition<in Bitmap>?) {
if(tag == _notif_last_video) { if (tag != _notif_last_video) return
notifyMediaSession(video, resource) if (resource.isRecycled) {
_mediaSession?.setMetadata( notifyMediaSession(video, null)
MediaMetadataCompat.Builder() return
.putString(MediaMetadata.METADATA_KEY_ARTIST, video.author.name)
.putString(MediaMetadata.METADATA_KEY_TITLE, video.name)
.putLong(MediaMetadata.METADATA_KEY_DURATION, video.duration * 1000)
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, resource)
.build());
} }
val albumArt = resource.copy(
resource.config ?: Bitmap.Config.ARGB_8888,
false
)
_notif_last_bitmap = albumArt
notifyMediaSession(video, albumArt)
updateMediaMetadata(video, albumArt)
} }
override fun onLoadCleared(placeholder: Drawable?) { override fun onLoadCleared(placeholder: Drawable?) {
if(tag == _notif_last_video) if(tag == _notif_last_video)
@@ -247,6 +251,19 @@ class MediaPlaybackService : Service() {
else else
notifyMediaSession(video, null); notifyMediaSession(video, null);
} }
private fun updateMediaMetadata(video: IPlatformVideo, bitmap: Bitmap?) {
val builder = MediaMetadataCompat.Builder()
.putString(MediaMetadata.METADATA_KEY_ARTIST, video.author.name)
.putString(MediaMetadata.METADATA_KEY_TITLE, video.name)
.putLong(MediaMetadata.METADATA_KEY_DURATION, video.duration * 1000)
val safeBitmap = bitmap?.takeIf { !it.isRecycled }
if (safeBitmap != null) {
builder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, safeBitmap)
}
_mediaSession?.setMetadata(builder.build())
}
private fun generateMediaAction(icon: Int, title: String, intent: PendingIntent) : NotificationCompat.Action { private fun generateMediaAction(icon: Int, title: String, intent: PendingIntent) : NotificationCompat.Action {
return NotificationCompat.Action.Builder(icon, title, intent).build(); return NotificationCompat.Action.Builder(icon, title, intent).build();
} }