playback: split up mediasession interface and holder
This commit is contained in:
parent
f1e1152e21
commit
916c3c46df
4 changed files with 218 additions and 190 deletions
|
@ -153,6 +153,9 @@ dependencies {
|
|||
// Tasker integration
|
||||
implementation 'com.joaomgcd:taskerpluginlibrary:0.4.10'
|
||||
|
||||
// Fuzzy search
|
||||
implementation 'org.apache.commons:commons-text:1.9'
|
||||
|
||||
// Testing
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
|
||||
testImplementation "junit:junit:4.13.2"
|
||||
|
|
|
@ -108,16 +108,6 @@ class AuxioService :
|
|||
musicFragment.search(query, result)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun onSubscribe(id: String?, option: Bundle?) {
|
||||
super.onSubscribe(id, option)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun onUnsubscribe(id: String?) {
|
||||
super.onUnsubscribe(id)
|
||||
}
|
||||
|
||||
override fun updateForeground(change: ForegroundListener.Change) {
|
||||
val mediaNotification = playbackFragment.notification
|
||||
if (mediaNotification != null) {
|
||||
|
|
|
@ -20,10 +20,8 @@ package org.oxycblt.auxio.playback.system
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.media.session.MediaSession
|
||||
import android.support.v4.media.MediaDescriptionCompat
|
||||
import android.support.v4.media.MediaMetadataCompat
|
||||
import android.support.v4.media.session.MediaSessionCompat
|
||||
|
@ -39,25 +37,17 @@ import org.oxycblt.auxio.IntegerTable
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.image.BitmapProvider
|
||||
import org.oxycblt.auxio.image.ImageSettings
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.MusicRepository
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.resolveNames
|
||||
import org.oxycblt.auxio.music.service.MediaSessionUID
|
||||
import org.oxycblt.auxio.playback.ActionMode
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.playback.service.MediaSessionInterface
|
||||
import org.oxycblt.auxio.playback.service.PlaybackActions
|
||||
import org.oxycblt.auxio.playback.state.PlaybackCommand
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.playback.state.Progression
|
||||
import org.oxycblt.auxio.playback.state.QueueChange
|
||||
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||
import org.oxycblt.auxio.playback.state.ShuffleMode
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.newBroadcastPendingIntent
|
||||
import org.oxycblt.auxio.util.newMainPendingIntent
|
||||
|
@ -71,10 +61,9 @@ import org.oxycblt.auxio.util.newMainPendingIntent
|
|||
class MediaSessionHolder
|
||||
private constructor(
|
||||
private val context: Context,
|
||||
private val sessionInterface: MediaSessionInterface,
|
||||
private val playbackManager: PlaybackStateManager,
|
||||
private val playbackSettings: PlaybackSettings,
|
||||
private val commandFactory: PlaybackCommand.Factory,
|
||||
private val musicRepository: MusicRepository,
|
||||
private val bitmapProvider: BitmapProvider,
|
||||
private val imageSettings: ImageSettings
|
||||
) :
|
||||
|
@ -86,29 +75,23 @@ private constructor(
|
|||
class Factory
|
||||
@Inject
|
||||
constructor(
|
||||
private val sessionInterface: MediaSessionInterface,
|
||||
private val playbackManager: PlaybackStateManager,
|
||||
private val playbackSettings: PlaybackSettings,
|
||||
private val commandFactory: PlaybackCommand.Factory,
|
||||
private val musicRepository: MusicRepository,
|
||||
private val bitmapProvider: BitmapProvider,
|
||||
private val imageSettings: ImageSettings
|
||||
private val imageSettings: ImageSettings,
|
||||
) {
|
||||
fun create(context: Context) =
|
||||
MediaSessionHolder(
|
||||
context,
|
||||
sessionInterface,
|
||||
playbackManager,
|
||||
playbackSettings,
|
||||
commandFactory,
|
||||
musicRepository,
|
||||
bitmapProvider,
|
||||
imageSettings)
|
||||
}
|
||||
|
||||
private val mediaSession =
|
||||
MediaSessionCompat(context, context.packageName).apply {
|
||||
isActive = true
|
||||
setQueueTitle(context.getString(R.string.lbl_queue))
|
||||
}
|
||||
private val mediaSession = MediaSessionCompat(context, context.packageName)
|
||||
val token: MediaSessionCompat.Token
|
||||
get() = mediaSession.sessionToken
|
||||
|
||||
|
@ -119,6 +102,11 @@ private constructor(
|
|||
private var foregroundListener: ForegroundListener? = null
|
||||
|
||||
fun attach(foregroundListener: ForegroundListener) {
|
||||
mediaSession.apply {
|
||||
isActive = true
|
||||
setQueueTitle(context.getString(R.string.lbl_queue))
|
||||
setCallback(sessionInterface)
|
||||
}
|
||||
this.foregroundListener = foregroundListener
|
||||
playbackManager.addListener(this)
|
||||
playbackSettings.registerListener(this)
|
||||
|
@ -218,116 +206,6 @@ private constructor(
|
|||
|
||||
// --- MEDIASESSION OVERRIDES ---
|
||||
|
||||
override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
|
||||
super.onPlayFromMediaId(mediaId, extras)
|
||||
val uid = MediaSessionUID.fromString(mediaId ?: return) ?: return
|
||||
val command = expandIntoCommand(uid)
|
||||
requireNotNull(command) { "Invalid playback configuration" }
|
||||
playbackManager.play(command)
|
||||
}
|
||||
|
||||
override fun onPlayFromUri(uri: Uri?, extras: Bundle?) {
|
||||
super.onPlayFromUri(uri, extras)
|
||||
// STUB
|
||||
}
|
||||
|
||||
override fun onPlayFromSearch(query: String?, extras: Bundle?) {
|
||||
super.onPlayFromSearch(query, extras)
|
||||
// STUB: Unimplemented, no search engine
|
||||
}
|
||||
|
||||
override fun onAddQueueItem(description: MediaDescriptionCompat) {
|
||||
super.onAddQueueItem(description)
|
||||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||
val uid = MediaSessionUID.fromString(description.mediaId ?: return) ?: return
|
||||
val song =
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> deviceLibrary.findSong(uid.uid)
|
||||
is MediaSessionUID.ChildItem -> deviceLibrary.findSong(uid.childUid)
|
||||
else -> null
|
||||
}
|
||||
?: return
|
||||
playbackManager.addToQueue(song)
|
||||
}
|
||||
|
||||
override fun onRemoveQueueItem(description: MediaDescriptionCompat) {
|
||||
super.onRemoveQueueItem(description)
|
||||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||
val uid = MediaSessionUID.fromString(description.mediaId ?: return) ?: return
|
||||
val song =
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> deviceLibrary.findSong(uid.uid)
|
||||
is MediaSessionUID.ChildItem -> deviceLibrary.findSong(uid.childUid)
|
||||
else -> null
|
||||
}
|
||||
?: return
|
||||
val queueIndex = playbackManager.queue.indexOf(song)
|
||||
if (queueIndex > -1) {
|
||||
playbackManager.removeQueueItem(queueIndex)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlay() {
|
||||
playbackManager.playing(true)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
playbackManager.playing(false)
|
||||
}
|
||||
|
||||
override fun onSkipToNext() {
|
||||
playbackManager.next()
|
||||
}
|
||||
|
||||
override fun onSkipToPrevious() {
|
||||
playbackManager.prev()
|
||||
}
|
||||
|
||||
override fun onSeekTo(position: Long) {
|
||||
playbackManager.seekTo(position)
|
||||
}
|
||||
|
||||
override fun onFastForward() {
|
||||
playbackManager.next()
|
||||
}
|
||||
|
||||
override fun onRewind() {
|
||||
playbackManager.seekTo(0)
|
||||
playbackManager.playing(true)
|
||||
}
|
||||
|
||||
override fun onSetRepeatMode(repeatMode: Int) {
|
||||
playbackManager.repeatMode(
|
||||
when (repeatMode) {
|
||||
PlaybackStateCompat.REPEAT_MODE_ALL -> RepeatMode.ALL
|
||||
PlaybackStateCompat.REPEAT_MODE_GROUP -> RepeatMode.ALL
|
||||
PlaybackStateCompat.REPEAT_MODE_ONE -> RepeatMode.TRACK
|
||||
else -> RepeatMode.NONE
|
||||
})
|
||||
}
|
||||
|
||||
override fun onSetShuffleMode(shuffleMode: Int) {
|
||||
playbackManager.shuffled(
|
||||
shuffleMode == PlaybackStateCompat.SHUFFLE_MODE_ALL ||
|
||||
shuffleMode == PlaybackStateCompat.SHUFFLE_MODE_GROUP)
|
||||
}
|
||||
|
||||
override fun onSkipToQueueItem(id: Long) {
|
||||
playbackManager.goto(id.toInt())
|
||||
}
|
||||
|
||||
override fun onCustomAction(action: String, extras: Bundle?) {
|
||||
super.onCustomAction(action, extras)
|
||||
// Service already handles intents from the old notification actions, easier to
|
||||
// plug into that system.
|
||||
context.sendBroadcast(Intent(action))
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
// Get the service to shut down with the ACTION_EXIT intent
|
||||
context.sendBroadcast(Intent(PlaybackActions.ACTION_EXIT))
|
||||
}
|
||||
|
||||
// --- INTERNAL ---
|
||||
|
||||
/**
|
||||
|
@ -435,40 +313,6 @@ private constructor(
|
|||
mediaSession.setQueue(queueItems)
|
||||
}
|
||||
|
||||
private fun expandIntoCommand(uid: MediaSessionUID): PlaybackCommand? {
|
||||
val music: Music
|
||||
var parent: MusicParent? = null
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> {
|
||||
music = musicRepository.find(uid.uid) ?: return null
|
||||
}
|
||||
is MediaSessionUID.ChildItem -> {
|
||||
music = musicRepository.find(uid.childUid) ?: return null
|
||||
parent = musicRepository.find(uid.parentUid) as? MusicParent ?: return null
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
return when (music) {
|
||||
is Song -> inferSongFromParent(music, parent)
|
||||
is Album -> commandFactory.album(music, ShuffleMode.OFF)
|
||||
is Artist -> commandFactory.artist(music, ShuffleMode.OFF)
|
||||
is Genre -> commandFactory.genre(music, ShuffleMode.OFF)
|
||||
is Playlist -> commandFactory.playlist(music, ShuffleMode.OFF)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inferSongFromParent(music: Song, parent: MusicParent?) =
|
||||
when (parent) {
|
||||
is Album -> commandFactory.songFromAlbum(music, ShuffleMode.IMPLICIT)
|
||||
is Artist -> commandFactory.songFromArtist(music, parent, ShuffleMode.IMPLICIT)
|
||||
?: commandFactory.songFromArtist(music, music.artists[0], ShuffleMode.IMPLICIT)
|
||||
is Genre -> commandFactory.songFromGenre(music, parent, ShuffleMode.IMPLICIT)
|
||||
?: commandFactory.songFromGenre(music, music.genres[0], ShuffleMode.IMPLICIT)
|
||||
is Playlist -> commandFactory.songFromPlaylist(music, parent, ShuffleMode.IMPLICIT)
|
||||
null -> commandFactory.songFromAll(music, ShuffleMode.IMPLICIT)
|
||||
}
|
||||
|
||||
/** Invalidate the current [MediaSessionCompat]'s [PlaybackStateCompat]. */
|
||||
private fun invalidateSessionState() {
|
||||
logD("Updating media session playback state")
|
||||
|
@ -477,7 +321,7 @@ private constructor(
|
|||
// InternalPlayer.State handles position/state information.
|
||||
playbackManager.progression
|
||||
.intoPlaybackState(PlaybackStateCompat.Builder())
|
||||
.setActions(ACTIONS)
|
||||
.setActions(MediaSessionInterface.ACTIONS)
|
||||
// Active queue ID corresponds to the indices we populated prior, use them here.
|
||||
.setActiveQueueItemId(playbackManager.index.toLong())
|
||||
|
||||
|
@ -543,17 +387,6 @@ private constructor(
|
|||
|
||||
companion object {
|
||||
private val emptyMetadata = MediaMetadataCompat.Builder().build()
|
||||
private const val ACTIONS =
|
||||
PlaybackStateCompat.ACTION_PLAY or
|
||||
PlaybackStateCompat.ACTION_PAUSE or
|
||||
PlaybackStateCompat.ACTION_PLAY_PAUSE or
|
||||
PlaybackStateCompat.ACTION_SET_REPEAT_MODE or
|
||||
PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE or
|
||||
PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
|
||||
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
|
||||
PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM or
|
||||
PlaybackStateCompat.ACTION_SEEK_TO or
|
||||
PlaybackStateCompat.ACTION_STOP
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
package org.oxycblt.auxio.playback.service
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.support.v4.media.MediaDescriptionCompat
|
||||
import android.support.v4.media.session.MediaSessionCompat
|
||||
import android.support.v4.media.session.PlaybackStateCompat
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.MusicRepository
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.service.MediaSessionUID
|
||||
import org.oxycblt.auxio.playback.state.PlaybackCommand
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||
import org.oxycblt.auxio.playback.state.ShuffleMode
|
||||
import javax.inject.Inject
|
||||
|
||||
class MediaSessionInterface @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val playbackManager: PlaybackStateManager,
|
||||
private val commandFactory: PlaybackCommand.Factory,
|
||||
private val musicRepository: MusicRepository,
|
||||
) : MediaSessionCompat.Callback() {
|
||||
|
||||
override fun onPrepareFromMediaId(mediaId: String?, extras: Bundle?) {
|
||||
super.onPrepareFromMediaId(mediaId, extras)
|
||||
}
|
||||
|
||||
override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
|
||||
super.onPlayFromMediaId(mediaId, extras)
|
||||
val uid = MediaSessionUID.fromString(mediaId ?: return) ?: return
|
||||
val command = expandIntoCommand(uid)
|
||||
requireNotNull(command) { "Invalid playback configuration" }
|
||||
playbackManager.play(command)
|
||||
}
|
||||
|
||||
override fun onPrepareFromSearch(query: String?, extras: Bundle?) {
|
||||
super.onPrepareFromSearch(query, extras)
|
||||
}
|
||||
|
||||
override fun onPlayFromSearch(query: String?, extras: Bundle?) {
|
||||
super.onPlayFromSearch(query, extras)
|
||||
// STUB: Unimplemented, no search engine
|
||||
}
|
||||
|
||||
override fun onPrepareFromUri(uri: Uri?, extras: Bundle?) {
|
||||
super.onPrepareFromUri(uri, extras)
|
||||
}
|
||||
|
||||
override fun onPlayFromUri(uri: Uri?, extras: Bundle?) {
|
||||
super.onPlayFromUri(uri, extras)
|
||||
// STUB
|
||||
}
|
||||
|
||||
override fun onAddQueueItem(description: MediaDescriptionCompat) {
|
||||
super.onAddQueueItem(description)
|
||||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||
val uid = MediaSessionUID.fromString(description.mediaId ?: return) ?: return
|
||||
val song =
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> deviceLibrary.findSong(uid.uid)
|
||||
is MediaSessionUID.ChildItem -> deviceLibrary.findSong(uid.childUid)
|
||||
else -> null
|
||||
}
|
||||
?: return
|
||||
playbackManager.addToQueue(song)
|
||||
}
|
||||
|
||||
override fun onRemoveQueueItem(description: MediaDescriptionCompat) {
|
||||
super.onRemoveQueueItem(description)
|
||||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||
val uid = MediaSessionUID.fromString(description.mediaId ?: return) ?: return
|
||||
val song =
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> deviceLibrary.findSong(uid.uid)
|
||||
is MediaSessionUID.ChildItem -> deviceLibrary.findSong(uid.childUid)
|
||||
else -> null
|
||||
}
|
||||
?: return
|
||||
val queueIndex = playbackManager.queue.indexOf(song)
|
||||
if (queueIndex > -1) {
|
||||
playbackManager.removeQueueItem(queueIndex)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlay() {
|
||||
playbackManager.playing(true)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
playbackManager.playing(false)
|
||||
}
|
||||
|
||||
override fun onSkipToNext() {
|
||||
playbackManager.next()
|
||||
}
|
||||
|
||||
override fun onSkipToPrevious() {
|
||||
playbackManager.prev()
|
||||
}
|
||||
|
||||
override fun onSeekTo(position: Long) {
|
||||
playbackManager.seekTo(position)
|
||||
}
|
||||
|
||||
override fun onFastForward() {
|
||||
playbackManager.next()
|
||||
}
|
||||
|
||||
override fun onRewind() {
|
||||
playbackManager.seekTo(0)
|
||||
playbackManager.playing(true)
|
||||
}
|
||||
|
||||
override fun onSetRepeatMode(repeatMode: Int) {
|
||||
playbackManager.repeatMode(
|
||||
when (repeatMode) {
|
||||
PlaybackStateCompat.REPEAT_MODE_ALL -> RepeatMode.ALL
|
||||
PlaybackStateCompat.REPEAT_MODE_GROUP -> RepeatMode.ALL
|
||||
PlaybackStateCompat.REPEAT_MODE_ONE -> RepeatMode.TRACK
|
||||
else -> RepeatMode.NONE
|
||||
})
|
||||
}
|
||||
|
||||
override fun onSetShuffleMode(shuffleMode: Int) {
|
||||
playbackManager.shuffled(
|
||||
shuffleMode == PlaybackStateCompat.SHUFFLE_MODE_ALL ||
|
||||
shuffleMode == PlaybackStateCompat.SHUFFLE_MODE_GROUP)
|
||||
}
|
||||
|
||||
override fun onSkipToQueueItem(id: Long) {
|
||||
playbackManager.goto(id.toInt())
|
||||
}
|
||||
|
||||
override fun onCustomAction(action: String, extras: Bundle?) {
|
||||
super.onCustomAction(action, extras)
|
||||
// Service already handles intents from the old notification actions, easier to
|
||||
// plug into that system.
|
||||
context.sendBroadcast(Intent(action))
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
// Get the service to shut down with the ACTION_EXIT intent
|
||||
context.sendBroadcast(Intent(PlaybackActions.ACTION_EXIT))
|
||||
}
|
||||
|
||||
private fun expandIntoCommand(uid: MediaSessionUID): PlaybackCommand? {
|
||||
val music: Music
|
||||
var parent: MusicParent? = null
|
||||
when (uid) {
|
||||
is MediaSessionUID.SingleItem -> {
|
||||
music = musicRepository.find(uid.uid) ?: return null
|
||||
}
|
||||
is MediaSessionUID.ChildItem -> {
|
||||
music = musicRepository.find(uid.childUid) ?: return null
|
||||
parent = musicRepository.find(uid.parentUid) as? MusicParent ?: return null
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
return when (music) {
|
||||
is Song -> inferSongFromParent(music, parent)
|
||||
is Album -> commandFactory.album(music, ShuffleMode.OFF)
|
||||
is Artist -> commandFactory.artist(music, ShuffleMode.OFF)
|
||||
is Genre -> commandFactory.genre(music, ShuffleMode.OFF)
|
||||
is Playlist -> commandFactory.playlist(music, ShuffleMode.OFF)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inferSongFromParent(music: Song, parent: MusicParent?) =
|
||||
when (parent) {
|
||||
is Album -> commandFactory.songFromAlbum(music, ShuffleMode.IMPLICIT)
|
||||
is Artist -> commandFactory.songFromArtist(music, parent, ShuffleMode.IMPLICIT)
|
||||
?: commandFactory.songFromArtist(music, music.artists[0], ShuffleMode.IMPLICIT)
|
||||
is Genre -> commandFactory.songFromGenre(music, parent, ShuffleMode.IMPLICIT)
|
||||
?: commandFactory.songFromGenre(music, music.genres[0], ShuffleMode.IMPLICIT)
|
||||
is Playlist -> commandFactory.songFromPlaylist(music, parent, ShuffleMode.IMPLICIT)
|
||||
null -> commandFactory.songFromAll(music, ShuffleMode.IMPLICIT)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ACTIONS =
|
||||
PlaybackStateCompat.ACTION_PLAY or
|
||||
PlaybackStateCompat.ACTION_PAUSE or
|
||||
PlaybackStateCompat.ACTION_PLAY_PAUSE or
|
||||
PlaybackStateCompat.ACTION_SET_REPEAT_MODE or
|
||||
PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE or
|
||||
PlaybackStateCompat.ACTION_SKIP_TO_NEXT or
|
||||
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or
|
||||
PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM or
|
||||
PlaybackStateCompat.ACTION_SEEK_TO or
|
||||
PlaybackStateCompat.ACTION_STOP
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue