Cómo compilar una app multimedia con plantillas

Las apps de música basadas en plantillas están en versión beta
Por el momento, cualquier persona puede publicar apps de música basadas en plantillas en los segmentos de pruebas internas y cerradas de Google Play Store. La publicación en segmentos abiertos y de producción se permitirá en una fecha posterior.

Las apps de música que usan las plantillas de la Biblioteca de apps para vehículos pueden personalizar su experiencia de exploración y reproducción de contenido multimedia, al mismo tiempo que se aseguran de que la experiencia esté optimizada para las pantallas de los automóviles y minimice las distracciones mientras se conduce.

En esta guía, se supone que ya tienes una app de música que reproduce audio en un teléfono y que cumple con la arquitectura de apps de música de Android. La Biblioteca de apps para vehículos te permite reemplazar la experiencia en la app con plantillas en lugar de las que se compilan con la estructura de datos Cómo compilar apps de música para automóviles MediaBrowser. Aun así, debes proporcionar un MediaSession para los controles de reproducción y un MediaBrowserService o MediaLibraryService, que se usa para recomendaciones y otras experiencias inteligentes.

Cómo configurar el manifiesto de tu app

Además de los pasos que se describen en Cómo usar la biblioteca de apps de Android para vehículos, se requieren los siguientes elementos para las apps de música basadas en plantillas:

Declara la compatibilidad de categoría en tu manifiesto

Tu app debe declarar la androidx.car.app.category.MEDIA categoría de app para vehículos en el filtro de intents de su CarAppService.

<application>
    ...
   <service
       ...
        android:name=".MyCarAppService"
        android:exported="true">
      <intent-filter>
        <action android:name="androidx.car.app.CarAppService" />
        <category android:name="androidx.car.app.category.MEDIA"/>
      </intent-filter>
    </service>
    ...
<application>

Para obtener acceso a MediaPlaybackTemplate, tu app también debe declarar el permiso androidx.car.app.MEDIA_TEMPLATES en su archivo de manifiesto:

<manifest ...>
  ...
  <uses-permission android:name="androidx.car.app.MEDIA_TEMPLATES"/>
  ...
</manifest>

Cómo configurar el nivel de API mínimo de la app para vehículos

Las apps de música que usan MediaPlaybackTemplate solo son compatibles con la API de CAL 8 y versiones posteriores. Asegúrate de que tu Car App API level mínimo esté configurado en 8.

<application ...>
  ...
  <meta-data
    android:name="androidx.car.app.minCarApiLevel"
    android:value="8"/>
  ...
</application>

Proporciona un ícono de atribución

Asegúrate de agregar un ícono de atribución para las apps de música compiladas con la Biblioteca de apps para vehículos.

Declara la compatibilidad con Android Auto

Asegúrate de que se incluya lo siguiente en el manifiesto de tu app:

<application>
  ...
  <meta-data android:name="com.google.android.gms.car.application"
      android:resource="@xml/automotive_app_desc"/>
  ...
</application>

Luego, agrega la declaración de plantilla a automotive_app_desc.xml en tus recursos XML. Debería verse de la siguiente manera:

<automotiveApp xmlns:android="http://schemas.android.com/apk/res/android">
 <uses name="media"/>
 <uses name="template"/>
</automotiveApp>

Declara la compatibilidad con el SO Android Automotive

Existen dos formas diferentes de distribuir una app de música habilitada para la Biblioteca de apps para vehículos en el SO Android Automotive: como un solo APK o como dos APK separados. Si distribuyes un solo APK, admitirá vehículos habilitados para el SO Android Automotive con el host de la Biblioteca de apps para vehículos y volverá a una aplicación MediaBrowserService o MediaLibraryService si no es así, incluso para versiones anteriores de Android (Android 10 a Android 13). Si eliges distribuir dos APK separados, puedes actualizar más fácilmente las nuevas incorporaciones a la versión de la Biblioteca de apps para vehículos sin temor a afectar la versión MediaBrowserService o MediaLibraryService de tu app.

Cómo distribuir un solo APK

Cuando distribuyes un solo APK para la Biblioteca de apps para vehículos y MediaBrowserService o MediaLibraryService versiones de tu app, es fundamental configurar "" en android:required="false".

<uses-feature android:name="android.software.car.templates_host.media" android:required="false"/>

A continuación, sigue los lineamientos de la Biblioteca de apps para vehículos para AAOS y presenta una que se pueda iniciar CarAppActivity (o actividad de trampolín). Debes configurar la actividad en android:enabled="false" en el manifiesto. Luego, agrega una etiqueta de metadatos a la declaración MediaBrowserService que indique el componente CarAppActivity como el reemplazo. Consulta el siguiente manifiesto de ejemplo:

<service android:name=".media.MyMediaService"
    android:exported="true"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaLibraryService"/>
    </intent-filter>

    <!-- Link to Car App Library Activity -->
    <meta-data
        android:name="androidx.car.app.media.CalMediaActivityComponent" 
        android:value="com.example.mediaapp.LaunchableTrampoline"/>
</service>

<activity
    android:name=".LaunchableTrampoline"
    android:exported="true"
    android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
    android:launchMode="singleTask"
    android:label="@string/app_name_cal"
    android:enabled="false"> <!-- Set to false -->

    <meta-data android:name="distractionOptimized" android:value="true" />

    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <action android:name="androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

Distribución de Play

Tu APK con la Biblioteca de apps para vehículos y MediaBrowserService o MediaLibraryService debe habilitarse con un código de versión más alto y minSdk orientado a Android 14 (34).

Cómo distribuir con dos APKs

Para distribuir dos APK separados, uno que use la Biblioteca de apps para vehículos y otro que use MediaBrowserService o MediaLibraryService, sigue estos pasos para asegurarte de que las capacidades correctas del vehículo se orienten correctamente.

Cuando crees un APK independiente para la versión de la Biblioteca de apps para vehículos de tu app, debes configurar android.software.car.templates_host.media en android:required=true. Esto garantiza que la app se distribuya solo en compilaciones del SO Android Automotive certificadas con compatibilidad para el host de la Biblioteca de apps para vehículos.

<uses-feature android:name="android.software.car.templates_host.media" android:required="true"/>

Además de usar android.software.car.templates_host.media y configurarlo en android:required=true anteriormente, sigue estos pasos para habilitar el SO Android Automotive para tu actividad de la Biblioteca de apps para vehículos que se puede iniciar.

Distribución de Play

El APK que usa la Biblioteca de apps para vehículos debe distribuirse en el segmento dedicado de Automotive OS.

Cómo admitir acciones de voz

Habilita la voz en tu app para permitir que los usuarios completen acciones comunes sin usar las manos. Consulta Cómo admitir acciones de voz para contenido multimedia para obtener instrucciones de implementación más detalladas. Con una app de música basada en plantillas, si recibes un comando de voz, no necesitas actualizar tu MediaBrowserService o MediaLibraryService con los resultados de la búsqueda. En su lugar, considera agregar una acción en tu plantilla de reproducción de contenido multimedia para permitir que el usuario encuentre más contenido en función de esa reproducción o consulta de búsqueda. Se requiere la compatibilidad con comandos de voz para cumplir con el VC-1 lineamiento de calidad.

Crea tu plantilla de reproducción

El MediaPlaybackTemplate muestra información de reproducción de contenido multimedia en tu app de música de la Biblioteca de apps para vehículos. Esta plantilla permite configurar un encabezado con un título y acciones personalizables, mientras que el host completa la información de contenido multimedia y los controles de reproducción según el estado de MediaSession de tu app.

Un reproductor de música muestra Sounds of Spring de Summer Fielding con un retrato cuadrado de una mujer tocando la guitarra.

Figura 1: MediaPlaybackTemplate con una acción de encabezado para abrir la cola en la parte superior

En este ejemplo de código, se muestra cómo compilar una plantilla de reproducción de ejemplo que establece una acción de encabezado que permite al usuario navegar a una pantalla con la cola de canciones.

val playbackTemplate = MediaPlaybackTemplate.Builder()
      .setHeader(
        Header.Builder()
          .setStartHeaderAction(Action.BACK)
          .addEndHeaderAction(
                Action.Builder()
                  .setTitle(model.context.getString(R.string.queue_button_title))
                  .setIcon(
                    CarIcon.Builder(
                        IconCompat.createWithResource(
                          model.context,
                          R.drawable.gs_queue_music_vd_theme_24,
                        ))
                      .build())
                  .setOnClickListener(showQueueScreen())
                  .build())
          .setTitle(model.context.getString(R.string.media_playback_view_title))
          .build())
      .build()

Cuando usas MediaPlaybackTemplate, registra un MediaSession token con MediaPlaybackManager en tu CarAppService. Si no lo haces, se mostrará un error cuando se envíe un MediaPlaybackTemplate al host.

import androidx.car.app.media.MediaPlaybackManager


override fun onCreateSession(sessionInfo: SessionInfo): Session {
    return object : Session() {
        

        init {
          lifecycle.addObserver(
            LifecycleEventObserver { _, event ->
              if (event == ON_CREATE) {
                val token = ... // MediaSessionCompat.Token
                (carContext.getCarService(CarContext.MEDIA_PLAYBACK_SERVICE) as MediaPlaybackManager)
                  .registerMediaPlaybackToken(token)
              }
              ...
            }
          )
        }
    }
}

.registerMediaPlaybackToken es necesario para exponer la información y los controles de reproducción de contenido multimedia a Android Auto. Esto también es importante para que el host cree notificaciones específicas de contenido multimedia.

En el caso de las apps que usan la biblioteca de Media3, que usan un PlatformToken en lugar de un MediaSessionCompat.Token estándar, deberás implementar un SessionCommand personalizado en tu MediaLibrarySession.Callback que muestre el token de plataforma subyacente de la sesión: session.platformToken. En tu CarAppService, envía este comando personalizado a la sesión. Una vez que recibas el token de plataforma, conviértelo con MediaSessionCompat.Token.fromToken(platformToken) y pasa este token de compatibilidad a la Biblioteca de apps para vehículos en .registerMediaPlaybackToken().

Organiza el contenido multimedia con plantillas

Para organizar el contenido multimedia para la exploración, como canciones o álbumes, te recomendamos que uses la SectionedItemTemplate, que te permite usar GridSection y RowSection juntos para crear diseños que combinen listas de imágenes y elementos de texto.

La interfaz de una app de música muestra las canciones y los álbumes que se reprodujeron recientemente, incluidas dos filas verticales y tres retratos horizontales de las imágenes de los álbumes.

Figura 2: Un SectionedItemTemplate que contiene un RowSection seguido de un GridSection

Cómo usar SectionedItemTemplate dentro de TabTemplate

Una forma conveniente de categorizar el contenido multimedia dentro de tu app es usar el SectionedItemTemplate dentro de un TabTemplate.

val template =
      SectionedItemTemplate.Builder()...build();
val tabTemplate = 
      TabTemplate.Builder(tabCallback)
          .setTabContents(TabContents.Builder(template).build)
          .setHeaderAction(Action.APP_ICON)
          
          .build();

Componentes y funciones de la biblioteca de apps para vehículos 1.9

La versión 1.9 de la API de la Biblioteca de apps para vehículos presenta componentes personalizados para capacidades de exploración únicas, como chips, barras de progreso, elementos condensados, encabezado interactivo y expandido, secciones destacadas y banners.

La interfaz de una app de música muestra las canciones y los álbumes que se reprodujeron recientemente, incluidas dos filas verticales y tres retratos horizontales de las imágenes de los álbumes.

Figura 3: Un SectionedItemTemplate que contiene Chips, Condensed Items, un Interactive Header, Grid Items y un Minimized Control Panel

La interfaz de una app de música muestra las canciones y los álbumes que se reprodujeron recientemente, incluidas dos filas verticales y tres retratos horizontales de las imágenes de los álbumes.

Figura 4: Dos pantallas de exploración de contenido multimedia con Expanded Header, Spotlight Sections y Progress Bars

Si quieres obtener más información para diseñar la interfaz de usuario de tu app de música con esas plantillas, consulta el documento sobre apps de música.

Cuando se explora el contenido multimedia, es importante que el usuario pueda navegar rápidamente a MediaPlaybackTemplate con una distracción mínima.Para cumplir con el requisito de calidad MFT-1, tu app debe tener una forma de acceder a MediaPlaybackTemplate desde todas las pantallas de exploración de contenido multimedia.

Si usas SectionedItemTemplate, puedes lograrlo agregando un botón de acción que te dirija a la pantalla de reproducción de contenido multimedia. Usa la acción Action.MEDIA_PLAYBACK estándar de la Biblioteca de apps para vehículos. Una app de música mostrará esta acción como un panel de control minimizado, que es necesario para cumplir con el requisito de calidad MFT-1 si usas la API 1.9 de la Biblioteca de apps para vehículos o versiones posteriores. Para otras plantillas, una acción de encabezado es otra forma de lograrlo.

Cómo controlar intents de reproducción de contenido multimedia del sistema

Es necesario dirigir al usuario a MediaPlaybackTemplate cuando se inicia una aplicación desde una plataforma del sistema que reproduce contenido multimedia, como una tarjeta de contenido multimedia. Requerimos que las aplicaciones de contenido multimedia controlen esta Intent Action para brindar una experiencia fluida a los usuarios.

Agrega la acción androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK al filtro de intents de tu componente de la Biblioteca de apps para vehículos (ya sea CarAppActivity o tu Activity de trampolín).

Asegúrate de que tu actividad use un launchMode de singleTask o singleTop para que se invoque onNewIntent().

<activity
    android:name=".LaunchableTrampoline"
    android:exported="true"
    android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
    android:launchMode="singleTask"
    android:label="@string/app_name_cal"
    android:enabled="false">

    <meta-data android:name="distractionOptimized" android:value="true" />

    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <action android:name="androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

En tu clase Session, anula onNewIntent() para analizar el intent entrante. Si la acción de intent entrante coincide con SHOW_MEDIA_PLAYBACK, dirige al usuario a la pantalla de reproducción.

@Override
public void onNewIntent(@NonNull Intent intent) {
    super.onNewIntent(intent);
    if (SHOW_MEDIA_PLAYBACK.equals(intent.getAction())) {
        ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class);
        // Avoid redundant navigation if already on the playing screen
        if (screenManager.getTop() instanceof MyMediaPlayScreen) {
            return;
        }
        screenManager.push(MyMediaPlayScreen.createScreenFromPlaying(
                getCarContext(), mMediaSessionController));
    }
}

Si usas una actividad de trampolín, busca la acción de intent dentro de onCreate(). Pasa esta acción al intent de creación de CarAppActivity antes de llamar a finish().

public class LaunchableTrampoline extends AppCompatActivity {
    private static final String SHOW_MEDIA_PLAYBACK = "androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent receivedIntent = getIntent();
        String action;

        if (SHOW_MEDIA_PLAYBACK.equals(receivedIntent.getAction())) {
            action = SHOW_MEDIA_PLAYBACK;
        } else {
            action = Intent.ACTION_MAIN;
        }

        Intent intent = new Intent(action);
        intent.setClassName(getPackageName(), "androidx.car.app.activity.CarAppActivity");
        startActivity(intent);
        finish();
    }
}