Los botones de medios son botones de hardware que se encuentran en dispositivos Android y otros dispositivos periféricos, por ejemplo, el botón de pausa/reproducción en auriculares Bluetooth. Cuando un usuario presiona un botón de medios, Android genera un KeyEvent
, que contiene un código de tecla que identifica el botón. Los códigos de tecla para los KeyEvents del botón de medios son constantes que comienzan con KEYCODE_MEDIA
(por ejemplo, KEYCODE_MEDIA_PLAY
).
Las apps deben poder controlar los eventos de botones multimedia en tres casos, en el orden de prioridad:
- Cuando la actividad de la IU de la app es visible
- Cuando la actividad de la IU está oculta y la sesión multimedia de la app está activa
- Cuando la actividad de IU está oculta y la sesión multimedia de la app está inactiva y debe reiniciarse
Cómo manejar los botones de medios en una actividad en primer plano
La actividad en primer plano recibe el evento de tecla del botón multimedia en su onKeyDown()
.
. Según la versión de ejecución de Android, el sistema enruta el evento de dos formas
un controlador multimedia:
- Si ejecutas Android 5.0 (nivel de API 21) o una versión posterior, llama
FLAG_HANDLES_MEDIA_BUTTONS
MediaBrowserCompat.ConnectionCallback.onConnected
Si confirmas esta acción, llamar automáticamente al controlador de contenido multimediadispatchMediaButtonEvent()
, que traduce el código de tecla a una devolución de llamada de sesión multimedia. - En versiones anteriores a Android 5.0 (nivel de API 21), debes modificar
onKeyDown()
para que maneje el evento por tu cuenta. (Obtén más información en Cómo manejar los botones de medios en una sesión multimedia activa). En el siguiente fragmento de código, se muestra cómo interceptar el código de tecla y llama a distribuMediaButtonEvent(). Asegúrate de devolvertrue
a indican que el evento se gestionó:Kotlin
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) }
Java
@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); }
Cómo encontrar una sesión multimedia
Si la actividad en primer plano no controla el evento, Android intentará encontrar un con una sesión multimedia que pueda controlarlo. Dependiendo de la versión en ejecución de En Android, existen dos maneras de buscar una sesión multimedia:
Si estás ejecutando Android 8.0 (nivel de API 26) o una versión posterior, el sistema intenta Buscar la última app con una MediaSession que reprodujo audio de forma local Si la sesión sigue activo. Android le envía el evento directamente. De lo contrario, si la sesión no está activa y tiene un receptor mediabutton, Android envía el evento al receptor, lo que reiniciará la sesión para que pueda recibir el evento. (Obtén más información en Cómo usar los botones de medios para reiniciar una sesión multimedia inactiva). Si la sesión no tiene un receptor de botones de medios, el sistema lo descarta. evento de botón y no sucederá nada. La lógica se muestra en el siguiente ejemplo: diagrama:
En versiones anteriores a Android 8.0 (nivel de API 26), el sistema intenta enviar el evento a un durante la sesión multimedia activa. Si hay varias sesiones multimedia activas, Android intenta para elegir una sesión multimedia que se esté preparando para reproducir (almacenando en búfer/conectando) en reproducción o en pausa, en lugar de uno que se detiene. (Consulta Cómo manejar los botones de medios en una sesión multimedia activa para obtener más información). Si no hay activos , Android intenta enviar el evento a la sesión activa más reciente. (Obtén más información en Cómo usar los botones de medios para reiniciar una sesión multimedia inactiva). La lógica se muestra en el siguiente diagrama:
Cómo manejar botones de medios en una sesión multimedia activa
En Android 5.0 (nivel de API 21) y versiones posteriores, Android envía automáticamente eventos de botones de medios a tu sesión multimedia activa con una llamada a
onMediaButtonEvent()
De forma predeterminada, esta devolución de llamada convierte el KeyEvent en el método apropiado de devolución de llamada de la sesión multimedia que coincide con el código de tecla.
En versiones anteriores a Android 5.0 (nivel de API 21), Android maneja los eventos de botones multimedia transmitiendo un intent.
con la acción ACTION_MEDIA_BUTTON
. Tu app debe registrar un
BroadcastReceiver para interceptar estos intents. El
MediaButtonReceiver
se diseñó específicamente para
con este propósito. Es una clase de conveniencia
En Android
biblioteca media-compat que
controla ACTION_MEDIA_BUTTON
y traduce los intents entrantes al
llamadas al método MediaSessionCompat.Callback
adecuadas.
Un MediaButtonReceiver
es un BroadcastReceiver de corta duración. Reenvía los mensajes entrantes
al servicio que administra tu sesión multimedia. Si quieres utilizar
botones multimedia en sistemas anteriores a Android 5.0, debes incluir
el MediaButtonReceiver
en tu manifiesto con un filtro de intents MEDIA_BUTTON
:
<receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
El BroadcastReceiver
reenvía el intent a tu servicio. Cómo analizar el intent
y generar la devolución de llamada a tu sesión multimedia, incluye el método MediaButtonReceiver.handleIntent()
en el onStartCommand()
de tu servicio.
Así, el código de tecla se convierte en el método de devolución de llamada de sesión adecuado.
Kotlin
private val mediaSessionCompat: MediaSessionCompat = ... override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { MediaButtonReceiver.handleIntent(mediaSessionCompat, intent) return super.onStartCommand(intent, flags, startId) }
Java
private MediaSessionCompat mediaSessionCompat = ...; public int onStartCommand(Intent intent, int flags, int startId) { MediaButtonReceiver.handleIntent(mediaSessionCompat, intent); return super.onStartCommand(intent, flags, startId); }
Cómo usar los botones de medios para reiniciar una sesión multimedia inactiva
Si Android puede identificar la última sesión multimedia activa, intentará reiniciar la sesión enviando un intent ACTION_MEDIA_BUTTON
a un componente registrado en el manifiesto (como un servicio o BroadcastReceiver
).
De este modo, tu app puede reiniciar la reproducción mientras su IU no está visible, como sucede con la mayoría de las apps de audio.
Este comportamiento se habilita automáticamente cuando usas MediaSessionCompat
. Si
usa el MediaSession
del framework de Android o la biblioteca de compatibilidad 24.0.0 hasta
25.1.1, debes llamar a setMediaButtonReceiver
para permitir que un botón de medios reinicie una
sesión multimedia inactiva.
Puedes inhabilitar este comportamiento en Android 5.0 (nivel de API 21) y versiones posteriores si haces lo siguiente: Configura un receptor de botón multimedia nulo:
Kotlin
// Create a MediaSessionCompat mediaSession = MediaSessionCompat(context, LOG_TAG) mediaSession.setMediaButtonReceiver(null)
Java
// Create a MediaSessionCompat mediaSession = new MediaSessionCompat(context, LOG_TAG); mediaSession.setMediaButtonReceiver(null);
Cómo personalizar los controladores de botones de medios
El comportamiento predeterminado para onMediaButtonEvent()
extrae el código de tecla y utiliza el estado actual de la sesión multimedia y la lista de acciones admitidas para determinar a qué método llamar. Por ejemplo, KEYCODE_MEDIA_PLAY
invoca a onPlay()
.
Para proporcionar una experiencia de botones multimedia coherente en todas las apps, debes usar
el comportamiento predeterminado y solo se desvía para un propósito específico. Si un botón multimedia
necesita un manejo personalizado, anula los campos
onMediaButtonEvent()
método, extrae KeyEvent
con
intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)
,
manejar el evento por tu cuenta y mostrar true
.
Resumen
Para manejar correctamente los eventos de botones de medios en todas las versiones de Android, debes hacer lo siguiente:
especificar FLAG_HANDLES_MEDIA_BUTTONS
cuando creas una sesión multimedia.
Además, según las versiones de Android que quieras admitir, también debes cumplir con estos requisitos:
Cuando uses Android 5.0 o versiones posteriores:
- Llama a
MediaControllerCompat.setMediaController()
desde la devolución de llamadaonConnected()
del controlador multimedia. - Para permitir que un botón de medios reinicie una sesión inactiva, crea un
MediaButtonReceiver
de forma dinámica llamando asetMediaButtonReceiver()
y pásale unPendingIntent
Cuando uses sistemas previos a Android 5.0:
- Anula el objeto
onKeyDown()
de la actividad para manejar botones de medios. - Crea un
MediaButtonReceiver
de forma estática agregándolo al manifiesto de la app.