Os botões de mídia são botões de hardware encontrados em dispositivos Android e outros dispositivos periféricos, por exemplo, o botão de pausa/reprodução em um fone de ouvido Bluetooth. Quando um usuário pressiona um botão de mídia, o Android gera um KeyEvent
, que contém um código de tecla que identifica o botão. Os códigos de tecla para KeyEvents de mídia são constantes que começam com KEYCODE_MEDIA
(por exemplo, KEYCODE_MEDIA_PLAY
).
Os aplicativos devem ser capazes de processar eventos de botão de mídia em três casos, nesta ordem de prioridade:
- quando a atividade da IU do app estiver visível;
- quando a atividade da IU estiver oculta, e a sessão de mídia do app estiver ativa;
- quando a atividade da IU estiver oculta, e a sessão de mídia do app estiver inativa e precisar ser reiniciada.
Como processar botões de mídia em uma atividade em primeiro plano
A atividade em primeiro plano recebe o evento de tecla do botão de mídia na onKeyDown()
.
. Dependendo da versão em execução do Android, o sistema pode direcionar o evento de duas maneiras para
um controlador de mídia:
- Se você estiver executando o Android 5.0 (nível 21 da API) ou mais recente, chame
FLAG_HANDLES_MEDIA_BUTTONS
MediaBrowserCompat.ConnectionCallback.onConnected
. Isso vai chamar automaticamente o métododispatchMediaButtonEvent()
, que converte o código de tecla em um callback de sessão de mídia. - Em versões anteriores ao Android 5.0 (nível 21 da API), é necessário modificar
onKeyDown()
para processar o evento. Consulte Como processar botões de mídia em uma sessão de mídia ativa para ver mais detalhes. O snippet de código a seguir mostra como interceptar e chamar DispatcherMediaButtonEvent(). Devolvatrue
para indicam que o evento foi tratado: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); }
Como encontrar uma sessão de mídia
Se a atividade em primeiro plano não processar o evento, o Android tentará encontrar uma sessão de mídia que pode lidar com isso. Novamente, dependendo da versão em execução do Android, há duas maneiras de pesquisar uma sessão de mídia:
Se você estiver executando o Android 8.0 (API de nível 26) ou posterior, o sistema tentará encontre o último app com uma MediaSession que reproduziu áudio localmente. Se a sessão ainda estiver ativo, o Android enviará o evento diretamente para ele. Caso contrário, se o sessão não está ativa e tem um receptor de botão de mídia, o Android envia o evento ao receptor, que reiniciará a sessão e poderá receber o evento. Consulte Como usar botões de mídia para reiniciar uma sessão de mídia inativa para ver detalhes. Se a sessão não tiver um receptor de botão de mídia, o sistema descartará a mídia e nada acontecerá. A lógica é mostrada diagrama:
Em versões anteriores ao Android 8.0 (API de nível 26), o sistema tenta enviar o evento para uma sessão de mídia ativa. Se houver várias sessões de mídia ativas, o Android tentará para escolher uma sessão de mídia que está se preparando para reproduzir (armazenamento em buffer/conexão), em reprodução ou pausada, em vez de uma que esteja interrompida. Consulte Como gerenciar botões de mídia em uma sessão de mídia ativa para mais detalhes. Se não houver o Android tentará enviar o evento para a sessão ativa mais recente. Consulte Como usar botões de mídia para reiniciar uma sessão de mídia inativa para ver detalhes. A lógica é mostrada no diagrama a seguir.
Como processar botões de mídia em uma sessão de mídia ativa
No Android 5.0 (nível 21 da API) e versões mais recentes, o Android envia automaticamente eventos do botão de mídia para a sessão de mídia ativa chamando
onMediaButtonEvent()
:
Por padrão, esse chamado converte o KeyEvent no método de callback de sessão de mídia apropriado que corresponde ao código de tecla.
Antes do Android 5.0 (API de nível 21), o Android processa eventos de botão de mídia transmitindo uma intent
com a ação ACTION_MEDIA_BUTTON
. Seu app precisa registrar um
BroadcastReceiver para interceptar essas intents. A
MediaButtonReceiver
foi criada especificamente para
para esse propósito. É uma classe de conveniência no
No Android
media-compatibilidade, que
processa ACTION_MEDIA_BUTTON
e traduz as intents recebidas para o
chamadas de método MediaSessionCompat.Callback
adequadas.
Um MediaButtonReceiver
é um BroadcastReceiver de curta duração. Ele encaminha mensagens
intents para o serviço que está gerenciando sua sessão de mídia. Se você quiser usar
de mídia em sistemas anteriores ao Android 5.0, é necessário incluir
o MediaButtonReceiver
no manifesto com um filtro de intent MEDIA_BUTTON
:
<receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
O BroadcastReceiver
encaminha o intent para o serviço. Para analisar a intent
e gerar o callback para a sessão de mídia, inclua o método MediaButtonReceiver.handleIntent()
no onStartCommand()
do serviço.
Isso converte o código de tecla em um método apropriado de callback de sessão.
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); }
Como usar botões de mídia para reiniciar uma sessão de mídia inativa
Se o Android puder identificar a última sessão de mídia ativa, ele tentará reiniciar a sessão enviando um Intent ACTION_MEDIA_BUTTON
para um componente registrado pelo manifesto (como um serviço ou BroadcastReceiver
).
Isso permite que o app reinicie a reprodução enquanto a IU não estiver visível, como é o caso da maioria dos apps de áudio.
Esse comportamento é ativado automaticamente quando você usa MediaSessionCompat
. Se você
usar a MediaSession
do framework do Android ou a Biblioteca de Suporte 24.0.0 até
25.1.1, você precisa chamar setMediaButtonReceiver
para permitir que um botão de mídia reinicie uma
sessão de mídia inativa.
Para desativar esse comportamento no Android 5.0 (nível 21 da API) e versões mais recentes, definindo um receptor de botão de mídia 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);
Como personalizar gerenciadores de botão de mídia
O comportamento padrão de onMediaButtonEvent()
extrai o código da tecla e usa o estado atual da sessão de mídia e a lista de ações compatíveis para determinar qual método chamar. Por exemplo, KEYCODE_MEDIA_PLAY
invoca onPlay()
.
Para oferecer uma experiência consistente de botão de mídia em todos os apps, use o
comportamento padrão e desviam apenas para uma finalidade específica. Se um botão de mídia
precisa de tratamento personalizado, substitua o método
onMediaButtonEvent()
extraia o KeyEvent
usando
intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)
,
processar o evento e retornar true
.
Resumo
Para processar corretamente os eventos do botão de mídia em todas as versões do Android, é necessário
especificar FLAG_HANDLES_MEDIA_BUTTONS
ao criar uma sessão de mídia.
Além disso, dependendo das versões do Android com as quais você pretende oferecer suporte, você também precisa atender a estes requisitos:
Ao executar no Android 5.0 ou versões posteriores:
- Chame
MediaControllerCompat.setMediaController()
do callback do controlador de mídiaonConnected()
- Para permitir que um botão de mídia reinicie uma sessão inativa, crie dinamicamente um
MediaButtonReceiver
chamandosetMediaButtonReceiver()
e transmitindo umPendingIntent
Ao executar em sistemas anteriores ao Android 5.0:
- Substitua o
onKeyDown()
da atividade para gerenciar botões de mídia - Crie estaticamente um
MediaButtonReceiver
adicionando-o ao manifesto do app