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 toca áudio em um smartphone
e que ele seja compatível com a arquitetura de app de música do Android. A
Car App Library permite substituir a experiência no app por
modelos em vez daqueles criados com a estrutura de dados MediaBrowser de
Criar apps de música para carros. Ainda é necessário 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 compatíveis com o Android Automotive OS com o host da biblioteca Car App e vai voltar para um aplicativo MediaBrowserService ou MediaLibraryService se não for compatível, mesmo em 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 biblioteca Car App sem afetar a versão MediaBrowserService ou MediaLibraryService do 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 trampoline). Defina a atividade como android:enabled="false" no manifesto. Em seguida, adicione uma tag de metadados
à declaração MediaBrowserService indicando o componente CarAppActivity
como substituto. 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 no 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 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 para 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, considere adicionar 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. Caso contrário, um erro será exibido 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)
}
...
}
)
}
}
}
.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 seu MediaLibrarySession.Callback que retorne o
token da plataforma subjacente da sessão: session.platformToken. No
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 o
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 versão 1.9 da API da biblioteca de apps para carro 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 navegue até a tela de reprodução de mídia. Use a ação padrão Action.MEDIA_PLAYBACK da biblioteca de apps para carros. 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 1.9 ou mais recente da biblioteca de apps para carros. 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 reprodução de mídia do sistema, como um card de mídia. Exigimos que os aplicativos de mídia processem esse Intent Action para oferecer uma experiência contínua 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 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();
}
}