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
"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.
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.
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.
Figura 3:um
SectionedItemTemplate que contém Chips,
Condensed Items, um Interactive Header,
Grid Items e um Minimized Control Panel
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.
Navegar até os controles 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();
}
}