Os apps de música que usam os modelos da biblioteca de apps para carros podem personalizar a experiência de navegação e reprodução de mídia, garantindo que ela seja otimizada para telas de carros 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
biblioteca de apps para carros permite substituir a experiência no app por
modelos em vez daqueles criados usando a estrutura de dados MediaBrowser de
Criar apps de música para carros. Ainda é necessário fornecer um MediaSession
para controles de mídia 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 de apps Android para carros, os apps de mídia baseados em modelos precisam:
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úsica 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 para apps de música criados com a biblioteca de apps para carros.
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 de distribuir um app de mídia com a biblioteca de apps Car App no Android Automotive OS: como um único APK ou como dois APKs separados. Se você distribuir um único APK, ele será compatível com veículos que têm o Android Automotive OS com o host da biblioteca de apps Car e, se não tiverem, vai usar um aplicativo MediaBrowserService ou MediaLibraryService, mesmo para versões mais antigas do Android (Android 10 a Android 13). Se você optar por distribuir
dois APKs separados, poderá atualizar as novas adições à versão da biblioteca de apps para carros
sem medo de afetar a versão MediaBrowserService ou
MediaLibraryService do seu app.
Distribuir um único APK
Ao distribuir um único APK para a biblioteca de apps Car App e as versões MediaBrowserService
ou MediaLibraryService do seu app, é fundamental definir o
android.software.car.templates_host.media 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 para o AAOS e
introduza uma CarAppActivity inicializável (ou atividade de trampolim). É necessário definir
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 o exemplo de manifesto a seguir:
<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 carros e MediaBrowserService
ou MediaLibraryService precisa ser ativado com um código de versão mais recente e
minSdk direcionado ao Android 14 (34).
Distribuição com dois APKs
Para distribuir dois APKs separados, um usando a biblioteca de apps Car e outro usando
MediaBrowserService ou MediaLibraryService, siga estas etapas para garantir que os
recursos corretos do veículo sejam segmentados corretamente.
Ao criar um APK separado para a versão da biblioteca de apps para carros 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 de apps 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, siga estas etapas para
ativar o Android Automotive OS na atividade
da biblioteca de apps para carros que pode ser iniciada.
Distribuição do Google Play
O APK que usa a biblioteca de apps Car precisa ser distribuído na faixa dedicada ao Automotive OS.
Oferecer compatibilidade com comandos de voz
Ative a voz no seu app para que os usuários possam realizar ações comuns por comando de voz.
Consulte Suporte para comandos de voz para mídia para ver instruções de implementação
mais detalhadas. Com um app de música baseado em modelo, se você receber um comando de voz, não
precisará atualizar o MediaBrowserService ou o MediaLibraryService com
os 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 nessa reprodução ou 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 de apps para carros. 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 mídia 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 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 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 usam um PlatformToken em vez de um
MediaSessionCompat.Token padrão, é necessário implementar um
SessionCommand personalizado no MediaLibrarySession.Callback que retorna o
token de 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 do carro em .registerMediaPlaybackToken().
Organizar mídia usando modelos
Para organizar mídias para navegação, como músicas ou álbuns, recomendamos o uso do
SectionedItemTemplate,
que permite usar o GridSection e o
RowSection juntos para criar layouts que misturam listas de imagens
e itens de texto.
Figura 2: uma
SectionedItemTemplate que contém uma RowSection
seguida por uma GridSection
Como usar SectionedItemTemplate dentro de um TabTemplate
Uma maneira conveniente de categorizar mídia no app é usar o
SectionedItemTemplate dentro de 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 de apps para carros 1.9
A versão 1.9 da API Car App Library apresenta componentes personalizados para recursos de navegação exclusivos, como ícones, 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 Expanded Header,
Spotlight Sections e Progress Bars
Para saber mais sobre como projetar a interface do usuário do seu app de música usando esses modelos, consulte Apps de música.
Como acessar 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, o 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 direcione à 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úsica 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 Car App. 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 do sistema, 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 filtro de intent do componente da biblioteca de apps Car App (CarAppActivity ou o 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 de intent recebida corresponder a SHOW_MEDIA_PLAYBACK, direcione o usuário
para 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();
}
}