Esta seção detalha os diferentes recursos da biblioteca que você pode usar para implementar a funcionalidade do seu app de navegação guiada.
Declarar suporte à navegação no manifesto
Seu app de navegação precisa declarar a
categoria de app para carros androidx.car.app.category.NAVIGATION
no filtro de
intent de CarAppService
:
<application>
...
<service
...
android:name=".MyNavigationCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.NAVIGATION"/>
</intent-filter>
</service>
...
<application>
Suporte a intents de navegação
Para oferecer suporte a intents de navegação no seu app, incluindo as que vêm do
Google Assistente usando uma consulta por voz, o app precisa processar a
intent CarContext.ACTION_NAVIGATE
nos métodos
Session.onCreateScreen
e
Session.onNewIntent
.
Consulte a documentação de
CarContext.startCarApp
para ver detalhes sobre o formato da intent.
Acessar os modelos de navegação
Os apps de navegação podem acessar os seguintes modelos projetados especificamente para apps de navegação. Todos esses modelos exibem uma plataforma em segundo plano que o app pode acessar para desenhar o mapa, junto com outras informações fornecidas pelo app que variam de acordo com o modelo.
NavigationTemplate
: exibe o mapa com uma mensagem informativa opcional ou rotas e estimativas de viagem durante a navegação ativa.MapTemplate
: apresenta uma versão compacta de uma lista (como noListTemplate
) ou de um painel (informações detalhadas com ações em destaque, como noPaneTemplate
) ao lado de um mapa.PlaceListNavigationTemplate
: exibe uma lista de lugares que podem ter marcadores correspondentes desenhados no mapa.RoutePreviewNavigationTemplate
: exibe uma lista de rotas, em que uma pode ser selecionada e destacada no mapa.
Para ver mais detalhes sobre como projetar a interface do usuário do seu app de navegação usando esses modelos, consulte as diretrizes de design da biblioteca de apps Android para carros.
Para ter acesso aos modelos de navegação, seu app precisa declarar
a permissão androidx.car.app.NAVIGATION_TEMPLATES
no
AndroidManifest.xml
:
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>
Desenhar o mapa
Os aplicativos de navegação podem acessar uma Surface
para desenhar o mapa nos modelos relevantes.
Um objeto SurfaceContainer
pode
ser acessado ao definir uma instância de SurfaceCallback
para o serviço de carro
AppManager
:
Kotlin
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
Java
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
O SurfaceCallback
fornece um
callback quando o SurfaceContainer
está disponível com outros callbacks no momento em que as propriedades da Surface
mudam.
Para ter acesso à plataforma, seu app precisa declarar a
permissão androidx.car.app.ACCESS_SURFACE
no AndroidManifest.xml
:
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE"/>
Área visível do mapa
O host pode desenhar elementos da interface do usuário para diferentes modelos na parte
de cima do mapa. Ele vai comunicar a área que certamente não vai estar fechada
e que vai ficar totalmente visível para o usuário chamando o método
SurfaceCallback.onVisibleAreaChanged
. Além disso, para minimizar o número de mudanças, o host também vai
chamar o método
SurfaceCallback.onStableAreaChanged
com o menor retângulo, que sempre vai ficar visível com base no
modelo atual.
Por exemplo, quando um app de navegação está usando 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á algum tempo, liberando mais espaço para o mapa. Nesse
caso, vai haver um callback para onStableAreaChanged
e
onVisibleAreaChanged
com o mesmo retângulo. Quando a faixa de ação estiver oculta,
somente onVisibleAreaChanged
será chamado com a área maior. Se o usuário
interagir com a tela, novamente apenas onVisibleAreaChanged
será chamado com
o primeiro retângulo.
Modo escuro
Os aplicativos de navegação precisam redesenhar o mapa na instância de Surface
com as
cores escuras adequadas quando o host determina que as condições as justificam, conforme
descrito nas
diretrizes de qualidade de apps do Android Auto.
Para decidir se você precisa desenhar um mapa escuro, use o
método
CarContext.isDarkMode
. Sempre que o status do modo escuro for mudado, você vai receber uma chamada para
Session.onCarConfigurationChanged
.
Metadados de navegação
Os aplicativos de navegação precisam comunicar outros metadados de navegação ao host. O host usa as informações para fornecer dados à unidade principal do veículo e impedir que aplicativos de navegação entrem em conflito com os recursos compartilhados.
Os metadados de navegação são fornecidos pelo
serviço de carro NavigationManager
,
que pode ser acessado em
CarContext
:
Kotlin
val navigationManager = carContext.getCarService(NavigationManager::class.java)
Java
NavigationManager navigationManager = carContext.getCarService(NavigationManager.class);
Iniciar, encerrar e interromper a navegação
Para que o host gerencie vários apps de navegação, notificações de roteamento
e dados de cluster do veículo, ele precisa estar ciente do estado atual da
navegação. Quando um usuário inicia a navegação, o app precisa chamar
NavigationManager.navigationStarted
.
Da mesma forma, quando a navegação termina, por exemplo, quando o usuário chega ao
destino ou quando ele cancela a navegação, o app precisa chamar
NavigationManager.navigationEnded
.
Chame
NavigationManager.navigationEnded
apenas quando o usuário terminar a navegação. Por exemplo, se você precisar recalcular
a rota no meio de uma viagem,
use
Trip.Builder.setLoading(true)
.
Ocasionalmente, o host vai precisar de um app para interromper a navegação e chamar
stopNavigation
em um
objeto NavigationManagerListener
fornecido pelo seu aplicativo usando
NavigationManager.setListener
.
Para isso, o app vai precisar parar de emitir informações da próxima curva na exibição do cluster,
nas notificações de navegação e na orientação por voz.
Informações da viagem
Durante a navegação ativa, o app precisa chamar
NavigationManager.updateTrip
.
As informações fornecidas nessa chamada vão ser usadas no cluster do veículo e
nos avisos na tela. Nem todas as informações podem ser mostradas para o usuário, dependendo do
veículo em questão. Por exemplo, a Desktop Head Unit mostra
a Step
adicionada à
Trip
, mas não mostra
a informação do
Destination
.
Para testar se as informações estão chegando ao cluster, a ferramenta Desktop Head
Unit (DHU) pode ser configurada para mostrar uma exibição de cluster simples. Crie um
arquivo cluster.ini
com o seguinte conteúdo:
[general]
instrumentcluster = true
É possível invocar a DHU com um parâmetro de linha de comando adicional:
dhu -c cluster.ini
Personalizar TravelEstimate com texto e/ou ícone
Para personalizar a estimativa de viagem com texto e/ou ícone, use os
métodos
setTripIcon
de TravelEstimate.Builder
e/ou
setTripText
. O
NavigationTemplate
usa
TravelEstimate
para definir texto e ícones opcionais ao lado ou no lugar dos dados de horário previsto de chegada, tempo restante e distância restante.

O snippet a seguir usa os métodos
setTripIcon
e
setTripText
do TravelEstimate.Builder
para personalizar a estimativa de viagem:
Kotlin
TravelEstimate.Builder(Distance.create(...), DateTimeWithZone.create(...)) ... .setTripIcon(CarIcon.Builder(...).build()) .setTripText(CarText.create(...)) .build()
Java
new TravelEstimate.Builder(Distance.create(...), DateTimeWithZone.create(...)) ... .setTripIcon(CarIcon.Builder(...).build()) .setTripText(CarText.create(...)) .build();
Notificações da navegação guiada
As instruções de navegação guiada (TBT, sigla em inglês) podem ser fornecidas com uma notificação de navegação atualizada com frequência. Para ser tratado como uma notificação de navegação na tela do carro, o builder da notificação precisa fazer o seguinte:
- Marcar a notificação como em andamento com o
método
NotificationCompat.Builder.setOngoing
. - Definir a categoria da notificação como
Notification.CATEGORY_NAVIGATION
. - Estender a notificação com um
CarAppExtender
.
Uma notificação de navegação será exibida no widget de coluna na parte de baixo da
tela do carro. Se o nível de importância da notificação estiver definido como
IMPORTANCE_HIGH
, ela também vai ser exibida como uma notificação de alerta (HUN, sigla em inglês).
Se a importância não estiver definida com o
método
CarAppExtender.Builder.setImportance
,
a importância do canal de notificação
vai ser usada.
O app pode definir uma PendingIntent
no
CarAppExtender
que
vai ser enviada ao app quando o usuário tocar na HUN ou no widget de coluna.
Se
NotificationCompat.Builder.setOnlyAlertOnce
for chamado com o valor true
, uma notificação de alta importância vai ser emitida apenas
uma vez na HUN.
O snippet a seguir mostra como criar uma notificação de navegação:
Kotlin
NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) ... .setOnlyAlertOnce(true) .setOngoing(true) .setCategory(NotificationCompat.CATEGORY_NAVIGATION) .extend( CarAppExtender.Builder() .setContentTitle(carScreenTitle) ... .setContentIntent( PendingIntent.getBroadcast( context, ACTION_OPEN_APP.hashCode(), Intent(ACTION_OPEN_APP).setComponent( ComponentName(context, MyNotificationReceiver::class.java)), 0)) .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH) .build()) .build()
Java
new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) ... .setOnlyAlertOnce(true) .setOngoing(true) .setCategory(NotificationCompat.CATEGORY_NAVIGATION) .extend( new CarAppExtender.Builder() .setContentTitle(carScreenTitle) ... .setContentIntent( PendingIntent.getBroadcast( context, ACTION_OPEN_APP.hashCode(), new Intent(ACTION_OPEN_APP).setComponent( new ComponentName(context, MyNotificationReceiver.class)), 0)) .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH) .build()) .build();
Diretrizes para notificações de navegação guiada
Os apps de navegação precisam atualizar a notificação da navegação guiada regularmente com mudanças
de distância, o que atualiza o widget de coluna e mostra a notificação apenas como uma HUN.
Os apps podem controlar o comportamento da HUN definindo a importância da notificação com
o
método
CarAppExtender.Builder.setImportance
. Definir a importância como IMPORTANCE_HIGH
vai mostrar uma HUN, enquanto a definição
como qualquer outro valor vai apenas atualizar o widget de coluna.
Atualizar conteúdo do PlaceListNavigationTemplate
Você pode permitir que os motoristas atualizem o conteúdo com um simples toque de botão enquanto navegam
em listas de lugares criadas com o
PlaceListNavigationTemplate
.
Implemente o método
onContentRefreshRequested
da interface
OnContentRefreshListener
e use
PlaceListNavigationTemplate.Builder.setOnContentRefreshListener
para definir o listener no modelo e ativar a atualização da lista.
O snippet a seguir mostra a definição do listener no modelo.
Kotlin
PlaceListNavigationTemplate.Builder() ... .setOnContentRefreshListener { // Execute any desired logic ... // Then call invalidate() so onGetTemplate() is called again invalidate() } .build()
Java
new PlaceListNavigationTemplate.Builder() ... .setOnContentRefreshListener(() -> { // Execute any desired logic ... // Then call invalidate() so onGetTemplate() is called again invalidate(); }) .build();
O botão "Atualizar" só é exibido no cabeçalho do
PlaceListNavigationTemplate
quando o listener tem um valor.
Quando o motorista clica no botão "Atualizar", o
método onContentRefreshRequested
da implementação do seu
OnContentRefreshListener
é chamado. Em
onContentRefreshRequested
,
chame o método
Screen.invalidate
.
Em seguida, o host vai chamar o método
Screen.onGetTemplate
do app para recuperar o modelo com o conteúdo atualizado. Consulte
Como atualizar o conteúdo de um modelo para ver
mais informações sobre a atualização de modelos. Contanto que o próximo modelo
retornado por
onGetTemplate
seja do
mesmo tipo, ele vai ser contabilizado como uma atualização e não vai ser contabilizado na
cota do modelo.
Orientação por voz
Para reproduzir a orientação de navegação nos alto-falantes do carro, seu app precisa solicitar
seleção de áudio. Como parte da
AudioFocusRequest
, você precisa definir
o uso como AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
. Defina também
o ganho de seleção como AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
.
Simular a navegação
Para verificar a funcionalidade de navegação do seu app ao enviá-lo à
Google Play Store, o app precisa implementar o
callback
NavigationManagerCallback.onAutoDriveEnabled
. Quando esse callback é chamado, o app precisa simular o trajeto até o
destino escolhido quando o usuário inicia a navegação. O app pode sair desse
modo sempre que o ciclo de vida da Session
atual atinge o
estado
Lifecycle.Event.ON_DESTROY
.
Teste se a implementação de onAutoDriveEnabled
é chamada
executando o seguinte em uma linha de comando:
adb shell dumpsys activity service CAR_APP_SERVICE_NAME AUTO_DRIVE
Exemplo:
adb shell dumpsys activity service androidx.car.app.samples.navigation.car.NavigationCarAppService AUTO_DRIVE
App padrão de navegação para carro
No Android Auto, o app padrão de navegação para carro corresponde ao último app de navegação que o usuário iniciou. Esse é o app que, por exemplo, recebe as intents de navegação quando o usuário invoca comandos de navegação pelo assistente ou quando outro app envia uma intent para iniciar a navegação.
Permitir que os usuários interajam com seu mapa
Você pode adicionar suporte à interação com mapas, por exemplo, com zoom e movimentação, permitindo que os usuários vejam diferentes partes de um mapa. Cada modelo tem um requisito mínimo diferente de nível da API Car App. Consulte a tabela abaixo para verificar o nível mínimo do modelo que você quer implementar.
Modelo | Interatividade com suporte desde o nível da API Car App |
---|---|
NavigationTemplate | 2 |
PlaceListNavigationTemplate | 4 |
RoutePreviewNavigationTemplate | 4 |
MapTemplate | 5 |
Métodos do SurfaceCallback
O SurfaceCallback
tem vários
métodos de callback que permitem adicionar interatividade de mapas aos mapas criados com os
modelos NavigationTemplate
, PlaceListNavigationTemplate
, RoutePreviewNavigationTemplate
ou MapTemplate
:
onClick
,
onScroll
,
onScale
e
onFling
.
Consulte a tabela abaixo para saber como esses callbacks estão relacionados às interações do usuário.
Interação | Método SurfaceCallback |
Com suporte desde o nível da API Car App |
---|---|---|
Tocar | onClick |
5 |
Fazer gesto de pinça (zoom) | onScale |
2 |
Arrastar com um único toque | onScroll |
2 |
Deslizar rapidamente com um único toque | onFling |
2 |
Tocar duas vezes | onScale (com um fator de escalonamento determinado pelo host do modelo) |
2 |
Alerta giratório no modo Movimentar | onScroll (com um fator de distância determinado pelo host do modelo) |
2 |
Faixa de ações no mapa
Os modelos
NavigationTemplate
,
PlaceListNavigationTemplate
,
RoutePreviewNavigationTemplate
e MapTemplate
podem ter uma faixa de ações no mapa para ações relacionadas a ele, por exemplo, aumentar e
diminuir o zoom, recentralizar, exibir uma bússola ou qualquer outra ação que seja
possível exibir no app. A faixa de ações no mapa pode ter até quatro botões somente de ícones que podem
ser atualizados sem afetar a profundidade da tarefa. Assim como a faixa de ações, a faixa de ações no
mapa fica oculta no estado inativo e reaparece no estado ativo.
Para receber callbacks de interatividade no mapa, adicione um
botão Action.PAN
à faixa de ações no mapa. Se o app omitir o botão Action.PAN
na faixa de ações, você não vai receber entradas dos usuários dos métodos
SurfaceCallback
, e o host vai fechar qualquer modo de movimentação
ativado anteriormente. Quando o usuário pressiona o botão de movimentação, o host entra
no modo de movimentação. Em uma tela touchscreen, o botão de movimentação não será exibido.
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 controladores 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 pode ocultar outros componentes
de IU no modelo enquanto o usuário está no modo de movimentação.
Área estável
A área estável é atualizada entre os estados ativo e inativo. Seu app precisa desenhar informações relacionadas à condução, como velocidade, limite de velocidade ou avisos de rua, dependendo do tamanho da área estável, para que informações importantes não sejam escondidas pela faixa de ações no mapa.
Alertas de navegação no contexto
Um Alert
exibe informações
importantes para o motorista, com ações opcionais, sem sair do contexto
da tela de navegação. Para oferecer a melhor experiência ao motorista, o
Alert
funciona no
NavigationTemplate
para evitar o bloqueio da rota de navegação e minimizar a distração do motorista.
Alert
está disponível apenas no
NavigationTemplate
.
Para notificar um usuário fora do
NavigationTemplate
,
use uma notificação de alerta (HUN, na sigla em inglês), conforme explicado em
Exibir notificações.
Por exemplo, use Alert
para:
- informar o motorista sobre uma atualização relevante para a navegação atual, como uma mudança nas condições de trânsito;
- pedir ao motorista uma atualização relacionada à navegação atual, como a existência de um radar móvel;
- propor uma próxima tarefa e perguntar se o motorista vai aceitá-la ou não. Por exemplo, se o motorista quer pegar alguém no caminho.
Na forma básica, um Alert
consiste em um título e no
tempo da duração do Alert
. A duração é representada por uma barra de progresso. Também é
possível adicionar um subtítulo, um ícone e até duas
Action
s.

Depois que um Alert
é exibido, ele não
passa para outro modelo quando uma interação do motorista resulta na
saída do
NavigationTemplate
.
Ele permanece no
NavigationTemplate
original até o Alert
expirar, o usuário
realizar uma ação ou o app dispensar o
Alert
.
Configurar duração do alerta
Escolha uma duração de Alert
que
corresponda às necessidades do app. A duração recomendada para um Alert
de navegação é de 10 segundos. Consulte as
Diretrizes de design do Android para carros
para ver orientações.
Criar um alerta
Use o Alert.Builder
para criar uma instância de Alert
.
Kotlin
Alert.Builder( /*alertId*/ 1, /*title*/ CarText.create("Hello"), /*durationMillis*/ 5000 ) // The fields below are optional .addAction(firstAction) .addAction(secondAction) .setSubtitle(CarText.create(...)) .setIcon(CarIcon.APP_ICON) .setCallback(...) .build()
Java
new Alert.Builder( /*alertId*/ 1, /*title*/ CarText.create("Hello"), /*durationMillis*/ 5000 ) // The fields below are optional .addAction(firstAction) .addAction(secondAction) .setSubtitle(CarText.create(...)) .setIcon(CarIcon.APP_ICON) .setCallback(...) .build();
Para ouvir o cancelamento ou a dispensa do Alert
,
crie uma implementação da interface
AlertCallback
.
Veja os caminhos de chamada de
AlertCallback
:
Se o
Alert
expirar, o host vai chamar o métodoAlertCallback.onCancel
com o valorAlertCallback.REASON_TIMEOUT
. Em seguida, ele vai chamar o métodoAlertCallback.onDismiss
.Se o motorista clicar em um dos botões de ação, o host vai chamar
Action.OnClickListener
eAlertCallback.onDismiss
.Se não houver suporte aos
Alert
s, o host vai chamarAlertCallback.onCancel
com o valorAlertCallback.REASON_NOT_SUPPORTED
. O host não vai chamarAlertCallback.onDismiss
, já que oAlert
não foi exibido.
Mostrar um alerta
Para mostrar um Alert
, chame o método
AppManager.showAlert
,
disponível no
CarContext
do app.
// Show an alert
carContext.getCarService(AppManager.class).showAlert(alert)
- Chamar
showAlert
com umAlert
que tenha umalertId
igual aoAlert
que está sendo exibido no momento não resulta em nenhuma ação. OAlert
não é atualizado. Para atualizar oAlert
, você precisa recriar oAlert
com um novoalertId
. - Chamar
showAlert
com umAlert
que tenha umalertId
diferente doAlert
que está em exibição no momento dispensa oAlert
que está sendo exibido.
Dispensar um alerta
Embora um Alert
seja dispensado automaticamente
em razão do tempo limite ou da interação do motorista, você também pode dispensar um
Alert
manualmente. Por exemplo, é possível
dispensar um Alert
porque as
informações dele estão desatualizadas. Para dispensar um
Alert
chame o
método dismissAlert
com o
alertId
do Alert
.
// Dismiss the same alert
carContext.getCarService(AppManager.class).dismissAlert(alert.getId())
Chamar
dismissAlert
com um
alertId
que não corresponde ao
Alert
exibido no momento (se houver) não
resulta em nenhuma ação. Isso não gera uma exceção.