In questa pagina vengono descritte le diverse funzionalità della Raccolta di app per auto che puoi utilizzare per implementare la funzionalità dell'app di navigazione passo passo.
Dichiara il supporto per la navigazione nel tuo file manifest
La tua app di navigazione deve dichiarare androidx.car.app.category.NAVIGATION
categoria di app auto nell'intent
del relativo 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>
Supporta gli intent di navigazione
Per supportare gli intent di navigazione verso la tua app, inclusi quelli provenienti da
l'Assistente Google tramite una query vocale, l'app deve gestire
CarContext.ACTION_NAVIGATE
l'intento
Session.onCreateScreen
e
Session.onNewIntent
Consulta la documentazione su
CarContext.startCarApp
per informazioni dettagliate sul formato dell'intent.
Accedere ai modelli di navigazione
Le app di navigazione possono accedere ai seguenti modelli, che mostrano un'area in lo sfondo con la mappa e, durante la navigazione attiva, istruzioni passo passo indicazioni stradali.
NavigationTemplate
: mostra anche un messaggio informativo facoltativo e le stime di viaggio durante la navigazione attiva.MapWithContentTemplate
: Un modello che consente a un'app di visualizzare riquadri di mappe con un qualche tipo di contenuto (ad ad esempio un elenco). In genere, i contenuti vengono visualizzati come overlay sulla parte superiore riquadri della mappa, in cui le aree visibili e stabili si adattano ai contenuti.
Per ulteriori dettagli su come progettare l'interfaccia utente della tua app di navigazione utilizzando questi modelli, vedi App di navigazione.
Per ottenere l'accesso ai modelli di navigazione, la tua app deve dichiarare
l'autorizzazione androidx.car.app.NAVIGATION_TEMPLATES
nel relativo
AndroidManifest.xml
file:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>
...
</manifest>
Per disegnare le mappe è necessaria un'autorizzazione aggiuntiva.
Esegui la migrazione a MapWithContentTemplate
A partire dal Livello 7 dell'API Car App,
MapTemplate
,
PlaceListNavigationTemplate
,
e RoutePreviewNavigationTemplate
sono deprecate. I modelli deprecati continueranno a essere supportati,
ti consigliamo vivamente di eseguire la migrazione a MapWithContentTemplate
.
La funzionalità fornita da questi modelli può essere implementata
utilizzando l'MapWithContentTemplate
. Consulta i seguenti snippet per avere degli esempi:
Modello di mappa
Kotlin
// MapTemplate (deprecated) val template = MapTemplate.Builder() .setPane(paneBuilder.build()) .setActionStrip(actionStrip) .setHeader(header) .setMapController(mapController) .build() // MapWithContentTemplate val template = MapWithContentTemplate.Builder() .setContentTemplate( PaneTemplate.Builder(paneBuilder.build()) .setHeader(header) .build()) .setActionStrip(actionStrip) .setMapController(mapController) .build()
Java
// MapTemplate (deprecated) MapTemplate template = new MapTemplate.Builder() .setPane(paneBuilder.build()) .setActionStrip(actionStrip) .setHeader(header) .setMapController(mapController) .build(); // MapWithContentTemplate MapWithContentTemplate template = new MapWithContentTemplate.Builder() .setContentTemplate(new PaneTemplate.Builder(paneBuilder.build()) .setHeader(header) build()) .setActionStrip(actionStrip) .setMapController(mapController) .build();
Modello di navigazione per l'elenco dei luoghi
Kotlin
// PlaceListNavigationTemplate (deprecated) val template = PlaceListNavigationTemplate.Builder() .setItemList(itemListBuilder.build()) .setHeader(header) .setActionStrip(actionStrip) .setMapActionStrip(mapActionStrip) .build() // MapWithContentTemplate val template = MapWithContentTemplate.Builder() .setContentTemplate( ListTemplate.Builder() .setSingleList(itemListBuilder.build()) .setHeader(header) .build()) .setActionStrip(actionStrip) .setMapController( MapController.Builder() .setMapActionStrip(mapActionStrip) .build()) .build()
Java
// PlaceListNavigationTemplate (deprecated) PlaceListNavigationTemplate template = new PlaceListNavigationTemplate.Builder() .setItemList(itemListBuilder.build()) .setHeader(header) .setActionStrip(actionStrip) .setMapActionStrip(mapActionStrip) .build(); // MapWithContentTemplate MapWithContentTemplate template = new MapWithContentTemplate.Builder() .setContentTemplate(new ListTemplate.Builder() .setSingleList(itemListBuilder.build()) .setHeader(header) .build()) .setActionStrip(actionStrip) .setMapController(new MapController.Builder() .setMapActionStrip(mapActionStrip) .build()) .build();
Modello di navigazione in anteprima route
Kotlin
// RoutePreviewNavigationTemplate (deprecated) val template = RoutePreviewNavigationTemplate.Builder() .setItemList( ItemList.Builder() .addItem( Row.Builder() .setTitle(title) .build()) .build()) .setHeader(header) .setNavigateAction( Action.Builder() .setTitle(actionTitle) .setOnClickListener { ... } .build()) .setActionStrip(actionStrip) .setMapActionStrip(mapActionStrip) .build() // MapWithContentTemplate val template = MapWithContentTemplate.Builder() .setContentTemplate( ListTemplate.Builder() .setSingleList( ItemList.Builder() .addItem( Row.Builder() .setTitle(title) .addAction( Action.Builder() .setTitle(actionTitle) .setOnClickListener { ... } .build()) .build()) .build()) .setHeader(header) .build()) .setActionStrip(actionStrip) .setMapController( MapController.Builder() .setMapActionStrip(mapActionStrip) .build()) .build()
Java
// RoutePreviewNavigationTemplate (deprecated) RoutePreviewNavigationTemplate template = new RoutePreviewNavigationTemplate.Builder() .setItemList(new ItemList.Builder() .addItem(new Row.Builder() .setTitle(title)) .build()) .build()) .setHeader(header) .setNavigateAction(new Action.Builder() .setTitle(actionTitle) .setOnClickListener(() -> { ... }) .build()) .setActionStrip(actionStrip) .setMapActionStrip(mapActionStrip) .build(); // MapWithContentTemplate MapWithContentTemplate template = new MapWithContentTemplate.Builder() .setContentTemplate(new ListTemplate.Builder() .setSingleList(new ItemList.Builder() .addItem(new Row.Builder() .setTitle(title)) .addAction(new Action.Builder() .setTitle(actionTitle) .setOnClickListener(() -> { ... }) .build()) .build()) .build())) .setHeader(header) .build()) .setActionStrip(actionStrip) .setMapController(new MapController.Builder() .setMapActionStrip(mapActionStrip) .build()) .build();
Comunicare i metadati di navigazione
Le app di navigazione devono comunicare metadati di navigazione aggiuntivi con il . L'organizzatore utilizza le informazioni per fornire informazioni al all'unità principale del veicolo ed evitare conflitti tra le applicazioni di navigazione e risorse condivise.
I metadati di navigazione vengono forniti tramite
NavigationManager
accessibile dal
CarContext
:
Kotlin
val navigationManager = carContext.getCarService(NavigationManager::class.java)
Java
NavigationManager navigationManager = carContext.getCarService(NavigationManager.class);
Avviare, terminare e interrompere la navigazione
Per consentire all'organizzatore di gestire più app di navigazione, notifiche di percorso,
e dati cluster del veicolo, deve conoscere lo stato attuale
per la navigazione. Quando un utente avvia la navigazione, chiama
NavigationManager.navigationStarted
Analogamente, al termine della navigazione, ad esempio quando l'utente arriva al suo
destinazione o l'utente annulla la navigazione:
NavigationManager.navigationEnded
Chiama solo NavigationManager.navigationEnded
quando l'utente termina la navigazione. Ad esempio, se devi ricalcolare
il percorso a metà di una corsa, usa
Trip.Builder.setLoading(true)
.
A volte l'organizzatore ha bisogno di un'app per interrompere la navigazione e le chiamate
onStopNavigation
in
NavigationManagerCallback
fornito dalla tua app tramite
NavigationManager.setNavigationManagerCallback
.
L'app deve quindi interrompere l'invio di informazioni relative alla svolta successiva nel display del cluster.
notifiche di navigazione e la guida vocale.
Aggiorna le informazioni sulla corsa
Durante la navigazione attiva, chiama
NavigationManager.updateTrip
Le informazioni fornite in questa chiamata possono essere utilizzate dal cluster del veicolo e
di avvisi. A seconda del veicolo specifico, non tutti
le informazioni vengono mostrate all'utente.
Ad esempio, l'unità principale desktop (DHU) mostra
Step
aggiunto al
Trip
, ma non viene visualizzato
Destination
informazioni.
Disegno sulla visualizzazione del cluster
Per offrire l'esperienza utente più immersiva, potresti voler andare oltre mostrare i metadati di base sul display del cluster del veicolo. A partire dal Livello 6 dell'API Car App, è possibile eseguire il rendering delle app di navigazione i propri contenuti direttamente sul display del cluster (nei veicoli supportati), con le seguenti limitazioni:
- L'API cluster display non supporta i controlli di input
- La visualizzazione del cluster dovrebbe mostrare solo riquadri della mappa. La navigazione di un percorso attivo può può essere visualizzata su questi riquadri.
- L'API di visualizzazione del cluster supporta solo l'uso
NavigationTemplate
- A differenza delle schermate principali, le visualizzazioni del cluster potrebbero non mostrare in modo coerente tutti
Elementi UI di
NavigationTemplate
, come istruzioni passo passo, orario di arrivo stimato schede e azioni. I riquadri della mappa sono l'unica UI visualizzata in modo coerente .
- A differenza delle schermate principali, le visualizzazioni del cluster potrebbero non mostrare in modo coerente tutti
Elementi UI di
Dichiara l'assistenza per i cluster
Comunicare all'applicazione host che la tua app supporta il rendering sul cluster
devi aggiungere androidx.car.app.category.FEATURE_CLUSTER
<category>
al <intent-filter>
di CarAppService
come mostrato in
seguente snippet:
<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"/> <category android:name="androidx.car.app.category.FEATURE_CLUSTER"/> </intent-filter> </service> ... </application>
Ciclo di vita e gestione degli stati
A partire dal livello API 6, l'app Auto
flusso del ciclo di vita
rimane invariato, ma ora CarAppService::onCreateSession
utilizza il parametro
tipo SessionInfo
che fornisce
informazioni aggiuntive sul Session
da creare (vale a dire, lo spazio
e l'insieme di modelli supportati).
Le app possono utilizzare la stessa classe Session
per gestire sia
cluster e display principale oppure crea Sessions
specifici per il display da personalizzare
su ogni display (come illustrato nello snippet seguente).
Kotlin
override fun onCreateSession(sessionInfo: SessionInfo): Session { return if (sessionInfo.displayType == SessionInfo.DISPLAY_TYPE_CLUSTER) { ClusterSession() } else { MainDisplaySession() } }
Java
@Override @NonNull public Session onCreateSession(@NonNull SessionInfo sessionInfo) { if (sessionInfo.getDisplayType() == SessionInfo.DISPLAY_TYPE_CLUSTER) { return new ClusterSession(); } else { return new MainDisplaySession(); } }
Non vi sono garanzie su quando e se la visualizzazione del cluster viene fornita
è anche possibile che il cluster Session
sia l'unico Session
(per
Ad esempio, l'utente ha cambiato il display principale con un'altra app mentre la tua app
la navigazione attiva). Lo "standard" concordano sul fatto che l'app acquisisce il controllo
la visualizzazione del cluster solo dopo che è stato eseguito NavigationManager::navigationStarted
chiamato. Tuttavia, è possibile che all'app venga fornito il display del cluster
quando non è in corso alcuna navigazione attiva o che non venga mai fornito il cluster
display. Sta all'app gestire questi scenari eseguendo il rendering
stato di inattività dei riquadri della mappa.
L'host crea binder e istanze CarContext
separate per Session
. Questo
significa che, quando utilizzi metodi come ScreenManager::push
o
Screen::invalidate
, solo il Session
da cui vengono chiamati è
interessati. Le app devono creare i propri canali di comunicazione tra questi
istanze se è necessaria una comunicazione tra Session
(ad esempio, utilizzando
trasmissioni, un singleton condiviso o qualcosa di simile
altro).
Test del supporto dei cluster
Puoi testare la tua implementazione sia su Android Auto sia sul sistema operativo Android Automotive. Per Android Auto, questo viene fatto configurando l'unità principale desktop per emulare di un cluster secondario. Per Android Automotive OS, immagini di sistema generiche per API Livello 30 e livelli successivi emulano la visualizzazione di un cluster.
Personalizza Stima di viaggio con testo o un'icona
Per personalizzare la stima di viaggio con testo, un'icona o entrambi, utilizza la
TravelEstimate.Builder
del corso
setTripIcon
o
setTripText
di machine learning. La
NavigationTemplate
utilizza
TravelEstimate
per impostare facoltativamente testo e icone accanto o al posto del tempo stimato
di arrivo, del tempo rimanente e della distanza rimanente.
Il seguente snippet utilizza setTripIcon
e setTripText
per personalizzare
stima del viaggio:
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();
Fornire notifiche passo passo
Fornisci istruzioni di navigazione passo passo (TBT) utilizzando un notifica di navigazione aggiornata. Da trattare come una navigazione sullo schermo dell'auto, il generatore della notifica deve eseguire seguenti:
- Contrassegna la notifica come in corso con il
NotificationCompat.Builder.setOngoing
. - Imposta la categoria della notifica su
Notification.CATEGORY_NAVIGATION
. - Estendi la notifica con un
CarAppExtender
Viene visualizzata una notifica di navigazione nel widget della barra laterale nella parte inferiore di
sullo schermo dell'auto. Se il livello di importanza della notifica è impostato su
IMPORTANCE_HIGH
, viene visualizzata anche come notifica di avviso (HUN).
Se l'importanza non è impostata con il
CarAppExtender.Builder.setImportance
,
importanza del canale di notifica
.
L'app può impostare un valore PendingIntent
nel
CarAppExtender
che
viene inviato all'app quando l'utente tocca il widget HUN o il widget Rail.
Se
NotificationCompat.Builder.setOnlyAlertOnce
viene richiamata con il valore true
, un avviso di notifica di importanza elevata
una volta nello HUN.
Il seguente snippet mostra come creare una notifica di navigazione:
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();
Aggiorna regolarmente la notifica TBT per la distanza
che aggiorna il widget ferroviario e mostra la notifica solo come HUN.
Puoi controllare il comportamento HUN impostando l'importanza della notifica con
CarAppExtender.Builder.setImportance
. Dando importanza a
IMPORTANCE_HIGH
mostra uno HUN. Impostazione
a qualsiasi altro valore aggiorna solo il widget ferroviario.
Aggiorna i contenuti PlaceListNavigatorTemplate
Puoi consentire ai conducenti di aggiornare i contenuti semplicemente toccando un pulsante mentre navigano
di luoghi con
PlaceListNavigationTemplate
Per attivare l'aggiornamento dell'elenco, implementa
OnContentRefreshListener
dell'interfaccia utente
onContentRefreshRequested
e utilizzare
PlaceListNavigationTemplate.Builder.setOnContentRefreshListener
per impostare il listener sul modello.
Lo snippet seguente mostra come impostare il listener sul modello:
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();
Il pulsante di aggiornamento viene visualizzato solo nell'intestazione del
PlaceListNavigationTemplate
se il listener ha un valore.
Quando l'utente fa clic sul pulsante di aggiornamento,
onContentRefreshRequested
metodo di
Viene richiamata l'implementazione di OnContentRefreshListener
. Entro
onContentRefreshRequested
, chiama il
Screen.invalidate
.
L'organizzatore richiama quindi
Screen.onGetTemplate
per recuperare il modello con i contenuti aggiornati. Consulta
Aggiorna i contenuti di un modello per
ulteriori informazioni sull'aggiornamento dei modelli. Purché il modello successivo
restituito da
onGetTemplate
è di
lo stesso tipo, viene conteggiato come un aggiornamento e non viene conteggiato ai fini
quota del modello.
Fornire indicazioni audio
Per riprodurre le indicazioni di navigazione sugli altoparlanti dell'auto, la tua app deve richiedere
audio focus. Nell'ambito della tua
AudioFocusRequest
, imposta
l'utilizzo come AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
. Inoltre,
imposta il guadagno dello stato attivo su AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
.
Simula navigazione
Per verificare la funzionalità di navigazione dell'app quando la invii al
Google Play Store, la tua app deve implementare
NavigationManagerCallback.onAutoDriveEnabled
di Google. Quando viene chiamato questo callback, la tua app deve simulare la navigazione verso
la destinazione scelta quando l'utente inizia la navigazione. L'app può uscire da questa impostazione
ogni volta che il ciclo di vita dell'attuale Session
raggiunge
Lifecycle.Event.ON_DESTROY
stato.
Puoi verificare che la tua implementazione di onAutoDriveEnabled
venga chiamata
che esegue il comando seguente da una riga di comando:
adb shell dumpsys activity service CAR_APP_SERVICE_NAME AUTO_DRIVE
Ciò è mostrato nell'esempio seguente:
adb shell dumpsys activity service androidx.car.app.samples.navigation.car.NavigationCarAppService AUTO_DRIVE
App navigazione predefinita per auto
In Android Auto, l'app di navigazione predefinita per auto corrisponde all'ultima app di navigazione avviata dall'utente. App predefinita riceve intent di navigazione quando l'utente richiama i comandi di navigazione tramite l'assistente o quando un'altra app invia un per avviare la navigazione.
Mostra avvisi di navigazione contestualizzati
Alert
mostra importanti
informazioni al conducente con azioni facoltative, senza lasciare il contesto
nella schermata di navigazione. Per offrire un'esperienza ottimale al conducente,
Alert
funziona all'interno di
NavigationTemplate
per evitare di bloccare il percorso di navigazione e ridurre al minimo le distrazioni per chi guida.
Alert
è disponibile solo in NavigationTemplate
.
Per inviare una notifica all'utente al di fuori di NavigationTemplate
,
valuta la possibilità di utilizzare una notifica di avviso (HUN), come spiegato nella
Mostra notifiche.
Ad esempio, utilizza Alert
per:
- Comunica al conducente un aggiornamento relativo alla navigazione corrente, ad esempio una variazione delle condizioni del traffico.
- Chiedi al conducente un aggiornamento relativo alla navigazione corrente, ad esempio la l'esistenza di un autovelox mobile.
- Proponi un'attività imminente e chiedi al conducente se la accetta. ad esempio se il conducente è disposto a prendere qualcuno lungo la strada.
Nella forma di base, un Alert
è costituito da un titolo e dal Alert
durata massima. La durata è rappresentata da una barra di avanzamento. Se vuoi,
puoi aggiungere un sottotitolo, un'icona e fino
Action
oggetti.
Una volta mostrato, un Alert
non viene trasferito in un altro modello se
l'interazione con il conducente comporta l'uscita dal NavigationTemplate
.
Rimane nel file NavigationTemplate
originale fino al Alert
di timeout, l'utente
esegue un'azione oppure l'app ignora Alert
.
Crea un avviso
Utilizza Alert.Builder
per creare un'istanza 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();
Se vuoi ascoltare Alert
la cancellazione o il rifiuto, crea un'implementazione
Interfaccia di AlertCallback
.
I percorsi di chiamata AlertCallback
sono:
Se si verifica il timeout di
Alert
, l'organizzatore chiamaAlertCallback.onCancel
con ilAlertCallback.REASON_TIMEOUT
valore. Quindi chiamaAlertCallback.onDismiss
.Se il conducente fa clic su uno dei pulsanti di azione, l'organizzatore chiama
Action.OnClickListener
e poi chiamaAlertCallback.onDismiss
.Se
Alert
non è supportato, l'organizzatore chiamaAlertCallback.onCancel
conAlertCallback.REASON_NOT_SUPPORTED
: valore. L'organizzatore non chiamaAlertCallback.onDismiss
, perchéAlert
non è stato mostrato.
Configura la durata dell'avviso
Scegli una durata per Alert
che
in base alle esigenze della tua app. La durata consigliata per una navigazione
Alert
dura 10 secondi. Consulta Avvisi di navigazione.
per ulteriori informazioni.
Mostra un avviso
Per visualizzare una Alert
, chiama il metodo
AppManager.showAlert
di fatturazione disponibile tramite
CarContext
// Show an alert
carContext.getCarService(AppManager.class).showAlert(alert)
- Chiamata a
showAlert
con unAlert
con unalertId
: che corrisponde all'ID diAlert
attualmente in esposizione non produce alcun effetto.Alert
non si aggiorna. Per aggiornare unAlert
, devi ricreare con un nuovoalertId
. - Chiamata a
showAlert
con unAlert
con un altroalertId
rispetto alla metricaAlert
attualmente in esposizione ignora laAlert
attualmente visualizzati.
Ignorare un avviso
Mentre una Alert
ignora automaticamente
a causa di un timeout o di un'interazione con il conducente, puoi anche ignorare manualmente
Alert
, ad esempio se le sue informazioni diventano obsolete. Per ignorare un
Alert
, chiama il
dismissAlert
con il
alertId
di Alert
.
// Dismiss the same alert
carContext.getCarService(AppManager.class).dismissAlert(alert.getId())
Chiamata a dismissAlert
con un alertId
che non corrisponde a quello attualmente
visualizzato, Alert
non ha alcun effetto. Non genera un'eccezione.