Novos controles de mídia

O Android 11 atualiza a forma como os controles de mídia são exibidos, usando as APIs MediaSession e MediaRouter2 para renderizar controles e informações de saída de áudio.

Os controles de mídia no Android 11 estão localizados perto das Configurações rápidas. As sessões de vários apps são organizadas em um carrossel deslizante. O carrossel lista as sessões nesta ordem:

  • streams reproduzidos localmente no smartphone;
  • streams remotos, como aqueles detectados em dispositivos externos ou sessões de transmissão;
  • sessões retomáveis anteriores, na ordem em que foram reproduzidas pela última vez.

Os usuários podem reiniciar as sessões anteriores a partir do carrossel sem precisar iniciar o app. Quando a reprodução começar, o usuário interagirá com os controles de mídia da maneira habitual. algum texto

Compatibilidade com retomada de reprodução

Para usar esse recurso, é necessário ativar a Retomada de mídia nas configurações de "Opções do desenvolvedor".

Para que o app do player apareça na área de configurações rápidas, você precisa criar uma notificação MediaStyle com um token MediaSession válido.

Para exibir o ícone de marca do player de mídia, use NotificationBuilder.setSmallIcon().

Para compatibilidade com a retomada de reprodução, os apps precisam implementar um MediaBrowserService e um MediaSession.

Implementação de MediaBrowserService

Depois que o dispositivo for inicializado, o sistema procurará os cinco apps de mídia mais recentes e fornecerá controles que podem ser usados para reiniciar a reprodução de cada app.

O sistema tentará entrar em contato com o MediaBrowserService com uma conexão da SystemUI. Seu app precisa permitir essas conexões. Caso contrário, não será possível retomar a reprodução.

As conexões da SystemUI podem ser identificadas e verificadas usando o nome do pacote com.android.systemui e a assinatura. A SystemUI tem a assinatura da plataforma. Um exemplo de como verificar a assinatura da plataforma pode ser encontrado no app UAMP.

Para compatibilidade com a retomada de reprodução, seu MediaBrowserService precisa implementar estes comportamentos:

  • onGetRoot() precisa retornar uma raiz não nula rapidamente. Outra lógica complexa precisa ser tratada em onLoadChildren()

  • Quando onLoadChildren() é chamado no ID de mídia raiz, o resultado precisa conter um filho FLAG_PLAYABLE.

  • MediaBrowserService precisa retornar o item de mídia reproduzido mais recentemente quando receber uma consulta EXTRA_RECENT. O valor retornado precisa ser um item de mídia real em vez de uma função genérica.

  • MediaBrowserService precisa fornecer uma MediaDescription apropriada com um título e uma legenda não vazios. Ele também precisa definir um URI de ícone ou um bitmap de ícone.

Os exemplos de código a seguir ilustram como implementar onGetRoot().

Kotlin

override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle?
): BrowserRoot? {
    ...
    // Verify that the specified package is SystemUI. You'll need to write your
    // own logic to do this.
    if (isSystem(clientPackageName, clientUid)) {
        rootHints?.let {
            if (it.getBoolean(BrowserRoot.EXTRA_RECENT)) {
                // Return a tree with a single playable media item for resumption.
                return BrowserRoot(MY_RECENTS_ROOT_ID, null)
            }
        }
        // You can return your normal tree if the EXTRA_RECENT flag is not present.
        return BrowserRoot(MY_MEDIA_ROOT_ID, null)
    }
    // Return an empty tree to disallow browsing.
    return BrowserRoot(MY_EMPTY_ROOT_ID, null)

Java

@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
    Bundle rootHints) {
    ...
    // Verify that the specified package is SystemUI. You'll need to write your
    // own logic to do this.
    if (isSystem(clientPackageName, clientUid)) {
        if (rootHints != null) {
            if (rootHints.getBoolean(BrowserRoot.EXTRA_RECENT)) {
                // Return a tree with a single playable media item for resumption.
                return new BrowserRoot(MY_RECENTS_ROOT_ID, null);
            }
        }
        // You can return your normal tree if the EXTRA_RECENT flag is not present.
        return new BrowserRoot(MY_MEDIA_ROOT_ID, null);
    }
    // Return an empty tree to disallow browsing.
    return new BrowserRoot(MY_EMPTY_ROOT_ID, null);
}

Implementação de MediaSession

O sistema recupera as seguintes informações do MediaMetadata do MediaSession e as exibe quando estão disponíveis:

  • METADATA_KEY_ALBUM_ART_URI
  • METADATA_KEY_TITLE
  • METADATA_KEY_ARTIST
  • METADATA_KEY_DURATION: se a duração não for definida, a barra de busca não mostrará o progresso.

Para compatibilidade com a retomada de reprodução, seu MediaSession precisa implementar um callback MediaSession para onPlay().

O player de mídia mostra o tempo decorrido da mídia em reprodução no momento com uma barra de busca mapeada para o MediaSession PlaybackState.

Para que a barra de busca funcione corretamente, você precisa implementar PlaybackState.Builder#setActions e incluir ACTION_SEEK_TO. Caso contrário, o player mostrará apenas o tempo decorrido e a duração.

Para definir os controles do player, use Notification.Builder#setCustomActions. Somente as ações indicadas com Notification.MediaStyle#setShowsActionsInCompactView serão exibidas no player de mídia que aparece nas configurações rápidas recolhidas.