mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 16:30:31 +05:30
Fix notification actions on older Android versions and react on playback changes
This commit is contained in:
parent
33de6ca827
commit
7364986afe
@ -1,11 +1,12 @@
|
||||
package com.github.libretube.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -14,7 +15,6 @@ import androidx.annotation.DrawableRes
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.media3.common.Player
|
||||
@ -24,7 +24,6 @@ import androidx.media3.session.MediaSession
|
||||
import androidx.media3.session.MediaStyleNotificationHelper
|
||||
import androidx.media3.session.SessionCommand
|
||||
import androidx.media3.session.SessionResult
|
||||
import androidx.media3.ui.PlayerNotificationManager
|
||||
import coil.request.ImageRequest
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.constants.BACKGROUND_CHANNEL_ID
|
||||
@ -35,10 +34,6 @@ import com.github.libretube.helpers.PlayerHelper
|
||||
import com.github.libretube.obj.PlayerNotificationData
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||
class NowPlayingNotification(
|
||||
@ -67,9 +62,7 @@ class NowPlayingNotification(
|
||||
private val nManager = NotificationManagerCompat.from(context)
|
||||
|
||||
private fun loadCurrentLargeIcon() {
|
||||
// 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
|
||||
if (DataSaverMode.isEnabled(context)) return
|
||||
if (notificationBitmap == null) enqueueThumbnailRequest {
|
||||
createOrUpdateNotification()
|
||||
}
|
||||
@ -94,7 +87,7 @@ class NowPlayingNotification(
|
||||
// online image
|
||||
notificationData?.thumbnailPath?.let { path ->
|
||||
ImageHelper.getDownloadedImage(context, path)?.let {
|
||||
notificationBitmap = ImageHelper.getSquareBitmap(it)
|
||||
notificationBitmap = processBitmap(it)
|
||||
callback.invoke(notificationBitmap!!)
|
||||
}
|
||||
return
|
||||
@ -103,7 +96,7 @@ class NowPlayingNotification(
|
||||
val request = ImageRequest.Builder(context)
|
||||
.data(notificationData?.thumbnailUrl)
|
||||
.target {
|
||||
notificationBitmap = ImageHelper.getSquareBitmap(it.toBitmap())
|
||||
notificationBitmap = processBitmap(it.toBitmap())
|
||||
callback.invoke(notificationBitmap!!)
|
||||
}
|
||||
.build()
|
||||
@ -112,8 +105,15 @@ class NowPlayingNotification(
|
||||
ImageHelper.imageLoader.enqueue(request)
|
||||
}
|
||||
|
||||
private val customActions = listOf(
|
||||
private fun processBitmap(bitmap: Bitmap): Bitmap {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
bitmap
|
||||
} else ImageHelper.getSquareBitmap(bitmap)
|
||||
}
|
||||
|
||||
private val legacyNotificationButtons get() = listOf(
|
||||
createNotificationAction(R.drawable.ic_prev_outlined, PREV, 1),
|
||||
createNotificationAction(if (player.isPlaying) R.drawable.ic_pause else R.drawable.ic_play, PLAY_PAUSE, 1),
|
||||
createNotificationAction(R.drawable.ic_next_outlined, NEXT, 1),
|
||||
createNotificationAction(R.drawable.ic_rewind_md, REWIND, 1),
|
||||
createNotificationAction(R.drawable.ic_forward_md, FORWARD, 1),
|
||||
@ -154,11 +154,16 @@ class NowPlayingNotification(
|
||||
): MediaSession.ConnectionResult {
|
||||
val connectionResult = super.onConnect(session, controller)
|
||||
val availableSessionCommands = connectionResult.availableSessionCommands.buildUpon()
|
||||
val availablePlayerCommands = connectionResult.availablePlayerCommands // Player.Commands.Builder().add(Player.COMMAND_PLAY_PAUSE).build()
|
||||
val availablePlayerCommands =
|
||||
connectionResult.availablePlayerCommands // Player.Commands.Builder().add(Player.COMMAND_PLAY_PAUSE).build()
|
||||
getCustomActions().forEach { button ->
|
||||
button.sessionCommand?.let { availableSessionCommands.add(it) }
|
||||
}
|
||||
session.setAvailableCommands(controller, availableSessionCommands.build(), availablePlayerCommands)
|
||||
session.setAvailableCommands(
|
||||
controller,
|
||||
availableSessionCommands.build(),
|
||||
availablePlayerCommands
|
||||
)
|
||||
return MediaSession.ConnectionResult.accept(
|
||||
availableSessionCommands.build(),
|
||||
availablePlayerCommands,
|
||||
@ -234,6 +239,10 @@ class NowPlayingNotification(
|
||||
FORWARD -> {
|
||||
player.seekTo(player.currentPosition + PlayerHelper.seekIncrement)
|
||||
}
|
||||
|
||||
PLAY_PAUSE -> {
|
||||
if (player.isPlaying) player.pause() else player.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,6 +263,14 @@ class NowPlayingNotification(
|
||||
if (notificationBuilder == null) {
|
||||
createMediaSession()
|
||||
createNotificationBuilder()
|
||||
createActionReceiver()
|
||||
// update the notification each time the player continues playing or pauses
|
||||
player.addListener(object : Player.Listener {
|
||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||
createOrUpdateNotification()
|
||||
super.onIsPlayingChanged(isPlaying)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
createOrUpdateNotification()
|
||||
@ -266,25 +283,41 @@ class NowPlayingNotification(
|
||||
notificationBuilder = NotificationCompat.Builder(context, BACKGROUND_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_launcher_lockscreen)
|
||||
.setContentIntent(createCurrentContentIntent())
|
||||
.setStyle(MediaStyleNotificationHelper.MediaStyle(mediaSession))
|
||||
.setLargeIcon(notificationBitmap)
|
||||
.apply {
|
||||
customActions.forEach {
|
||||
addAction(it)
|
||||
}
|
||||
}
|
||||
.setStyle(
|
||||
MediaStyleNotificationHelper.MediaStyle(mediaSession)
|
||||
.setShowActionsInCompactView(1)
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun createOrUpdateNotification() {
|
||||
if (notificationBuilder == null) return
|
||||
val notification = notificationBuilder!!
|
||||
.setContentText(notificationData?.title)
|
||||
.setContentTitle(notificationData?.title)
|
||||
.setContentText(notificationData?.uploaderName)
|
||||
.setLargeIcon(notificationBitmap)
|
||||
.clearActions()
|
||||
.apply {
|
||||
legacyNotificationButtons.forEach {
|
||||
addAction(it)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
nManager.notify(PLAYER_NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
||||
private val notificationActionReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
handlePlayerAction(intent.action ?: return)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createActionReceiver() {
|
||||
listOf(PREV, NEXT, REWIND, FORWARD, PLAY_PAUSE).forEach {
|
||||
context.registerReceiver(notificationActionReceiver, IntentFilter(it))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the [NowPlayingNotification]
|
||||
*/
|
||||
@ -294,7 +327,11 @@ class NowPlayingNotification(
|
||||
player.stop()
|
||||
player.release()
|
||||
|
||||
context.getSystemService<NotificationManager>()!!.cancel(PLAYER_NOTIFICATION_ID)
|
||||
runCatching {
|
||||
context.unregisterReceiver(notificationActionReceiver)
|
||||
}
|
||||
|
||||
nManager.cancel(PLAYER_NOTIFICATION_ID)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@ -302,5 +339,6 @@ class NowPlayingNotification(
|
||||
private const val NEXT = "next"
|
||||
private const val REWIND = "rewind"
|
||||
private const val FORWARD = "forward"
|
||||
private const val PLAY_PAUSE = "play_pause"
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user