Os apps de TV precisam exibir um card Tocando agora ao reproduzir mídia por trás da tela de início ou em segundo plano. Esse card permite que os usuários voltem ao app que está reproduzindo mídia.
O framework do Android exibe um card Tocando agora na tela inicial quando há uma MediaSession
ativa.
O card inclui metadados de mídia, como a capa do álbum, o título e um ícone do app.
Quando o usuário seleciona esse card, o sistema abre o app.
Esta lição mostra como usar a classe MediaSession
para implementar o card Tocando agora.

Figura 1. Exiba um card Tocando agora ao reproduzir mídia em segundo plano.
Iniciar uma sessão de mídia
Crie uma MediaSession
quando seu app estiver se preparando para reproduzir mídia. O snippet de código a seguir é um exemplo de como definir apropriadamente o callback e os sinalizadores:
Kotlin
session = MediaSession(this, "MusicService").apply { setCallback(MediaSessionCallback()) setFlags( MediaSession.FLAG_HANDLES_MEDIA_BUTTONS or MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS ) }
Java
session = new MediaSession(this, "MusicService"); session.setCallback(new MediaSessionCallback()); session.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
Observação: o card Tocando agora será exibido somente para uma sessão de mídia com a sinalização FLAG_HANDLES_TRANSPORT_CONTROLS
definida.
Exibir um card "Tocando agora"
O card Tocando agora aparece apenas para sessões ativas. Você precisa chamar setActive(true)
quando a reprodução começar. Seu app também precisa solicitar seleção de áudio, conforme descrito em Gerenciar seleção de áudio.
Kotlin
private fun handlePlayRequest() { tryToGetAudioFocus() if (!session.isActive) { session.isActive = true } ... }
Java
private void handlePlayRequest() { tryToGetAudioFocus(); if (!session.isActive()) { session.setActive(true); } ... }
O card será removido da tela de início quando uma chamada setActive(false)
desativar a sessão de mídia ou quando outro app iniciar a reprodução.
Se a reprodução for completamente interrompida e não houver mídia ativa, o app desativará a sessão de mídia imediatamente.
Se a reprodução for pausada, o app desativará a sessão de mídia após um atraso, geralmente de 5 a 30 minutos.
Atualizar o estado da reprodução
Atualize o estado da reprodução na MediaSession
para que o card mostre o estado da mídia atual.
Kotlin
private fun updatePlaybackState() { val position: Long = mediaPlayer ?.takeIf { it.isPlaying } ?.currentPosition?.toLong() ?: PlaybackState.PLAYBACK_POSITION_UNKNOWN val stateBuilder = PlaybackState.Builder() .setActions(getAvailableActions()).apply { setState(mState, position, 1.0f) } session.setPlaybackState(stateBuilder.build()) } private fun getAvailableActions(): Long { var actions = (PlaybackState.ACTION_PLAY_PAUSE or PlaybackState.ACTION_PLAY_FROM_MEDIA_ID or PlaybackState.ACTION_PLAY_FROM_SEARCH) playingQueue?.takeIf { it.isNotEmpty() }?.apply { actions = if (mState == PlaybackState.STATE_PLAYING) { actions or PlaybackState.ACTION_PAUSE } else { actions or PlaybackState.ACTION_PLAY } if (currentIndexOnQueue > 0) { actions = actions or PlaybackState.ACTION_SKIP_TO_PREVIOUS } if (currentIndexOnQueue < size - 1) { actions = actions or PlaybackState.ACTION_SKIP_TO_NEXT } } return actions }
Java
private void updatePlaybackState() { long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN; if (mediaPlayer != null && mediaPlayer.isPlaying()) { position = mediaPlayer.getCurrentPosition(); } PlaybackState.Builder stateBuilder = new PlaybackState.Builder() .setActions(getAvailableActions()); stateBuilder.setState(mState, position, 1.0f); session.setPlaybackState(stateBuilder.build()); } private long getAvailableActions() { long actions = PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_PLAY_FROM_MEDIA_ID | PlaybackState.ACTION_PLAY_FROM_SEARCH; if (playingQueue == null || playingQueue.isEmpty()) { return actions; } if (mState == PlaybackState.STATE_PLAYING) { actions |= PlaybackState.ACTION_PAUSE; } else { actions |= PlaybackState.ACTION_PLAY; } if (currentIndexOnQueue > 0) { actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS; } if (currentIndexOnQueue < playingQueue.size() - 1) { actions |= PlaybackState.ACTION_SKIP_TO_NEXT; } return actions; }
Exibir os metadados da mídia
Defina MediaMetadata
com o método setMetadata()
. Esse método do objeto da sessão de mídia permite fornecer informações ao card Tocando agora sobre a faixa, como título, subtítulo e diversos ícones. O exemplo seguinte supõe que os dados da faixa estejam armazenados em uma classe de dados personalizados, MediaData
.
Kotlin
private fun updateMetadata(myData: MediaData) { val metadataBuilder = MediaMetadata.Builder().apply { // To provide most control over how an item is displayed set the // display fields in the metadata putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, myData.displayTitle) putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, myData.displaySubtitle) putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, myData.artUri) // And at minimum the title and artist for legacy support putString(MediaMetadata.METADATA_KEY_TITLE, myData.title) putString(MediaMetadata.METADATA_KEY_ARTIST, myData.artist) // A small bitmap for the artwork is also recommended putBitmap(MediaMetadata.METADATA_KEY_ART, myData.artBitmap) // Add any other fields you have for your data as well } session.setMetadata(metadataBuilder.build()) }
Java
private void updateMetadata(MediaData myData) { MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder(); // To provide most control over how an item is displayed set the // display fields in the metadata metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, myData.displayTitle); metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, myData.displaySubtitle); metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, myData.artUri); // And at minimum the title and artist for legacy support metadataBuilder.putString(MediaMetadata.METADATA_KEY_TITLE, myData.title); metadataBuilder.putString(MediaMetadata.METADATA_KEY_ARTIST, myData.artist); // A small bitmap for the artwork is also recommended metadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_ART, myData.artBitmap); // Add any other fields you have for your data as well session.setMetadata(metadataBuilder.build()); }
Responder à ação do usuário
Quando o usuário seleciona o card Tocando agora, o sistema abre o app dono da sessão.
Se o app fornecer um PendingIntent
para setSessionActivity()
, o sistema iniciará a atividade especificada, conforme demonstrado abaixo. Caso contrário, o intent padrão do sistema será aberto. A atividade especificada precisa oferecer controles de reprodução que permitam aos usuários pausar ou interromper a reprodução.
Kotlin
val pi: PendingIntent = Intent(context, MyActivity::class.java).let { intent -> PendingIntent.getActivity( context, 99 /*request code*/, intent, PendingIntent.FLAG_UPDATE_CURRENT ) } session.setSessionActivity(pi)
Java
Intent intent = new Intent(context, MyActivity.class); PendingIntent pi = PendingIntent.getActivity(context, 99 /*request code*/, intent, PendingIntent.FLAG_UPDATE_CURRENT); session.setSessionActivity(pi);