PlaybackState“ACTION_STOP”在 Android Auto Media 应用程序中不起作用

问题描述 投票:0回答:1

我正在尝试为 Android 汽车构建一个媒体应用程序。我尝试根据官方文档构建应用程序,但我可能错过/误解了一些东西。我创建了一个“可播放”MediaItem,并且可以正确显示它及其元数据。我还为我的“MediaSession”设置了“PlaybackState”,但不知何故,我无法停止/暂停媒体,尽管我可以播放它。

这是播放媒体之前的 UI:

这是开始播放媒体后的 UI:

我期望开始播放媒体时应该有“暂停”按钮而不是“停止”。除了这个期望之外,主要的问题是,这个“停止”按钮不起作用。当我按下它时什么也没有发生。

这是我的 MusicService 类的完整代码:


//  imports here

class MusicService : MediaBrowserServiceCompat() {
    private lateinit var mediaSession: MediaSessionCompat
    private lateinit var mediaController: MediaControllerCompat
    private var playbackStateBuilder = PlaybackStateCompat.Builder()

    override fun onCreate() {
        super.onCreate()

        mediaSession = MediaSessionCompat(baseContext, "MusicService").apply {
            setCallback(MyMediaSessionCallback())
            setPlaybackState(
                playbackStateBuilder.apply {
                    setState(PlaybackStateCompat.STATE_NONE, 0L, 1f)
                    addActionsForPlayback(this)
//                    addCustomActionsForPlayback(this)
                }.build()
            )
//            setFlags(
//                MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or 
//  MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
            )
            isActive = true
        }
        sessionToken = mediaSession.sessionToken

        mediaController = MediaControllerCompat(baseContext, mediaSession.sessionToken).apply {
            registerCallback(MyMediaControllerCallback())
        }
    }

    override fun onGetRoot(
        clientPackageName: String, clientUid: Int, rootHints: Bundle?
    ): BrowserRoot {
        val extras = Bundle()
        extras.putBoolean(
            MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true
        )
        extras.putInt(
            MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE,
            MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM
        )
        extras.putInt(
            MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE,
            MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM
        )

        return BrowserRoot("/", extras)
    }

    override fun onLoadChildren(
        parentId: String, result: Result<MutableList<MediaItem>>
    ) {
        val treeResult = BrowseTree(baseContext)[parentId]

        if (treeResult.isNullOrEmpty()) {
            result.detach()
        } else {
            result.sendResult(treeResult)
        }
    }

    private fun addActionsForPlayback(playbackStateCompatBuilder: PlaybackStateCompat.Builder) {
        playbackStateCompatBuilder.apply {
            setActions(PlaybackStateCompat.ACTION_PLAY)
            setActions(PlaybackStateCompat.ACTION_PAUSE)
//            setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
            setActions(PlaybackStateCompat.ACTION_STOP)
            setActions(PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID)
            setActions(PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH)
            setActions(PlaybackStateCompat.ACTION_SEEK_TO)
        }
    }

    private fun addCustomActionsForPlayback(playbackStateCompatBuilder: PlaybackStateCompat.Builder) {
        //  custom actions defined here
    }

    inner class MyMediaSessionCallback : MediaSessionCompat.Callback() {
        private val musicSource = MusicSource(this@MusicService)
        private var seekedPos: Long? = null

        override fun onPrepare() {
            println("Preparing")

            super.onPrepare()
        }

        override fun onPrepareFromMediaId(mediaId: String?, extras: Bundle?) {
            println("Preparing from media id")

            super.onPrepareFromMediaId(mediaId, extras)
        }

        override fun onPlay() {
            println("Playing")
            mediaSession.setPlaybackState(
                playbackStateBuilder.apply {
                    setState(PlaybackStateCompat.STATE_PLAYING, seekedPos ?: 0L, 1f)

                    setActions(PlaybackStateCompat.ACTION_PAUSE)
                    setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
                    setActions(PlaybackStateCompat.ACTION_STOP)
                    setActions(PlaybackStateCompat.ACTION_SEEK_TO)
                    setActions(PlaybackStateCompat.ACTION_PLAY)
                }.build()
            )

            super.onPlay()
        }

        override fun onPause() {
            println("Paused")

            super.onPause()
        }

        override fun onStop() {
            println("Stopped")
            mediaSession.release()

            super.onStop()
        }

        override fun onSeekTo(pos: Long) {
            println("Seeked to: $pos")
            seekedPos = pos
            if (mediaController.playbackState.state == 3) {
                mediaSession.setPlaybackState(
                    playbackStateBuilder.apply {
                        setState(PlaybackStateCompat.STATE_PLAYING, pos, 1f)

                        addActionsForPlayback(this)
                    }.build()
                )
            } else {
                mediaSession.setPlaybackState(
                    playbackStateBuilder.apply {
                        setState(PlaybackStateCompat.STATE_PAUSED, pos, 1f)

                        addActionsForPlayback(this)
                    }.build()
                )
            }

            super.onSeekTo(pos)
        }

        override fun onRewind() {
            println("Rewind command")

            super.onRewind()
        }

        override fun onPlayFromMediaId(mediaId: String?, extras: Bundle) {
            seekedPos = null

            val defaultArt = BitmapFactory.decodeResource(
                [email protected], R.drawable.music_library_icon_2
            )
            val albumCover = musicSource.getAlbumCover(extras.getString("PATH", ""))

            mediaSession.apply {
                setPlaybackState(playbackStateBuilder.apply {
                    setState(PlaybackStateCompat.STATE_STOPPED, 0L, 1f)
                    setBufferedPosition(extras.getLong(MediaMetadataCompat.METADATA_KEY_DURATION))

                    setActions(PlaybackStateCompat.ACTION_PLAY)
                    setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
                    setActions(PlaybackStateCompat.ACTION_STOP)
                    setActions(PlaybackStateCompat.ACTION_SEEK_TO)
                    setActions(PlaybackStateCompat.ACTION_PAUSE)

                    val playbackStateExtras = Bundle().apply {
                        putString(
                            MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID,
                            extras.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID)
                        )
                    }
                    setExtras(playbackStateExtras)

                    addActionsForPlayback(this)
                }.build())
                setMetadata(
                    MediaMetadataCompat.Builder().apply {
                        putString(
                            MediaMetadataCompat.METADATA_KEY_MEDIA_ID,
                            extras.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID)
                        )
                        putString(
                            MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE,
                            extras.getString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE)
                        )
                        putString(
                            MediaMetadataCompat.METADATA_KEY_ARTIST,
                            extras.getString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE)
                        )
                        putString(
                            MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST,
                            extras.getString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE)
                        )
                        putString(
                            MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE,
                            extras.getString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE)
                        )
                        putLong(
                            MediaMetadataCompat.METADATA_KEY_DURATION,
                            extras.getLong(MediaMetadataCompat.METADATA_KEY_DURATION)
                        )
                        putString(
                            MediaMetadataCompat.METADATA_KEY_MEDIA_URI,
                            extras.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI)
                        )
                        if (albumCover != null) {
                            putBitmap(
                                MediaMetadataCompat.METADATA_KEY_ART, albumCover
                            )
                        } else {
                            putBitmap(
                                MediaMetadataCompat.METADATA_KEY_ART, defaultArt
                            )
                        }
                        putLong(
                            MediaConstants.METADATA_KEY_IS_EXPLICIT,
                            extras.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT)
                        )
                    }.build()
                )
            }

            println("Playing from Media Id")

            super.onPlayFromMediaId(mediaId, extras)
        }

        override fun onPlayFromSearch(query: String?, extras: Bundle?) {
            println("Playing from Search")

            super.onPlayFromSearch(query, extras)
        }

        override fun onPlayFromUri(uri: Uri?, extras: Bundle?) {
            println("Playing from Uri")

            super.onPlayFromUri(uri, extras)
        }

        override fun onCommand(command: String?, extras: Bundle?, cb: ResultReceiver?) {
            println("Command: $command")

            super.onCommand(command, extras, cb)
        }

        override fun onCustomAction(action: String?, extras: Bundle?) {
            println("Action: $action")

            super.onCustomAction(action, extras)
        }

        override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {
            println("Media button event")

            return super.onMediaButtonEvent(mediaButtonEvent)
        }
    }

    inner class MyMediaControllerCallback : MediaControllerCompat.Callback() {
        override fun onMetadataChanged(metadata: MediaMetadataCompat?) {
            println("Controller media id: ${metadata?.description?.mediaId}")

            super.onMetadataChanged(metadata)
        }

        override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {
            println("Controller playback state : ${state?.state}")

            super.onPlaybackStateChanged(state)
        }

        override fun onSessionReady() {
            println("Controller session is ready")

            super.onSessionReady()
        }
    }
}

我尝试使用以下代码设置 PlaybackState 所需的操作:

setActions(PlaybackStateCompat.ACTION_PLAY)
setActions(PlaybackStateCompat.ACTION_PAUSE)
setActions(PlaybackStateCompat.ACTION_STOP)
setActions(PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID)
setActions(PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH)
setActions(PlaybackStateCompat.ACTION_SEEK_TO)

但是这些没有显示“暂停”按钮,或者没有使“停止”按钮起作用。如果您需要,我可以提供更多从其他类导入的代码块。预先感谢您的帮助。

android kotlin android-mediaplayer android-music-player android-auto
1个回答
0
投票

看来问题可能是由于重复调用

setActions
引起的。您应该使用支持的操作的位掩码调用一次,而不是每个操作调用一次。

setActions(ACTION_PLAY or ACTION_PAUSE or ACTION_STOP or ACTION_PLAY_FROM_MEDIA_ID or ACTION_PLAY_FROM_SEARCH or ACTION_SEEK_TO)

or
是 Kotlin 中的按位 OR 运算符(类似于其他语言(包括 Java)中的
|
)。这有点令人困惑,但用简单的英语来说,上面的代码翻译为“这支持 ACTION_PLAY 和 ACTION_PAUSE 以及......”

© www.soinside.com 2019 - 2024. All rights reserved.