Android Media3: Как добавить кнопки поиска в медиа-уведомление?

Потратив целую неделю на то, чтобы разобраться в этой невероятно сложной библиотеке, я пришел в замешательство. Я убежден, что существует готовое решение для этого пользовательского интерфейса мультимедийных уведомлений, которое в наши дни есть практически в каждом крупном приложении с воспроизведением мультимедиа. Он имеет кнопки поиска вперед и назад, кнопку скорости воспроизведения и кнопку избранного:

Я точно следовал этим инструкциям , и мое уведомление не изменилось, оно выглядит вот так. Просто кнопка предыдущего трека:

Я прочитал этот выпуск, где разработчик признает, что это сложно (и обещает задокументировать это, лол), но я не понимаю решения, которое он объясняет.

Я не использую PlayerNotificationManager. Вот что у меня есть до сих пор, что не работает. В моем PlaybackService:

    private val back = CommandButton.Builder()
            .setEnabled(true)
            .setIconResId(androidx.media3.session.R.drawable.media3_notification_seek_back)
            .setDisplayName("Seek Back")
            .setPlayerCommand(Player.COMMAND_SEEK_BACK)
            .build()
    private val forward = CommandButton.Builder()
            .setEnabled(true)
            .setIconResId(androidx.media3.session.R.drawable.media3_notification_seek_forward)
            .setDisplayName("Seek Forward")
            .setPlayerCommand(Player.COMMAND_SEEK_FORWARD)
            .build()
    private val buttons = ImmutableList.of(back, forward)

    override fun onCreate() {
        super.onCreate()
        val intent = packageManager!!.getLaunchIntentForPackage(packageName)!!
            .let { sessionIntent ->
                PendingIntent.getActivity(this, SESSION_INTENT_REQUEST_CODE, sessionIntent, PendingIntent.FLAG_IMMUTABLE)
            }
        _session = MediaSession.Builder(this, buildPlayer())
            .setSessionActivity(intent)
            .setCustomLayout(buttons)
            .setCallback(CustomMediaSessionCallback())
            .build()
        setListener(PlaybackServiceListener()) // irrelevant to this question
    }

    private inner class CustomMediaSessionCallback: MediaSession.Callback {
      override fun onConnect(
          session: MediaSession,
          controller: MediaSession.ControllerInfo
      ): MediaSession.ConnectionResult {
          val sessionCommands = MediaSession.ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon()
              .add(back.playerCommand)
              .add(forward.playerCommand)
              .build()
          return MediaSession.ConnectionResult.AcceptedResultBuilder(session)
              .setCustomLayout(buttons)
              .setAvailablePlayerCommands(sessionCommands)
              .build()
      }
    }

В моей ViewModel я создаю SessionToken и MediaController:

private val sessionToken =
        SessionToken(getApplication(), ComponentName(getApplication(), PlaybackService::class.java))
private val controllerFuture = MediaController.Builder(getApplication(), sessionToken).buildAsync()

Когда MediaController готов, я добавляю MediaItem и начинаю воспроизведение.

with(controller!!) {
    playWhenReady = true
    setMediaItem(mediaItem)
    prepare()
}

Чтобы внести ясность: абсолютно ничего не изменится, если я удалю .setCustomLayout(buttons) и .setCallback(CustomMediaSessionCallback()) из своего MediaSession.Builder. Это не имеет никакого эффекта.

Я получаю предупреждение в logcat: «Не удалось найти уникальный зарегистрированный приемник медиа-кнопки в данном контексте». Я искал эту строку в репозитории media3, но она там не появилась.

Может кто-нибудь мне помочь? Спасибо!

Какая настройка по умолчанию. Судя по тому, что я прочитал, все эти действия доступны по умолчанию.

gtxtreme 08.07.2024 07:25

@gtxtreme Я отредактировал свое сообщение, указав, как я создаю SessionToken и MediaController в ViewModel. Если эти действия доступны по умолчанию, возможно, в том, как я создаю MediaItem, чего-то не хватает или что-то в этом роде. Документы крайне бесполезны, несмотря ни на что...

Dale Cooper 09.07.2024 19:58

Обновление! Я узнал, что CommandButton.Builder.setPlayerCommand() предназначен для PlayerView в приложении, а не для уведомления. Для уведомления нам нужно вызвать setSessionCommand() с нашей специальной командной строкой. Благодаря этому изменению я получаю функцию поиска вперед и назад, но при этом оба значка добавляются справа от панели поиска. Я нашел стили и файлы макета в репозитории media3, соответствующие этим кнопкам (например, ExoStyledControls.Button.Center.FfwdWithAmount). Кажется, они предназначены только для пользовательского интерфейса приложения. Я совсем теряю голову, пытаясь понять, как сделать эту очень простую вещь 😩

Dale Cooper 09.07.2024 21:38

Дальнейшие приключения в кроличьей норе отладки... Я подозреваю, что эти кнопки недоступны, потому что команда игрока COMMAND_GET_CURRENT_MEDIA_ITEM недоступна после установки MediaItem. Теперь пытаюсь понять, почему... Но isCurrentMediaItemSeekable() возвращает false, если эта команда не доступна.

Dale Cooper 10.07.2024 04:20
0
4
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я наконец нашел на GitHub базу кода с пользовательским интерфейсом уведомлений, который я пытаюсь создать, и похоже, что люди действительно используют это сами. Мне кажется совершенно сумасшедшим, что это недоступно из коробки, но на данный момент я закончил копаться во внутренностях этой мусорной библиотеки. Пора построить макет с нуля и двигаться дальше по жизни.

Если я ошибаюсь, пожалуйста, дайте мне знать, и я буду рад принять лучший ответ.

Другие вопросы по теме

Потрясающие уведомления — различные диалоговые окна для запроса разрешения у пользователя на Android
Почему запланированное уведомление не появляется в установленное время, а вместо этого приложение возвращается к основной активности в Android Java?
Как получать активированные и отклоненные сообщения для Toast-уведомлений Windows
Android: когда приложение было открыто нажатием на уведомление, нажатие на дальнейшие уведомления открывает только приложение, не изменяя активность
Упорядоченная архитектура службы обмена сообщениями
Уведомления Azure DevOps: электронное письмо отправляется, если оно слишком долго находится в одном состоянии
Flutter_local_notification iOS: дубликат ключа плагина: FilePickerPlugin
Как отформатировать дату Last_triggered_at в уведомляющем сообщении Datadog
Как я могу планировать уведомления OneSignal программно из приложения Flutter
Создание оповещения об активности Azure для создания новых групп