funkwhale-app-android/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt

128 lines
4.0 KiB
Kotlin

package audio.funkwhale.ffa.playback
import android.app.Notification
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.app.Service
import android.content.Intent
import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.media.app.NotificationCompat.MediaStyle
import androidx.media.session.MediaButtonReceiver
import audio.funkwhale.ffa.R
import audio.funkwhale.ffa.activities.MainActivity
import audio.funkwhale.ffa.model.Track
import audio.funkwhale.ffa.utils.AppContext
import audio.funkwhale.ffa.utils.CoverArt
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Default
import kotlinx.coroutines.launch
import org.koin.java.KoinJavaComponent.inject
class MediaControlsManager(
val context: Service,
private val scope: CoroutineScope,
private val mediaSession: MediaSessionCompat
) {
companion object {
const val NOTIFICATION_ACTION_OPEN_QUEUE = 0
}
private val ffaMediaSession: MediaSession by inject(MediaSession::class.java)
private var notification: Notification? = null
fun updateNotification(track: Track?, playing: Boolean) {
if (notification == null && !playing) return
track?.let {
val stateIcon = when (playing) {
true -> R.drawable.pause
false -> R.drawable.play
}
scope.launch(Default) {
val openIntent = Intent(context, MainActivity::class.java).apply {
action = NOTIFICATION_ACTION_OPEN_QUEUE.toString()
}
val openPendingIntent = PendingIntent.getActivity(context, 0, openIntent, FLAG_IMMUTABLE)
val coverUrl = maybeNormalizeUrl(track.album?.cover())
notification = NotificationCompat.Builder(
context,
AppContext.NOTIFICATION_CHANNEL_MEDIA_CONTROL
)
.setShowWhen(false)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setStyle(
MediaStyle()
.setMediaSession(mediaSession.sessionToken)
.setShowActionsInCompactView(0, 1, 2)
)
.setSmallIcon(R.drawable.funkwhaleshape)
.run {
coverUrl?.let {
try {
setLargeIcon(CoverArt.requestCreator(coverUrl).get())
} catch (_: Exception) {
}
return@run this
}
this
}
.setContentTitle(track.title)
.setContentText(track.artist.name)
.setContentIntent(openPendingIntent)
.setChannelId(AppContext.NOTIFICATION_CHANNEL_MEDIA_CONTROL)
.addAction(
action(
R.drawable.previous, context.getString(R.string.control_previous),
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
)
)
.addAction(
action(
stateIcon, context.getString(R.string.control_toggle),
PlaybackStateCompat.ACTION_PLAY_PAUSE
)
)
.addAction(
action(
R.drawable.next, context.getString(R.string.control_next),
PlaybackStateCompat.ACTION_SKIP_TO_NEXT
)
)
.build()
notification?.let {
if (playing) {
context.startForeground(AppContext.NOTIFICATION_MEDIA_CONTROL, it)
} else {
NotificationManagerCompat.from(context)
.notify(AppContext.NOTIFICATION_MEDIA_CONTROL, it)
}
}
ffaMediaSession.connector.invalidateMediaSessionMetadata()
}
}
}
fun remove() {
NotificationManagerCompat.from(context).cancel(AppContext.NOTIFICATION_MEDIA_CONTROL)
}
private fun action(icon: Int, title: String, id: Long): NotificationCompat.Action {
return MediaButtonReceiver.buildMediaButtonPendingIntent(context, id).run {
NotificationCompat.Action.Builder(icon, title, this).build()
}
}
}