Мультимедийные кнопки — это аппаратные кнопки, имеющиеся на устройствах Android и других периферийных устройствах, например кнопка паузы/воспроизведения на гарнитуре Bluetooth. Когда пользователь нажимает кнопку мультимедиа, Android генерирует KeyEvent
, который содержит код ключа , идентифицирующий кнопку. Коды клавиш для кнопки мультимедиа KeyEvents — это константы, начинающиеся с KEYCODE_MEDIA
(например, KEYCODE_MEDIA_PLAY
).
Приложения должны иметь возможность обрабатывать события мультимедийных кнопок в трех случаях в следующем порядке приоритета:
- Когда активность пользовательского интерфейса приложения видна
- Когда активность пользовательского интерфейса скрыта, а медиа-сеанс приложения активен
- Когда активность пользовательского интерфейса скрыта, а мультимедийный сеанс приложения неактивен и его необходимо перезапустить.
Обработка медиа-кнопок в активности на переднем плане
Активность переднего плана получает событие клавиши медиа-кнопки в своем методе onKeyDown()
. В зависимости от работающей версии Android система перенаправляет событие на медиаконтроллер двумя способами:
- Если вы используете Android 5.0 (уровень API 21) или новее, вызовите
FLAG_HANDLES_MEDIA_BUTTONS
MediaBrowserCompat.ConnectionCallback.onConnected
. Это автоматически вызоветdispatchMediaButtonEvent()
вашего медиа-контроллера, который преобразует код ключа в обратный вызов медиа-сеанса. - До Android 5.0 (уровень API 21) вам необходимо изменить
onKeyDown()
для самостоятельной обработки события. (Подробнее см. в разделе «Обработка медиа-кнопок в активном медиа-сеансе» .) В следующем фрагменте кода показано, как перехватить код ключа и вызвать sendMediaButtonEvent(). Обязательно вернитеtrue
, чтобы указать, что событие было обработано:Котлин
fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return super.onKeyDown(keyCode, event) } when (keyCode) { KeyEvent.KEYCODE_MEDIA_PLAY -> { yourMediaController.dispatchMediaButtonEvent(event) return true } } return super.onKeyDown(keyCode, event) }
Ява
@Override boolean onKeyDown(int keyCode, KeyEvent event) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return super.onKeyDown(keyCode, event); } switch (keyCode) { case KeyEvent.KEYCODE_MEDIA_PLAY: yourMediaController.dispatchMediaButtonEvent(event); return true; } return super.onKeyDown(keyCode, event); }
Поиск медиа-сессии
Если активность переднего плана не обрабатывает событие, Android попытается найти сеанс мультимедиа, который сможет его обработать. Опять же, в зависимости от работающей версии Android, есть два способа поиска медиа-сессии:
Если вы используете Android 8.0 (уровень API 26) или более позднюю версию, система пытается найти последнее приложение с MediaSession, которое воспроизводило звук локально. Если сеанс все еще активен, Android отправляет событие непосредственно ему. В противном случае, если сеанс не активен и у него есть приемник медиа-кнопки, Android отправляет событие получателю, который перезапускает сеанс и может получить событие. (Подробнее см. в разделе «Использование мультимедийных кнопок для перезапуска неактивного мультимедийного сеанса» .) Если в сеансе нет приемника мультимедийных кнопок, система отбрасывает событие мультимедийной кнопки, и ничего не происходит. Логика показана на следующей схеме:
До Android 8.0 (уровень API 26) система пытается отправить событие в активный сеанс мультимедиа. Если имеется несколько активных сеансов мультимедиа, Android пытается выбрать сеанс мультимедиа, который готовится к воспроизведению (буферизации/подключению), воспроизведению или приостановке, а не тот, который остановлен. (Подробнее см. в разделе «Обработка медиа-кнопок в активном медиа-сеансе» .) Если активного сеанса нет, Android пытается отправить событие в последний активный сеанс. (Подробнее см. в разделе Использование кнопок мультимедиа для перезапуска неактивного сеанса мультимедиа .) Логика показана на следующей диаграмме:
Обработка медиа-кнопок в активном медиа-сеансе
В Android 5.0 (уровень API 21) и более поздних версиях Android автоматически отправляет события мультимедийных кнопок в ваш активный мультимедийный сеанс, вызывая onMediaButtonEvent()
. По умолчанию этот обратный вызов преобразует KeyEvent в соответствующий метод обратного вызова мультимедийного сеанса, который соответствует коду ключа.
До Android 5.0 (уровень API 21) Android обрабатывал события мультимедийных кнопок, передавая намерение с помощью действия ACTION_MEDIA_BUTTON
. Ваше приложение должно зарегистрировать BroadcastReceiver, чтобы перехватывать эти намерения. Класс MediaButtonReceiver
был разработан специально для этой цели. Это удобный класс в библиотеке совместимости мультимедиа Android , который обрабатывает ACTION_MEDIA_BUTTON
и преобразует входящие намерения в соответствующие вызовы метода MediaSessionCompat.Callback
.
MediaButtonReceiver
— это недолговечный BroadcastReceiver. Он пересылает входящие намерения службе, которая управляет вашим медиа-сеансом. Если вы хотите использовать мультимедийные кнопки в системах более ранних версий, чем Android 5.0, вы должны включить MediaButtonReceiver
в свой манифест с фильтром намерений MEDIA_BUTTON
. :
<receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
BroadcastReceiver
пересылает намерение в вашу службу. Чтобы проанализировать намерение и сгенерировать обратный вызов для вашего медиа-сеанса, включите метод MediaButtonReceiver.handleIntent()
в onStartCommand()
вашего сервиса. Это преобразует код ключа в соответствующий метод обратного вызова сеанса.
Котлин
private val mediaSessionCompat: MediaSessionCompat = ... override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { MediaButtonReceiver.handleIntent(mediaSessionCompat, intent) return super.onStartCommand(intent, flags, startId) }
Ява
private MediaSessionCompat mediaSessionCompat = ...; public int onStartCommand(Intent intent, int flags, int startId) { MediaButtonReceiver.handleIntent(mediaSessionCompat, intent); return super.onStartCommand(intent, flags, startId); }
Использование кнопок мультимедиа для перезапуска неактивного сеанса мультимедиа
Если Android может определить последний активный сеанс мультимедиа, он пытается перезапустить сеанс, отправив намерение ACTION_MEDIA_BUTTON
компоненту, зарегистрированному в манифесте (например, службе или BroadcastReceiver
).
Это позволит вашему приложению перезапустить воспроизведение, пока его пользовательский интерфейс не виден, что характерно для большинства аудиоприложений.
Это поведение автоматически включается при использовании MediaSessionCompat
. Если вы используете MediaSession
или библиотеку поддержки платформы Android версий 24.0.0–25.1.1, вам необходимо вызвать setMediaButtonReceiver
, чтобы позволить кнопке мультимедиа перезапустить неактивный сеанс мультимедиа.
Вы можете отключить это поведение в Android 5.0 (уровень API 21) и более поздних версиях, установив для приемника нулевой медиа-кнопки:
Котлин
// Create a MediaSessionCompat mediaSession = MediaSessionCompat(context, LOG_TAG) mediaSession.setMediaButtonReceiver(null)
Ява
// Create a MediaSessionCompat mediaSession = new MediaSessionCompat(context, LOG_TAG); mediaSession.setMediaButtonReceiver(null);
Настройка обработчиков медиа-кнопок
Поведение по умолчанию для onMediaButtonEvent()
извлекает код ключа и использует текущее состояние медиа-сеанса и список поддерживаемых действий, чтобы определить, какой метод вызывать. Например, KEYCODE_MEDIA_PLAY
вызывает onPlay()
.
Чтобы обеспечить единообразную работу мультимедийных кнопок во всех приложениях, вам следует использовать поведение по умолчанию и отклоняться от него только для определенной цели. Если медиа-кнопке требуется специальная обработка, переопределите метод обратного вызова onMediaButtonEvent()
, извлеките KeyEvent
с помощью intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)
, обработайте событие самостоятельно и верните true
.
Краткое содержание
Чтобы правильно обрабатывать события мультимедийных кнопок во всех версиях Android, вы должны указать FLAG_HANDLES_MEDIA_BUTTONS
при создании мультимедийного сеанса.
Кроме того, в зависимости от версий Android, которые вы планируете поддерживать, вы также должны соответствовать следующим требованиям:
При работе в Android 5.0 или более поздней версии:
- Вызовите
MediaControllerCompat.setMediaController()
из обратного вызова медиаконтроллераonConnected()
- Чтобы разрешить медиа-кнопке перезапустить неактивный сеанс, динамически создайте
MediaButtonReceiver
вызвавsetMediaButtonReceiver()
и передав емуPendingIntent
.
При работе в системах более ранних версий, чем Android 5.0:
- Переопределить
onKeyDown()
активности для обработки мультимедийных кнопок. - Статически создайте
MediaButtonReceiver
, добавив его в манифест приложения.