120 lines
3.9 KiB
Kotlin
120 lines
3.9 KiB
Kotlin
package audio.funkwhale.ffa.playback
|
|
|
|
import android.app.Notification
|
|
import android.app.PendingIntent
|
|
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.maybeNormalizeUrl
|
|
import com.squareup.picasso.Picasso
|
|
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, 0)
|
|
|
|
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(Picasso.get().load(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()
|
|
}
|
|
}
|
|
}
|