Juega bien con los controles multimedia

Publicado por Don Turner – Defensor del desarrollador – Android Media

Androide

En Android 11, hemos facilitado más que nunca a los usuarios el control de la reproducción de medios. Esto se logra con tres funciones relacionadas: controles multimedia, reanudación de la reproducción y transferencia perfecta.

Este artículo explicará cuáles son estas funciones, cómo funcionan juntas y cómo puede aprovecharlas en sus aplicaciones.

Los controles de medios de Android 11 se encuentran debajo del panel de Configuración rápida y representan un espacio persistente dedicado para controlar la reproducción de medios.

Promedio

Controles multimedia en Android 11

Parte del fundamento de los controles de medios es que los usuarios a menudo tienen múltiples aplicaciones de medios (reproductor de música, podcast, reproductor de video, etc.) y cambian entre ellas con regularidad. Los controles multimedia muestran hasta cinco sesiones multimedia actuales y recientes en un carrusel, lo que permite al usuario desplazarse por ellas.

En Android 10 y versiones anteriores, las notificaciones multimedia para varias aplicaciones pueden ocupar la mayor parte del área de notificación. Todos esos botones de control también pueden resultar confusos. Mover los controles a un espacio dedicado significa que hay más espacio para otras notificaciones y proporciona una experiencia de usuario más consistente para controlar aplicaciones multimedia.

Aquí está la comparación:

Imagen

captura de pantalla

Notificaciones multimedia de Android 10 (izquierda) Controles multimedia de Android 11 (derecha)

Ver controles de medios para su aplicación

Ahora, las realmente buenas noticias. Mientras esté usando MediaStyle con una valida MediaSession tokens (ambos disponibles en Lollipop API 21), los controles de medios aparecerán automáticamente para su aplicación, ¡sin trabajo adicional para usted!

En caso de que no use un MediaStyle es MediaSession aquí hay un breve resumen en el código:

// Create a media session. NotificationCompat.MediaStyle
// PlayerService is your own Service or Activity responsible for media playback.  
val mediaSession = MediaSessionCompat(this, "PlayerService")

// Create a MediaStyle object and supply your media session token to it. 
val mediaStyle = Notification.MediaStyle().setMediaSession(mediaSession.sessionToken)

// Create a Notification which is styled by your MediaStyle object. 
// This connects your media session to the media controls. 
// Don't forget to include a small icon.
val notification = Notification.Builder(this@PlayerService, CHANNEL_ID)
            .setStyle(mediaStyle)
            .setSmallIcon(R.drawable.ic_app_logo)
            .build()

// Specify any actions which your users can perform, such as pausing and skipping to the next track. 
val pauseAction: Notification.Action = Notification.Action.Builder(
            pauseIcon, "Pause", pauseIntent
        ).build()
notification.addAction(pauseAction)

El pequeño icono y el nombre de la aplicación aparecen en la parte superior izquierda de los controles multimedia. Las acciones se muestran en la parte inferior central.

Paginación

Interfaz de usuario de controles multimedia y campos de notificación correspondientes

El resto de los campos de la interfaz de usuario, como el título de la pista y la posición de reproducción, se obtienen de los metadatos de la sesión multimedia y el estado de reproducción.

A continuación, se explica cómo se asignan los campos de metadatos a la interfaz de usuario.

mediaSession.setMetadata(
    MediaMetadataCompat.Builder()
        
        // Title. 
        .putString(MediaMetadata.METADATA_KEY_TITLE, currentTrack.title)

        // Artist. 
        // Could also be the channel name or TV series.
        .putString(MediaMetadata.METADATA_KEY_ARTIST, currentTrack.artist)
        
        // Album art. 
        // Could also be a screenshot or hero image for video content
        // The URI scheme needs to be "content", "file", or "android.resource".
        .putString(
            MediaMetadata.METADATA_KEY_ALBUM_ART_URI, currentTrack.albumArtUri)
        )

        // Duration. 
        // If duration isn't set, such as for live broadcasts, then the progress
        // indicator won't be shown on the seekbar.
        .putLong(MediaMetadata.METADATA_KEY_DURATION, currentTrack.duration) // 4

        .build()
)

Esta captura de pantalla muestra cómo se muestran estos campos de metadatos en los controles multimedia.

metadatos

Los medios controlan la interfaz de usuario y los campos de metadatos correspondientes.

La barra de búsqueda se actualiza usando el estado de reproducción de la sesión multimedia de una manera similar:

mediaSession.setPlaybackState(
    PlaybackStateCompat.Builder()
        .setState(
            PlaybackStateCompat.STATE_PLAYING,
                        
            // Playback position.
            // Used to update the elapsed time and the progress bar. 
            mediaPlayer.currentPosition.toLong(), 
                        
            // Playback speed. 
            // Determines the rate at which the elapsed time changes. 
            playbackSpeed
        )

        // isSeekable. 
        // Adding the SEEK_TO action indicates that seeking is supported 
        // and makes the seekbar position marker draggable. If this is not 
        // supplied seek will be disabled but progress will still be shown.
        .setActions(PlaybackStateCompat.ACTION_SEEK_TO)
        .build()
)

Esta pantalla muestra cómo se muestran estos campos de estado de reproducción en los controles multimedia.

Los medios controlan la interfaz de usuario y los campos de estado de reproducción correspondientes

¡Sus controles multimedia ahora deberían verse y funcionar perfectamente!

¿Alguna vez has querido seguir escuchando un podcast, un episodio de televisión o un set de DJ pero no recuerdas dónde lo dejaste, o incluso la aplicación que lo estaba reproduciendo? La cobertura de los medios resuelve este problema.

Hay dos etapas para la reanudación de los medios: descubrir aplicaciones multimedia recientes es reanudar la reproducción.

Descubriendo aplicaciones multimedia recientes

Después del lanzamiento, Android buscará aplicaciones multimedia recientes y les preguntará qué contenido se reprodujo más recientemente. Luego, creará controles de medios para ese contenido.

Para ser detectable, su aplicación debe proporcionar un MediaBrowserService, normalmente utilizando el MediaBrowserServiceCompat biblioteca de Android Jetpack.

Al iniciarse, Android llamará a su MediaBrowserServiceCompat onGetRoot método, por lo que es imperativo regresar rápidamente. Por lo general, devolvería la raíz de su árbol de medios de este método, pero el sistema también especifica el archivo EXTRA_RECENT sugerencia.

Deberías tratar EXTRA_RECENT como un caso especial y en su lugar devuelve la raíz de un árbol de medios que contiene el elemento multimedia reproducido más recientemente como primer elemento.

El sistema llamará al tuyo onLoadChildren método para obtener este árbol multimedia, que es una lista de archivos MediaItem objetos.

A continuación, se muestra un diagrama que muestra cómo interactúan el sistema y una aplicación multimedia para recuperar el elemento reproducido más recientemente.

Cómo el sistema recupera el elemento reproducido más recientemente de MediaBrowserService

Para los primeros medios reproducibles en esta lista, el sistema creará controles de medios estáticos con un simple botón de reproducción.

estático

Controles de medios estáticos

No se ha creado ninguna sesión multimedia en este momento. Esto es para ahorrar recursos: el sistema no sabe si el usuario Realmente quiero para reanudar la reproducción de ese contenido nuevamente.

Reanudar la reproducción

Si el usuario toca el botón de reproducción, el sistema realizará otra llamada onGetRoot con el EXTRA_RECENT sugerencia. De esta manera puede preparar el contenido reproducido anteriormente como antes, en caso de que algo haya cambiado desde que se crearon los controles estáticos.

Luego, Android se conectará a la sesión multimedia y le enviará un comando de reproducción. Deberías sobrescribir la sesión multimedia onPlay devolución de llamada para comenzar a reproducir sus medios y crear los suyos MediaStyle notificación.

Después de publicar la notificación, los controles de medios estáticos se intercambiarán con los controles de medios creados por la notificación.

Gráfico

Figura 7: Diagrama que muestra la interacción entre la interfaz de usuario del sistema y la aplicación multimedia al reanudar la reproducción

Además de poder reanudar las sesiones multimedia, Android 11 también te permite transferir fácilmente la reproducción de un dispositivo a otro. Esto se conoce como “transferencia de medios sin interrupciones” y se realiza mediante interruptor de salida. El selector de salida se muestra en la esquina superior derecha de la notificación multimedia que aparece a continuación.

gráfico

Interruptor de salida (esquina superior derecha)

El selector de salida muestra el nombre y el icono de la ruta de medios actual; y cuando lo toque, verá una lista de rutas de medios compatibles con esta aplicación.

Imagen

Rutas de medios disponibles para la aplicación actual

De forma predeterminada, solo se muestran las rutas de medios locales. Si su aplicación admite otras rutas de medios, como el uso a distancia, deberá notificar al sistema.

Para hacer esto, agregue la biblioteca de jetpack de MediaRouter a su aplicación.

dependencies {
    implementation 'androidx.mediarouter:mediarouter:1.2.0-alpha02'`
}

La transferencia de medios sin problemas es compatible con 1.2.0-alpha02.

Luego, agregue el archivo MediaTransferReceiver class a su manifiesto de Android.

<receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />

Ahora en su aplicación, obtenga el MediaRouter singleton: este es un objeto que mantiene el estado de todas las rutas de medios disponibles actualmente.

router = MediaRouter.getInstance(this)

Crear un MediaRouteSelector y especifique las categorías de rutas admitidas por su aplicación. Las categorías definidas aquí determinan las rutas que se muestran en el selector de salida.

Aquí especificaremos solo la categoría de “reproducción remota” utilizada para dispositivos de transmisión.

routeSelector = MediaRouteSelector.Builder() // Add control categories that this media app is interested in.
            .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
            .build()

Si desea admitir la transferencia de dispositivos remotos a dispositivos locales, debe habilitarla explícitamente usando setTransferToLocalEnabled:

router.routerParams = MediaRouterParams.Builder().setTransferToLocalEnabled(true).build()

Ahora podemos usar nuestro selector al agregar un enrutador de medios recuerda.

router.addCallback(routeSelector, MediaRouterCallback(),
             MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);

También proporcionamos un objeto de devolución de llamada para que podamos ser notificados de los cambios en las rutas de medios.

Aquí está la clase de devolución de llamada:

    private class MediaRouterCallback : MediaRouter.Callback() {
        override fun onRouteSelected(
            router: MediaRouter,
            route: MediaRouter.RouteInfo,
            reason: Int
        ) {
            if (reason == MediaRouter.UNSELECT_REASON_ROUTE_CHANGED) {
                Timber.d("Unselected because route changed, continue playback")
            } else if (reason == MediaRouter.UNSELECT_REASON_STOPPED) {
                Timber.d("Unselected because route was stopped, stop playback")
            }
        }
    }

El método que sustituimos es onRouteSelected que se llamará cada vez que se seleccione una nueva ruta de medios.

Cuando esto suceda, debemos tenerlo en cuenta porque has sido seleccionado.

Si se desconectaba la ruta existente (por ejemplo, se apagaban los auriculares bluetooth) deberíamos pausar o detener la reproducción.

Si la ruta se ha cambiado activamente, por ejemplo, al cambiar de un teléfono a un dispositivo de transmisión, debe continuar reproduciendo el archivo multimedia desde la posición de reproducción anterior; esta es la parte “sin interrupciones” de la “transferencia de medios sin interrupciones “:)

Para comenzar con los controles multimedia y las funciones relacionadas en Android 11, consulte la documentación oficial. También asegúrese de consultar UAMP, que contiene una implementación de referencia para muchas de las características mencionadas en este artículo.

¡Buena suerte y recuerda jugar bien!



Compruebe también

en vivo desde Droidcon, incluida la mayor actualización de Gemini en Android Studio y más lanzamientos del SDK de Android.

Acabamos de lanzar nuestro episodio de otoño de #TheAndroidShow en YouTube etcétera desarrollador.android.comy esta vez …

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *