A biblioteca Android for Cars App permite que você use a navegação, o ponto de interesse (PDI) e a Internet das Coisas (IoT) para o carro. Ele faz isso fornecendo um conjunto de modelos para atender à distração do motorista. e cuidar de detalhes como a variedade de fatores da tela do carro e modalidades de entrada.
Este guia fornece uma visão geral dos principais recursos e conceitos da biblioteca e vai ajudar você a configurar um app básico.
Antes de começar
- Revise o Design para direção
páginas que cobrem a biblioteca Car App
- Apps de navegação e Outros apps relacionados a carros visões gerais de categorias
- Visão geral de como criar apps com modelos
- Elementos básicos que abrangem modelos e componentes de modelos
- Fluxos de amostra demonstrando padrões comuns de UX
- Requisitos de apps baseados em modelos
- Revise os principais termos e conceitos a seguir nesta seção.
- Familiarize-se com o sistema Android Auto Interface e Android Automotive OS design.
- Leia as Notas da versão.
- Analise os Exemplos (link em inglês).
Principais termos e conceitos
- Estilos e modelos
- A interface do usuário é representada por um gráfico de objetos de modelo que podem ser organizados de maneiras diferentes, conforme permitido pelo modelo a que pertencem. Os modelos são um subconjunto dos modelos principais que podem funcionar como uma raiz nesses gráficos. Os modelos incluem as informações a serem exibidas para o usuário no texto e imagens, bem como atributos para configurar aspectos do a aparência visual dessas informações, como cores de texto ou imagens tamanhos. O organizador converte os modelos em visualizações projetadas para atender os padrões de distração do motorista e cuida de detalhes como a variedade dos fatores de tela do carro e modalidades de entrada.
- Host
- O host é o componente de back-end que implementa a funcionalidade oferecida pelas APIs da biblioteca para que o app seja executado no carro. O responsabilidades do host variam de descobrir seu aplicativo e gerenciar o ciclo de vida até a conversão dos modelos em visualizações e a notificação do app das interações do usuário. Em dispositivos móveis, esse host é implementado pelo Android Auto. No Android Automotive OS, esse host é instalado como um app do sistema.
- Restrições de modelos
- Diferentes modelos impõem restrições ao conteúdo dos estilos principais. Por exemplo, os modelos de lista têm limites quanto ao número de itens que podem ser apresentados ao usuário. Os modelos também têm restrições estar conectado para formar o fluxo de uma tarefa. Por exemplo, o app só pode enviar até cinco modelos para a pilha de tela. Consulte Restrições de modelo para mais detalhes.
Screen
Screen
é uma classe fornecida pelo que os aplicativos implementam para gerenciar a interface do usuário apresentada à usuário. UmScreen
tem um ciclo de vida e fornece o mecanismo para o app envie o modelo para ser exibido quando a tela estiver visível. As instâncias deScreen
também podem ser enviadas e abertas na pilhaScreen
e retiradas dela, o que garante que elas sigam as restrições de fluxo de modelo.CarAppService
CarAppService
é uma classe abstrataService
que o app precisa implementar e exportar para ser descoberto e gerenciado pelo host. OCarAppService
do app é responsável por validar que uma conexão de host pode ser confiável usandocreateHostValidator
e, em seguida, fornecendoSession
instâncias para cada conexão usandoonCreateSession
.Session
Session
é uma classe abstrata que seu app precisa implementar e retornar usandoCarAppService.onCreateSession
. Ele serve como ponto de entrada para mostrar informações na tela do carro. Ela tem um ciclo de vida que informa ao o estado atual do app na tela do carro, como quando ele está visíveis ou ocultas.Quando uma
Session
é iniciada, como quando o app é aberto pela primeira vez, o host solicita que aScreen
inicial seja exibida usando o métodoonCreateScreen
.
Instalar a biblioteca de apps para carros
Ver a biblioteca Jetpack página de lançamento para instruções sobre como adicionar a biblioteca ao seu app.
Configurar os arquivos de manifesto do app
Antes de criar o app para carro, configure os arquivos de manifesto dele da seguinte maneira.
Declarar o CarAppService
O host se conecta ao seu app usando a
implementação CarAppService
. Você
declare esse serviço no manifesto para permitir que o host descubra e se conecte
ao seu app.
Também é necessário declarar a categoria do app no elemento
<category>
do filtro de intent. Veja a lista de
categorias de aplicativos compatíveis com os valores permitidos para
esse elemento.
O snippet de código abaixo mostra como declarar um serviço de app para carros em um app de ponto de interesse no manifesto:
<application>
...
<service
...
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService"/>
<category android:name="androidx.car.app.category.POI"/>
</intent-filter>
</service>
...
<application>
Categorias de apps compatíveis
Declare a categoria do app adicionando uma ou mais das seguintes categorias
valores no filtro de intent ao declarar o CarAppService
conforme descrito
na seção anterior:
androidx.car.app.category.NAVIGATION
: um app que fornece navegação guiada rotas de navegação. Consulte Criar apps de navegação para carros para conferir mais documentação sobre essa categoria.androidx.car.app.category.POI
: um app que oferece uma funcionalidade relevante para encontrar pontos de interesse, como vagas de estacionamento, estações de recarga e postos de gasolina. Finalizar compra Criar apps de ponto de interesse para carros para documentação adicional sobre esta categoria.androidx.car.app.category.IOT
: um app que permite que os usuários realizem ações relevantes em dispositivos conectados de dentro do carro. Consulte Criar apps de Internet das Coisas para carros para mais documentação sobre essa categoria.
Consulte Qualidade de apps Android para carros para descrições detalhadas de cada categoria e critérios para que os apps pertençam a elas.
Especificar o nome e o ícone do aplicativo
Especifique o nome e o ícone do app que o host pode usar para representar seu app na IU do sistema.
É possível especificar o nome e o ícone do aplicativo usado para representar seu aplicativo usando
os objetos label
e
icon
da sua
CarAppService
:
...
<service
android:name=".MyCarAppService"
android:exported="true"
android:label="@string/my_app_name"
android:icon="@drawable/my_app_icon">
...
</service>
...
Se o rótulo ou ícone não forem declarados no
Elemento <service>
, o host
volta para os valores especificados para
<application>
.
Definir um tema personalizado
Para definir um tema personalizado para o app para carros, adicione um
O elemento <meta-data>
na sua
da seguinte forma:
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
Em seguida, declare seu recurso de estilo para definir os seguintes atributos para o tema personalizado do app de carro:
<resources> <style name="MyCarAppTheme"> <item name="carColorPrimary">@layout/my_primary_car_color</item> <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item> <item name="carColorSecondary">@layout/my_secondary_car_color</item> <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
Nível da API Car App
A biblioteca Car App define os próprios níveis de API para que você saiba quais
recursos da biblioteca são compatíveis com o host do modelo em um veículo.
Para recuperar o nível mais alto da API Car App compatível com um host, use o
método
getCarAppApiLevel()
.
Declarar o nível mínimo da API Car App com suporte ao app no
Arquivo AndroidManifest.xml
:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
Consulte a documentação da anotação
RequiresCarApi
para mais detalhes sobre como manter a compatibilidade com versões anteriores e declarar
o nível mínimo da API necessário para usar um recurso. Para ver
uma definição de qual nível da API é necessário para usar determinado recurso da biblioteca Car
App, consulte a
documentação de referência de
CarAppApiLevels
.
Criar CarAppService e Session
Seu app precisa ampliar a classe
CarAppService
e implementar
o método
onCreateSession
,
que retorna uma instância Session
correspondente à conexão atual com o host:
Kotlin
class HelloWorldService : CarAppService() { ... override fun onCreateSession(): Session { return HelloWorldSession() } ... }
Java
public final class HelloWorldService extends CarAppService { ... @Override @NonNull public Session onCreateSession() { return new HelloWorldSession(); } ... }
A instância Session
é responsável
retornando a instância Screen
para usar
na primeira vez que o app for iniciado:
Kotlin
class HelloWorldSession : Session() { ... override fun onCreateScreen(intent: Intent): Screen { return HelloWorldScreen(carContext) } ... }
Java
public final class HelloWorldSession extends Session { ... @Override @NonNull public Screen onCreateScreen(@NonNull Intent intent) { return new HelloWorldScreen(getCarContext()); } ... }
Para gerenciar situações em que o app para carro precise ser iniciado em uma tela que não
seja a inicial ou de destino do app (como no processamento de links diretos), é possível
pré-buscar uma pilha de retorno de telas usando
ScreenManager.push
antes de retornar de
onCreateScreen
.
A pré-busca permite que os usuários naveguem de volta para as telas anteriores pela primeira
tela que seu app está exibindo.
Criar a tela inicial
Para criar as telas exibidas pelo app, defina classes que ampliem a
classe Screen
e implemente o método
onGetTemplate
,
que retorna a instância Template
que representa
o estado da IU a ser exibida na tela do carro.
O snippet a seguir mostra como declarar
Screen
que usa um
PaneTemplate
modelo para
exiba uma mensagem simples “Hello world!” string:
Kotlin
class HelloWorldScreen(carContext: CarContext) : Screen(carContext) { override fun onGetTemplate(): Template { val row = Row.Builder().setTitle("Hello world!").build() val pane = Pane.Builder().addRow(row).build() return PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build() } }
Java
public class HelloWorldScreen extends Screen { @NonNull @Override public Template onGetTemplate() { Row row = new Row.Builder().setTitle("Hello world!").build(); Pane pane = new Pane.Builder().addRow(row).build(); return new PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build(); } }
Classe CarContext
A classe CarContext
é uma
subclasse ContextWrapper
acessível às instâncias Session
e
Screen
. Ela dá acesso
até serviços automotivos,
ScreenManager
para gerenciar o
pilha de tela as
AppManager
para informações gerais relacionadas a apps
funcionalidade, como acessar o objeto Surface
para desenhar mapas;
e NavigationManager
usada por apps de navegação guiada para comunicar a navegação
metadados e outros
relacionado à navegação
eventos com
do host.
Consulte Acessar a navegação modelos para um lista abrangente de funcionalidades da biblioteca disponíveis para apps de navegação.
O CarContext
também oferece outras
do aplicativo, como permitir que você carregue recursos drawable usando o arquivo de
na tela do carro, iniciar um app no carro usando intents,
e sinalizando se seu app deve exibir o mapa no tema escuro.
Implementar a navegação na tela
Os apps costumam apresentar uma série de telas diferentes, cada uma possivelmente usando modelos diferentes em que o usuário pode navegar enquanto interage com a interface exibida na tela.
A classe ScreenManager
fornece
uma pilha de telas que pode ser usada para enviar telas que podem ser abertas automaticamente
quando o usuário seleciona um botão "Voltar" na tela do carro ou usa o hardware correspondente
disponível em alguns carros.
O snippet a seguir mostra como adicionar uma ação "Voltar" a um modelo de mensagem como bem como uma ação que abre uma nova tela quando selecionada pelo usuário:
Kotlin
val template = MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( Action.Builder() .setTitle("Next screen") .setOnClickListener { screenManager.push(NextScreen(carContext)) } .build()) .build()
Java
MessageTemplate template = new MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( new Action.Builder() .setTitle("Next screen") .setOnClickListener( () -> getScreenManager().push(new NextScreen(getCarContext()))) .build()) .build();
O objeto Action.BACK
é uma
Action
padrão que invoca automaticamente
ScreenManager.pop
.
Esse comportamento pode ser modificado usando a
instância OnBackPressedDispatcher
disponível no
CarContext
.
Para garantir que o app seja seguro para usar enquanto dirige, a pilha de telas pode ter no máximo profundidade de cinco telas. Consulte as Restrições de modelo. para mais detalhes.
Atualizar o conteúdo de um modelo
Seu app pode solicitar o conteúdo de um
Screen
seja invalidado chamando o método
Screen.invalidate
.
Em seguida, o anfitrião chama de volta para o
Screen.onGetTemplate
para recuperar o modelo com o novo conteúdo.
Ao atualizar um Screen
,
é importante entender o conteúdo específico do modelo que pode ser atualizado
portanto, o host não conta o novo modelo na cota de modelos.
Consulte a seção Restrições de modelo para mais detalhes.
Recomendamos que você estruture suas telas para que haja uma
um mapeamento entre um Screen
e o tipo
modelo retornado pela implementação de onGetTemplate
.
Desenhar mapas
Os apps de navegação e ponto de interesse (PDI) que usam os modelos a seguir podem
desenhar mapas acessando um Surface
:
Modelo | Permissão do modelo | Orientações sobre categorias |
---|---|---|
NavigationTemplate |
androidx.car.app.NAVIGATION_TEMPLATES |
Navegação |
MapWithContentTemplate |
androidx.car.app.NAVIGATION_TEMPLATES OU androidx.car.app.MAP_TEMPLATES |
Navegação, POI |
MapTemplate (descontinuado) |
androidx.car.app.NAVIGATION_TEMPLATES |
Navegação |
PlaceListNavigationTemplate (descontinuado) |
androidx.car.app.NAVIGATION_TEMPLATES |
Navegação |
RoutePreviewNavigationTemplate (descontinuado) |
androidx.car.app.NAVIGATION_TEMPLATES |
Navegação |
Declarar a permissão de exibição
Além da permissão necessária para o modelo usado pelo app,
o app precisa declarar a permissão androidx.car.app.ACCESS_SURFACE
na
AndroidManifest.xml
para ter acesso à plataforma:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
...
</manifest>
Acessar a superfície
Para acessar o Surface
fornecido pelo host, é necessário implementar um
SurfaceCallback
e fornecer
essa implementação ao serviço de carro AppManager
. O Surface
atual é transmitido para o
SurfaceCallback
no parâmetro SurfaceContainer
dos
callbacks onSurfaceAvailable()
e onSurfaceDestroyed()
.
Kotlin
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
Java
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
Entender a área visível da superfície
O host pode desenhar elementos da interface do usuário para os modelos na parte
de cima do mapa. O host comunica a área da superfície com certeza
desobstruída e totalmente visível para o usuário chamando
SurfaceCallback.onVisibleAreaChanged
. Além disso, para minimizar o número de mudanças, ele chama o método
SurfaceCallback.onStableAreaChanged
com o menor retângulo, que sempre fica visível com base no
modelo atual.
Por exemplo, quando um app de navegação usa o
NavigationTemplate
com uma faixa de ação na parte de cima, essa faixa pode ficar oculta
quando o usuário não interage com a tela há um tempo para fazer mais
espaço para o mapa. Nesse caso, há um callback para onStableAreaChanged
e
onVisibleAreaChanged
com o mesmo retângulo. Quando a faixa de ação está oculta,
apenas onVisibleAreaChanged
é chamado com a área maior. Se o usuário
interagir com a tela, novamente apenas o onVisibleAreaChanged
será chamado com
o primeiro retângulo.
Oferecer suporte ao tema escuro
Os apps precisam redesenhar o mapa na instância de Surface
com as cores escuras
adequadas quando o host determina que as condições justificam esse uso, conforme descrito em
Qualidade do app Android para carros.
Para decidir se você precisa desenhar um mapa escuro, use o
método
CarContext.isDarkMode
. Sempre que o status do tema escuro mudar, você vai receber uma chamada para
Session.onCarConfigurationChanged
.
Permitir que os usuários interajam com o mapa
Ao usar os modelos a seguir, você pode adicionar suporte à interação dos usuários com os mapas que você desenha, como permitir que eles vejam diferentes partes de um mapa usando zoom e movimento.
Modelo | Interatividade com suporte desde o nível da API Car App |
---|---|
NavigationTemplate |
2 |
PlaceListNavigationTemplate (descontinuado) |
4 |
RoutePreviewNavigationTemplate (descontinuado) |
4 |
MapTemplate (descontinuado) |
5 (introdução do modelo) |
MapWithContentTemplate |
7 (introdução do modelo) |
Implementar callbacks de interatividade
A interface SurfaceCallback
tem vários métodos de callback que podem ser implementados para adicionar interatividade aos mapas criados
com os modelos na seção anterior:
Interação | Método SurfaceCallback |
Com suporte desde o nível da API Car App |
---|---|---|
Tocar | onClick |
5 |
Fazer gesto de pinça para aplicar zoom | onScale |
2 |
Arrastar com um único toque | onScroll |
2 |
Deslizar rapidamente com um único toque | onFling |
2 |
Tocar duas vezes | onScale (com fator de escalonamento determinado pelo host do modelo) |
2 |
Alerta giratório no modo "Movimentar" | onScroll (com o fator de distância determinado pelo host do modelo) |
2 |
Adicionar uma faixa de ações no mapa
Esses modelos podem ter uma faixa de ações no mapa para ações relacionadas a ele, como aumentar e diminuir o zoom, recentralizar, mostrar uma bússola e outras ações que você escolher mostrar. A faixa de ações no mapa pode ter até quatro botões somente com ícones que podem ser atualizados sem afetar a profundidade da tarefa. Ele fica oculto durante o estado inativo e reaparece no estado ativo.
Para receber callbacks de interatividade do mapa,
precisa adicionar um botão Action.PAN
à faixa de ações no mapa. Quando o usuário
pressiona o botão de movimentação, o host entra no modo de movimentação, conforme descrito na seção
a seguir.
Se o app omitir o botão Action.PAN
na faixa de ações, ele não vai receber entradas do usuário dos
métodos SurfaceCallback
, e o host sairá de modos de movimentação
ativados anteriormente.
Em uma tela touchscreen, o botão de movimentação não é mostrado.
Entender o modo de movimentação
No modo de movimentação, o host do modelo converte a entrada do usuário de
dispositivos de entrada sem toque, como controles giratórios e touchpads, em métodos
SurfaceCallback
adequados. Responda à ação do usuário para entrar ou sair do modo de movimentação
com o
método setPanModeListener
no NavigationTemplate.Builder
. O host poderá ocultar outros componentes
de interface no modelo enquanto o usuário estiver no modo de movimentação.
Interagir com o usuário
Seu app pode interagir com o usuário usando padrões semelhantes aos de um app para dispositivos móveis.
Processar entrada do usuário
Seu app pode responder à entrada do usuário transmitindo os listeners adequados
aos estilos compatíveis. O snippet a seguir mostra como criar um
modelo Action
que define um
OnClickListener
que
chama um método definido pelo código do app:
Kotlin
val action = Action.Builder() .setTitle("Navigate") .setOnClickListener(::onClickNavigate) .build()
Java
Action action = new Action.Builder() .setTitle("Navigate") .setOnClickListener(this::onClickNavigate) .build();
O método onClickNavigate
pode iniciar o
app padrão de navegação para carro
usando o método
CarContext.startCarApp
:
Kotlin
private fun onClickNavigate() { val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)) carContext.startCarApp(intent) }
Java
private void onClickNavigate() { Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)); getCarContext().startCarApp(intent); }
Para mais detalhes sobre como iniciar aplicativos, incluindo o formato da
ACTION_NAVIGATE
, consulte Iniciar um app para carro com uma intent
nesta seção.
Algumas ações, como as que exigem direcionar o usuário para continuar a
interação nos dispositivos móveis, são permitidas apenas quando o carro está parado.
Você pode usar o
ParkedOnlyOnClickListener
para implementar essas ações. Se o carro não estiver parado, o host vai mostrar uma
indicação ao usuário de que a ação não é permitida nesse caso. Se o carro
estiver estacionado, o código será executado normalmente. O snippet a seguir mostra como
usar ParkedOnlyOnClickListener
para abrir uma tela de configurações no dispositivo móvel:
Kotlin
val row = Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone)) .build()
Java
Row row = new Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone)) .build();
Mostrar notificações
As notificações enviadas para o dispositivo móvel só vão aparecer na tela do carro se
eles são estendidos com um
CarAppExtender
Alguns atributos de notificação, como título, texto, ícone e ações do conteúdo,
podem ser definidas no CarAppExtender
, substituindo os atributos da notificação.
quando elas aparecerem na tela do carro.
O snippet a seguir mostra como enviar uma notificação para a tela do carro com um título diferente daquele exibido no dispositivo móvel:
Kotlin
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build()
Java
Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( new CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build();
As notificações podem afetar as seguintes partes da interface do usuário:
- Uma notificação de alerta (HUN, sigla em inglês) poderá ser exibida para o usuário.
- É possível adicionar uma entrada à central de notificações, com a opção de um ícone visível na coluna.
- Para apps de navegação, a notificação pode ser exibida no widget de coluna como descritos em Notificações de navegação guiada.
É possível escolher como configurar as notificações do app para afetar cada
um desses elementos da interface do usuário usando a prioridade da notificação, conforme descrito
na documentação do
CarAppExtender
.
Se
NotificationCompat.Builder.setOnlyAlertOnce
for chamado com o valor true
, uma notificação de alta prioridade será exibida como
HUN apenas uma vez.
Para mais informações sobre como projetar as notificações do seu app para carro, consulte a Guia do Google Design para direção sobre Notificações.
Mostrar avisos
Seu app pode mostrar um aviso usando
CarToast
, conforme mostrado neste snippet:
Kotlin
CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()
Java
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
Solicitar permissões
Caso o app precise de acesso a ações ou dados restritos, por exemplo,
localização: as regras padrão do Android
permissões
se aplicam. Para solicitar uma permissão, use o
método
CarContext.requestPermissions()
.
A vantagem de usar
CarContext.requestPermissions()
, em vez de usar
APIs padrão do Android, é
que você não precisa lançar seu próprio Activity
criar a caixa de diálogo de permissões. Além disso, é possível usar o mesmo código no
Android Auto e no Android Automotive OS, em vez de criar
fluxos dependentes da plataforma.
Definir o estilo da caixa de diálogo de permissões no Android Auto
No Android Auto, a caixa de diálogo de permissões do usuário vai aparecer no smartphone.
Por padrão, não haverá nenhum plano de fundo atrás da caixa de diálogo. Para definir um
segundo plano, declare um tema de app para carros na sua
arquivo AndroidManifest.xml
e defina o atributo carPermissionActivityLayout
para o tema do app para carros.
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
Em seguida, defina o atributo carPermissionActivityLayout
para o tema do app de carro:
<resources> <style name="MyCarAppTheme"> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
Iniciar um app para carro com uma intent
É possível chamar o método
CarContext.startCarApp
para executar uma das seguintes ações:
- Abrir o discador para fazer uma chamada telefônica
- Inicie a navegação guiada para um local com o app de navegação padrão para carros.
- Iniciar seu app com uma intent
O exemplo a seguir mostra como criar uma notificação com uma ação que abre
seu app com uma tela que mostra os detalhes de uma reserva de estacionamento.
Estenda a instância de notificação com uma intent de conteúdo que contenha uma
PendingIntent
unindo um objeto explícito
para a ação do seu app:
Kotlin
val notification = notificationBuilder ... .extend( CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(ComponentName(context, MyNotificationReceiver::class.java)), 0)) .build())
Java
Notification notification = notificationBuilder ... .extend( new CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), new Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(new ComponentName(context, MyNotificationReceiver.class)), 0)) .build());
O app também precisa declarar um
BroadcastReceiver
que é
invocada para processar a intent quando o usuário seleciona a ação no
interface de notificação e invoca
CarContext.startCarApp
com uma intent que inclui o URI de dados:
Kotlin
class MyNotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val intentAction = intent.action if (ACTION_VIEW_PARKING_RESERVATION == intentAction) { CarContext.startCarApp( intent, Intent(Intent.ACTION_VIEW) .setComponent(ComponentName(context, MyCarAppService::class.java)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))) } } }
Java
public class MyNotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String intentAction = intent.getAction(); if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) { CarContext.startCarApp( intent, new Intent(Intent.ACTION_VIEW) .setComponent(new ComponentName(context, MyCarAppService.class)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))); } } }
Por fim, o método
Session.onNewIntent
no seu app processa essa intent enviando a tela de reserva de estacionamento
à pilha, caso ainda não esteja na parte superior:
Kotlin
override fun onNewIntent(intent: Intent) { val screenManager = carContext.getCarService(ScreenManager::class.java) val uri = intent.data if (uri != null && MY_URI_SCHEME == uri.scheme && MY_URI_HOST == uri.schemeSpecificPart && ACTION_VIEW_PARKING_RESERVATION == uri.fragment ) { val top = screenManager.top if (top !is ParkingReservationScreen) { screenManager.push(ParkingReservationScreen(carContext)) } } }
Java
@Override public void onNewIntent(@NonNull Intent intent) { ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class); Uri uri = intent.getData(); if (uri != null && MY_URI_SCHEME.equals(uri.getScheme()) && MY_URI_HOST.equals(uri.getSchemeSpecificPart()) && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment()) ) { Screen top = screenManager.getTop(); if (!(top instanceof ParkingReservationScreen)) { screenManager.push(new ParkingReservationScreen(getCarContext())); } } }
Consulte a seção Exibir notificações para saber mais informações sobre como processar notificações para o app para carro.
Restrições de modelos
O host limita o número de modelos a serem exibidos para uma determinada tarefa de cinco, sendo que o último modelo precisa ser de um destes tipos:
Observe que esse limite se aplica ao número de modelos e não ao número de
Screen
instâncias na pilha. Para
exemplo, se um app envia dois modelos na tela A e depois envia para a tela
B: ele agora pode enviar mais três modelos. Como alternativa, se cada tela for estruturada
para enviar um único modelo, o aplicativo pode enviar cinco instâncias de tela para o
pilha ScreenManager
.
Há casos especiais para essas restrições: atualizações de modelo e retorno e de redefinição de senha.
Atualizações de modelos
Algumas atualizações de conteúdo não são contabilizadas no limite de modelos. Em geral,
se um app envia um novo modelo do mesmo tipo e com
o mesmo conteúdo principal do anterior, o novo modelo não é
contabilizado na cota. Por exemplo, a atualização do estado de alternância de uma linha em um
ListTemplate
não é
considerada na cota. Consulte a documentação de modelos individuais para saber
mais sobre quais tipos de atualizações de conteúdo podem ser considerados uma atualização.
Operações de retorno
Para ativar subfluxos em uma tarefa, o host detecta quando um app está abrindo uma
Screen
da pilha ScreenManager
e atualiza
a cota restante com base no número de modelos que o app está
retornando.
Por exemplo, se o app envia dois modelos na tela A e depois envia tela B e enviar mais dois modelos, o aplicativo terá uma cota restante. Se o aplicativo volta para a tela A, o host redefine a cota para três, porque o app voltou em dois modelos.
Ao retornar a uma tela, um app precisa enviar um modelo do mesmo tipo que o último enviado por essa tela. Enviar qualquer outro tipo de modelo causa um erro. Porém, contanto que o tipo permaneça o mesmo durante uma operação de retorno, um aplicativo poderá modificar livremente o conteúdo do modelo sem afetar a cota.
Redefinir operações
Alguns modelos têm uma semântica especial que representa o final de uma tarefa. Para
exemplo, os
NavigationTemplate
é uma visualização que deve permanecer na tela e ser atualizada com as novas
instruções passo a passo para o consumo do usuário. Quando ela chega a um desses
modelos, o host redefine a cota do modelo, tratando esse modelo como se
é a primeira etapa de uma nova tarefa. Isso permite que o app inicie uma nova tarefa.
Consulte a documentação de modelos individuais para ver quais deles acionam uma
redefinição no host.
Se o host receber uma intent para iniciar o aplicativo por uma ação de notificação ou no acesso rápido, a cota também é redefinida. Esse mecanismo permite que um app inicie um novo fluxo de tarefas pelas notificações e é válido até mesmo quando um app já está vinculado e em primeiro plano.
Consulte a seção Exibir notificações para mais detalhes sobre como mostrar as notificações do app na tela do carro. Consulte a Seção Iniciar um app para carro com uma intent para informações sobre como para iniciar o app a partir de uma ação de notificação.
API Connection
Você pode determinar se o app está sendo executado no Android Auto ou no Android.
o Automotive OS usando o
API CarConnection
para
recuperar informações de conexão no momento da execução.
Por exemplo, na Session
do app de carro, inicialize uma CarConnection
e
assine as atualizações de LiveData
:
Kotlin
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
Java
new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);
No observador, é possível reagir a mudanças no estado da conexão:
Kotlin
fun onConnectionStateUpdated(connectionState: Int) { val message = when(connectionState) { CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit" CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS" CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto" else -> "Unknown car connection type" } CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show() }
Java
private void onConnectionStateUpdated(int connectionState) { String message; switch(connectionState) { case CarConnection.CONNECTION_TYPE_NOT_CONNECTED: message = "Not connected to a head unit"; break; case CarConnection.CONNECTION_TYPE_NATIVE: message = "Connected to Android Automotive OS"; break; case CarConnection.CONNECTION_TYPE_PROJECTION: message = "Connected to Android Auto"; break; default: message = "Unknown car connection type"; break; } CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show(); }
API Constraints
Carros diferentes podem permitir que um número diferente de
instâncias de Item
seja mostrado ao
usuário por vez. Use o
ConstraintManager
para verificar o limite de conteúdo no tempo de execução e definir o número adequado de itens
nos modelos.
Comece recebendo um ConstraintManager
do CarContext
:
Kotlin
val manager = carContext.getCarService(ConstraintManager::class.java)
Java
ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);
Em seguida, consulte o objeto ConstraintManager
recuperado para encontrar o limite de conteúdo
relevante. Por exemplo, para saber o número de itens que podem ser mostrados em
uma grade, chame
getContentLimit
com
CONTENT_LIMIT_TYPE_GRID
:
Kotlin
val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)
Java
int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);
Adicionar um fluxo de login
Caso seu app ofereça uma experiência de login para os usuários, você pode usar modelos como
o SignInTemplate
e o LongMessageTemplate
com a API Car App nível 2 e mais recentes para processar o login no seu app na
unidade principal do carro.
Para criar um SignInTemplate
, defina um SignInMethod
. O carro
Atualmente, a biblioteca de apps oferece suporte aos seguintes métodos de login:
InputSignInMethod
para fazer login com nome de usuário/senha.PinSignInMethod
para login com o PIN, em que o usuário vincula a conta pelo smartphone usando um PIN exibido na unidade principal.ProviderSignInMethod
para o login do provedor, como Login do Google e um toque.QRCodeSignInMethod
para login com um QR code, em que o usuário lê um QR code para concluir o login. o celular. Esse recurso está disponível com a API Car de nível 4 e mais recentes.
Por exemplo, para implementar um modelo que colete a senha do usuário, comece criando um InputCallback
para processar e validar a entrada do usuário:
Kotlin
val callback = object : InputCallback { override fun onInputSubmitted(text: String) { // You will receive this callback when the user presses Enter on the keyboard. } override fun onInputTextChanged(text: String) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } }
Java
InputCallback callback = new InputCallback() { @Override public void onInputSubmitted(@NonNull String text) { // You will receive this callback when the user presses Enter on the keyboard. } @Override public void onInputTextChanged(@NonNull String text) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } };
É necessário um InputCallback
para o InputSignInMethod
Builder
.
Kotlin
val passwordInput = InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build()
Java
InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build();
Por fim, use o novo InputSignInMethod
para criar um SignInTemplate
.
Kotlin
SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build()
Java
new SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build();
Usar o AccountManager
Os apps Android Automotive OS que têm autenticação precisam usar o AccountManager pelos seguintes motivos:
- Melhor UX e gerenciamento de contas facilitado: os usuários podem gerenciar todas as informações com facilidade as contas deles no menu de contas das configurações do sistema, incluindo as opções e logout.
- "Convidado" experiências: como os carros são dispositivos compartilhados, os OEMs podem permitir experiências dos visitantes no veículo, quando não é possível adicionar contas.
Adicionar variantes de string de texto
Tamanhos de tela de carro diferentes podem mostrar quantidades distintas de texto. Com a API Car App
nível 2 e mais recentes, é possível especificar múltiplas variantes de uma string de texto para se adequar
melhor à tela. Para ver onde as variantes de texto são aceitas, procure modelos e
componentes que usem um CarText
.
Você pode adicionar variantes de string de texto a um CarText
com o
método
CarText.Builder.addVariant()
:
Kotlin
val itemTitle = CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build()
Java
CarText itemTitle = new CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build();
Você pode usar esse CarText
, por exemplo, como o texto principal de um
GridItem
.
Kotlin
GridItem.Builder() .addTitle(itemTitle) ... .build()
Java
new GridItem.Builder() .addTitle(itemTitle) ... build();
Adicione strings em ordem da mais para a menos preferida, por exemplo, da mais longa para mais curta. O host escolhe a string de comprimento adequado, dependendo da quantidade de espaço disponível na tela do carro.
Adicionar CarIcons inline para linhas.
É possível adicionar ícones inline com texto para enriquecer o apelo visual do app usando
CarIconSpan
.
Consulte a documentação do
CarIconSpan.create
para mais informações sobre a criação desses spans. Consulte
Spantastic
o estilo de texto com períodos para uma visão geral de como funciona o estilo de texto com períodos.
Kotlin
val rating = SpannableString("Rating: 4.5 stars") rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ) val row = Row.Builder() ... .addText(rating) .build()
Java
SpannableString rating = new SpannableString("Rating: 4.5 stars"); rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars new CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ); Row row = new Row.Builder() ... .addText(rating) .build();
APIs de hardware para carros
A partir do nível 3 da API Car App, a biblioteca Car App tem APIs que podem ser usadas para acessar propriedades e sensores do veículo.
Requisitos
Para usar as APIs com o Android Auto, comece adicionando uma dependência de
androidx.car.app:app-projected
ao arquivo build.gradle
do módulo do Android
Auto. Para o Android Automotive OS, adicione uma dependência de
androidx.car.app:app-automotive
ao arquivo build.gradle
do módulo do Android
Automotive OS.
Além disso, no arquivo AndroidManifest.xml
, você precisa:
declarar as permissões relevantes necessárias para
solicitar os dados do carro que você quer usar. Observe que essas permissões também devem ser
concedida pelo usuário. Você pode usar o
mesmo código no Android Auto e no Android Automotive OS, em
do que a necessidade de criar fluxos dependentes da plataforma. No entanto, as permissões necessárias
são diferentes.
Informações do carro
Esta tabela descreve as propriedades exibidas pelas
APIs CarInfo
e as
permissões necessárias para usá-las:
Métodos | Propriedades | Permissões do Android Auto | Permissões do Android Automotive OS | Com suporte desde o nível da API Car App |
---|---|---|---|---|
fetchModel |
Marca, modelo, ano | android.car.permission.CAR_INFO |
3 | |
fetchEnergyProfile |
Tipos de conector de VE, tipos de combustível | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_INFO |
3 |
fetchExteriorDimensions
Esses dados estão disponíveis apenas em alguns veículos com o Android Automotive OS que executam a API 30 ou mais recente |
Dimensões externas | N/A | android.car.permission.CAR_INFO |
7 |
addTollListener
removeTollListener |
Estado e tipo do cartão de pedágio | 3 | ||
addEnergyLevelListener
removeEnergyLevelListener |
Nível da bateria, nível de combustível, nível de combustível baixo, autonomia restante | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_ENERGY ,android.car.permission.CAR_ENERGY_PORTS ,android.car.permission.READ_CAR_DISPLAY_UNITS
|
3 |
addSpeedListener
removeSpeedListener |
Velocidade bruta, velocidade de exibição (mostrada no painel do carro) | com.google.android.gms.permission.CAR_SPEED |
android.car.permission.CAR_SPEED ,android.car.permission.READ_CAR_DISPLAY_UNITS |
3 |
addMileageListener
removeMileageListener |
Distância do odômetro | com.google.android.gms.permission.CAR_MILEAGE |
Esses dados não estão disponíveis no Android Automotive OS para apps instalados da Play Store. | 3 |
Por exemplo, para receber o intervalo restante, instancie um
objeto CarInfo
e
crie e registre um OnCarDataAvailableListener
:
Kotlin
val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo val listener = OnCarDataAvailableListener<EnergyLevel> { data -> if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) { val rangeRemaining = data.rangeRemainingMeters.value } else { // Handle error } } carInfo.addEnergyLevelListener(carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener)
Java
CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo(); OnCarDataAvailableListener<EnergyLevel> listener = (data) -> { if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) { float rangeRemaining = data.getRangeRemainingMeters().getValue(); } else { // Handle error } }; carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener);
Não suponha que os dados do carro estejam sempre disponíveis.
Se você receber um erro, verifique
status de
o valor solicitado para entender melhor por que os dados solicitados não
não poderão ser recuperados. Consulte a
documentação de referência para
a definição completa da classe CarInfo
.
CarSensors
A classe CarSensors
dá acesso ao acelerômetro, giroscópio, bússola e
dados de local. A disponibilidade desses valores pode depender do
OEM. O formato dos dados do acelerômetro, giroscópio e bússola é
da mesma forma que receberia
API SensorManager
. Por exemplo,
para verificar a direção do veículo:
Kotlin
val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors val listener = OnCarDataAvailableListener<Compass> { data -> if (data.orientations.status == CarValue.STATUS_SUCCESS) { val orientation = data.orientations.value } else { // Data not available, handle error } } carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener)
Java
CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors(); OnCarDataAvailableListener<Compass> listener = (data) -> { if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) { List<Float> orientations = data.getOrientations().getValue(); } else { // Data not available, handle error } }; carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener);
Para acessar os dados de localização do carro, você também precisa declarar e solicitar a
permissão android.permission.ACCESS_FINE_LOCATION
.
Teste
Para simular dados do sensor ao testar no Android Auto, consulte a Sensores e Sensores de configuração do Guia da unidade principal da área de trabalho. Simular dados do sensor em testes no Android o Automotive OS, consulte a seção Emulate hardware estado da interface do Android Guia do emulador do Automotive OS.
Ciclos de vida de CarAppService, Session e Screen
As classes Session
e
Screen
implementam a
interface LifecycleOwner
. Conforme
o usuário interage com o app, os callbacks de ciclo de vida dos objetos
Session
e Screen
são invocados, conforme descrito nos diagramas a seguir.
Os ciclos de vida de CarAppService e Session
Para mais detalhes, consulte a documentação
Session.getLifecycle
.
O ciclo de vida de Screen
Para saber todos os detalhes, consulte a documentação do
método Screen.getLifecycle
.
Gravar do microfone do carro
Usar o
CarAppService
e as
API CarAudioRecord
,
você pode permitir que o app acesse o microfone do carro do usuário. Os usuários precisam conceder
permissão ao app para acessar o microfone do carro. O app pode gravar e
processar a entrada do usuário.
Permissão para gravar
Antes de gravar qualquer áudio, é necessário declarar a permissão de gravação no seu
AndroidManifest.xml
e solicite que o usuário a conceda.
<manifest ...>
...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
...
</manifest>
Você precisa solicitar a permissão para gravar no momento da execução. Consulte a solicitação de permissões para detalhes sobre como solicitar uma permissão no app do carro.
Gravar áudio
Depois que o usuário der permissão para gravar, você poderá gravar o áudio e processar a gravação.
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) carAudioRecord.startRecording() val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording()
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); carAudioRecord.startRecording(); byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE]; while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording();
Seleção de áudio
Ao gravar com o microfone do carro, primeiro adquira o foco de áudio para garantir que todas as mídias em andamento sejam interrompidas. Se você perder o foco de áudio, interrompa a gravação.
Veja um exemplo de como adquirir a seleção de áudio:
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) // Take audio focus so that user's media is not recorded val audioAttributes = AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build() val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener { state: Int -> if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording() } } .build() if (carContext.getSystemService(AudioManager::class.java) .requestAudioFocus(audioFocusRequest) != AudioManager.AUDIOFOCUS_REQUEST_GRANTED ) { // Don't record if the focus isn't granted return } carAudioRecord.startRecording() // Process the audio and abandon the AudioFocusRequest when done
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); // Take audio focus so that user's media is not recorded AudioAttributes audioAttributes = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build(); AudioFocusRequest audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener(state -> { if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording(); } }) .build(); if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest) != AUDIOFOCUS_REQUEST_GRANTED) { // Don't record if the focus isn't granted return; } carAudioRecord.startRecording(); // Process the audio and abandon the AudioFocusRequest when done
Biblioteca de testes
A Biblioteca de testes
do Android para carros oferece classes auxiliares
que podem ser usadas para validar o comportamento do app em um ambiente de teste.
Por exemplo, o
SessionController
permite que você simule uma conexão com o host e verifique se a
Screen
e o
Template
corretos são criados e
retornados.
Consulte os exemplos de uso para conferir exemplos de uso.
Informar um problema na biblioteca Android for Cars App
Se você encontrar um problema com a biblioteca, informe-o usando o Google Issue Tracker. Preencha todas as informações solicitadas no modelo de problema.
Criar novo problema (link em inglês)
Antes de informar um novo problema, verifique se ele está listado na versão da biblioteca ou relatados na lista de problemas. Inscreva-se e vote nos problemas clicando na estrela de um deles no Issue Tracker. Para saber mais, consulte Inscrever-se em um problema.