Criar um app de mídia com modelo

Os apps de mídia com base em modelo estão na versão Beta
No momento, qualquer pessoa pode publicar apps de mídia com modelos em faixas de teste interno e fechado na Google Play Store. A publicação em faixas abertas e de produção será permitida em uma data futura.

Os apps de mídia que usam os modelos da biblioteca Car App podem personalizar a experiência de navegação e reprodução de mídia, garantindo que ela seja otimizada para telas de carro e minimize as distrações ao dirigir.

Este guia presume que você já tenha um app de música que reproduz áudio em um smartphone e que ele seja compatível com a arquitetura de app de música do Android. A biblioteca de apps para carros permite substituir a experiência no app por modelos em vez daqueles criados usando a estrutura de dados Criar apps de mídia para carros MediaBrowser. Você ainda precisa fornecer um MediaSession para controles de reprodução e um MediaBrowserService ou MediaLibraryService, que é usado para recomendações e outras experiências inteligentes.

Configurar o manifesto do app

Além das etapas descritas em Como usar a biblioteca Android para carros App, os seguintes requisitos são obrigatórios para apps de mídia com modelos:

Declarar suporte à categoria no manifesto

Seu app precisa declarar a categoria de app para carros androidx.car.app.category.MEDIA no filtro de intent de 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 ter acesso ao MediaPlaybackTemplate, seu app também precisa declarar a permissão androidx.car.app.MEDIA_TEMPLATES no arquivo de manifesto:

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

Definir o nível mínimo da API Car App

Os apps de mídia que usam o MediaPlaybackTemplate só são compatíveis com a API CAL 8 e versões mais recentes. Verifique se o Car App API level mínimo está definido como 8.

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

Fornecer um ícone de atribuição

Adicione um ícone de atribuição aos apps de mídia criados com a biblioteca Car App.

Declarar compatibilidade com o Android Auto

Verifique se o seguinte está incluído no manifesto do app:

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

Em seguida, adicione a declaração template a automotive_app_desc.xml nos recursos XML. Ele terá a seguinte aparência:

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

Declarar suporte ao Android Automotive OS

Há duas maneiras diferentes de distribuir um app de mídia compatível com a biblioteca Car App no Android Automotive OS: como um único APK ou como dois APKs separados. Se você distribuir um único APK, ele vai oferecer suporte a veículos ativados para o Android Automotive OS com o host da biblioteca Car App e vai voltar para um aplicativo MediaBrowserService ou MediaLibraryService se não for o caso, mesmo para versões mais antigas do Android (Android 10 a Android 13). Se você optar por distribuir dois APKs separados, poderá atualizar mais facilmente as novas adições à versão da Car App Library sem afetar a versão MediaBrowserService ou MediaLibraryService do seu app.

Distribuir um único APK

Ao distribuir um único APK para a biblioteca Car App e as versões MediaBrowserService ou MediaLibraryService do app, é fundamental definir o "" como android:required="false".

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

Em seguida, siga as diretrizes da biblioteca de apps para carros no AAOS e introduza um CarAppActivity inicializável (ou atividade de trampolim). Defina a atividade como android:enabled="false" no manifesto. Em seguida, adicione uma tag de metadados à declaração MediaBrowserService indicando o componente CarAppActivity como a substituição. Confira um exemplo de manifesto abaixo:

<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>

Distribuição do Google Play

O APK com a biblioteca de apps para carro e MediaBrowserService ou MediaLibraryService precisa ser ativado com um código de versão mais alto e minSdk segmentando o Android 14 (34).

Distribuição com dois APKs

Para distribuir dois APKs separados, um usando a biblioteca Car App e outro usando MediaBrowserService ou MediaLibraryService, siga estas etapas para garantir que as capacidades corretas do veículo sejam segmentadas corretamente.

Ao criar um APK separado para a versão da biblioteca Car App do seu app, defina o android.software.car.templates_host.media como android:required=true. Isso garante que o app seja distribuído apenas em builds do Android Automotive OS certificados com suporte ao host da biblioteca Car App.

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

Além de usar android.software.car.templates_host.media e definir como android:required=true acima, siga estas etapas para ativar o Android Automotive OS na sua atividade inicializável da biblioteca Car App.

Distribuição do Google Play

O APK que usa a biblioteca Car App precisa ser distribuído na faixa dedicada do Automotive OS.

Oferecer compatibilidade com comandos de voz

Ative a voz no seu app para permitir que os usuários concluam ações comuns sem usar as mãos. Consulte Suporte para comandos de voz de mídia para instruções de implementação mais detalhadas. Com um app de mídia baseado em modelo, se você receber um comando de voz, não precisará atualizar seu MediaBrowserService ou MediaLibraryService com resultados da pesquisa. Em vez disso, adicione uma ação ao modelo de reprodução de mídia para permitir que o usuário encontre mais conteúdo com base na reprodução ou na consulta de pesquisa. O suporte a comandos de voz é necessário para atender à diretriz de qualidade VC-1.

Criar seu modelo de reprodução

O MediaPlaybackTemplate mostra informações de reprodução de mídia no app de mídia da biblioteca Car App. Esse modelo permite definir um cabeçalho com um título e ações personalizáveis, enquanto as informações de mídia e os controles de reprodução são preenchidos pelo host com base no estado do MediaSession do app.

Um player de música mostra &quot;Sounds of Spring&quot;, de Summer Fielding, com um retrato quadrado de uma mulher tocando violão.

Figura 1:MediaPlaybackTemplate com uma ação de cabeçalho para abrir a fila na parte de cima.

Este exemplo de código mostra como criar um modelo de reprodução de exemplo que define uma ação de cabeçalho que permite ao usuário navegar até uma tela com a fila de músicas.

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()

Ao usar MediaPlaybackTemplate, registre um token MediaSession usando o MediaPlaybackManager no seu CarAppService. Se isso não for feito, um erro vai aparecer quando um MediaPlaybackTemplate for enviado ao 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)
              }
              ...
            }
          )
        }
    }
}

O .registerMediaPlaybackToken é necessário para expor informações e controles de reprodução de mídia ao Android Auto. Isso também é importante para que o host crie notificações específicas de mídia.

Para apps que usam a biblioteca Media3, que usa um PlatformToken em vez de um MediaSessionCompat.Token padrão, é necessário implementar um SessionCommand personalizado no MediaLibrarySession.Callback que retorna o token da plataforma subjacente da sessão: session.platformToken. No seu CarAppService, envie este comando personalizado para a sessão. Depois de receber o token da plataforma, converta-o usando MediaSessionCompat.Token.fromToken(platformToken) e transmita esse token de compatibilidade para a biblioteca de apps para carro em .registerMediaPlaybackToken().

Organizar mídia usando modelos

Para organizar mídias para navegação, como músicas ou álbuns, recomendamos usar o SectionedItemTemplate, que permite usar o GridSection e RowSection juntos para criar layouts que misturam listas de imagens e itens de texto.

Uma interface de app de música mostra músicas e álbuns reproduzidos recentemente,
     incluindo duas linhas verticais e três retratos horizontais de capas de álbuns.

Figura 2:um SectionedItemTemplate que contém um RowSection seguido por um GridSection

Como usar SectionedItemTemplate em um TabTemplate

Uma maneira conveniente de categorizar mídia no seu app é usar o SectionedItemTemplate em um TabTemplate.

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

Componentes e recursos da biblioteca Car App 1.9

A API Car App Library versão 1.9 apresenta componentes personalizados para recursos de navegação exclusivos, como chips, barras de progresso, itens condensados, cabeçalho interativo e expandido, seções de destaque e banners.

Uma interface de app de música mostra músicas e álbuns reproduzidos recentemente,
     incluindo duas linhas verticais e três retratos horizontais de capas de álbuns.

Figura 3:um SectionedItemTemplate que contém Chips, Condensed Items, um Interactive Header, Grid Items e um Minimized Control Panel

Uma interface de app de música mostra músicas e álbuns reproduzidos recentemente,
     incluindo duas linhas verticais e três retratos horizontais de capas de álbuns.

Figura 4:duas telas de navegação de mídia com os ícones Expanded Header, Spotlight Sections e Progress Bars.

Para saber mais sobre como projetar a interface do usuário do seu app de mídia usando esses modelos, consulte Apps de mídia.

Ao navegar pela mídia, é importante que o usuário possa acessar rapidamente o MediaPlaybackTemplate com o mínimo de distração.Para atender ao requisito de qualidade MFT-1, seu app precisa ter uma maneira de acessar o MediaPlaybackTemplate em todas as telas de navegação de mídia.

Se você estiver usando SectionedItemTemplate, adicione um botão de ação que navega até a tela de reprodução de mídia. Use a ação padrão Action.MEDIA_PLAYBACK da biblioteca Car App. Um app de mídia vai mostrar essa ação como um painel de controle minimizado, que é necessário para atender ao requisito de qualidade MFT-1 se você estiver usando a API da biblioteca Car App 1.9 ou mais recente. Para outros modelos, uma ação de cabeçalho é outra maneira de fazer isso.

Processar intents de reprodução de mídia do sistema

É necessário direcionar o usuário para o MediaPlaybackTemplate quando um aplicativo é iniciado em uma superfície de mídia, como um card de mídia. Exigimos que os aplicativos de mídia processem esse Intent Action para oferecer uma experiência perfeita aos usuários.

Adicione a ação androidx.car.app.media.action.SHOW_MEDIA_PLAYBACK ao intent-filter do componente da biblioteca Car App (CarAppActivity ou seu trampoline Activity).

Verifique se a atividade usa um launchMode de singleTask ou singleTop para que onNewIntent() seja invocado.

<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>

Na classe Session, substitua onNewIntent() para analisar a intent recebida. Se a ação da intent recebida corresponder a SHOW_MEDIA_PLAYBACK, navegue o usuário até a tela "Tocando agora".

@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));
    }
}

Se você estiver usando uma atividade de trampolim, verifique a ação da intent em onCreate(). Transmita essa ação para a intent de criação de CarAppActivity antes de chamar 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();
    }
}