Questa pagina descrive in dettaglio le diverse funzionalità della raccolta di app per auto che puoi utilizzare per implementare la funzionalità della tua app di navigazione passo passo.
Dichiarare il supporto della navigazione nel file manifest
La tua app di navigazione deve dichiarare la categoria di app per auto androidx.car.app.category.NAVIGATION
nel filtro per 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>
Supportare gli intent di navigazione
Una serie di formati di intent consente alle app di navigazione di funzionare con altre app, come le app per punti d'interesse e gli assistenti vocali.
Per supportare questi formati di intent, devi prima dichiarare il supporto aggiungendo filtri per intent nel file manifest dell'app. La posizione di questi filtri per intent dipende dalla piattaforma:
- Android Auto: all'interno dell'elemento manifest
<activity>perActivityutilizzata per gestire l'intent quando un utente non utilizza Android Auto. - Android Automotive OS: all'interno dell'elemento manifest
<activity>perCarAppActivity.
Quindi, leggi e gestisci gli intent nei callback onCreateScreen() e
onNewIntent() nell'implementazione di Session dell'app.
Formati di intent obbligatori
Per soddisfare il requisito di qualità NF-6, la tua app deve gestire
gli intent di navigazione.
Formati di intent facoltativi
Puoi anche supportare i seguenti formati di intent per aumentare ulteriormente l'interoperabilità della tua app:
Accedere ai modelli di navigazione
Le app di navigazione possono accedere ai seguenti modelli, che mostrano una superficie in background con la mappa e, durante la navigazione attiva, le indicazioni passo passo.
NavigationTemplate: un modello che mostra un messaggio informativo facoltativo e le stime di viaggio durante la navigazione attiva.MapWithContentTemplate: un modello che consente a un'app di eseguire il rendering dei riquadri della mappa con un tipo di contenuto (ad esempio, un elenco). In genere, il rendering dei contenuti viene eseguito come overlay sopra i riquadri della mappa, con le aree visibili e stabili della mappa che si adattano ai contenuti.
Per ulteriori dettagli su come progettare l'interfaccia utente dell'app di navigazione utilizzando questi modelli, consulta App di navigazione.
Per accedere ai modelli di navigazione, la tua app deve dichiarare l'autorizzazione androidx.car.app.NAVIGATION_TEMPLATES nel file AndroidManifest.xml:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>
...
</manifest>
È necessaria un'autorizzazione aggiuntiva per disegnare le mappe.
Eseguire la migrazione a MapWithContentTemplate
A partire dal livello API 7 dell'API Car App, MapTemplate,
PlaceListNavigationTemplate,
e RoutePreviewNavigationTemplate
sono deprecati. I modelli deprecati continueranno a essere supportati, ma è vivamente consigliata la migrazione a MapWithContentTemplate.
La funzionalità fornita da questi modelli può essere implementata utilizzando MapWithContentTemplate. Di seguito sono riportati alcuni esempi:
MapTemplate
// MapTemplate (deprecated) val templateDeprecated = 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()
PlaceListNavigationTemplate
// PlaceListNavigationTemplate (deprecated) val templateDeprecated = 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()
RoutePreviewNavigationTemplate
// RoutePreviewNavigationTemplate (deprecated) val templateDeprecated = RoutePreviewNavigationTemplate.Builder() .setItemList( ItemList.Builder() .addItem( Row.Builder() .setTitle(title) .build() ) .build() ) .setHeader(header) .setNavigateAction( Action.Builder() .setTitle(actionTitle) .setOnClickListener { /* onClick */ } .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 { /* onClick */ } .build() ) .build() ) .build() ) .setHeader(header) .build() ) .setActionStrip(actionStrip) .setMapController( MapController.Builder() .setMapActionStrip(mapActionStrip) .build() ) .build()
Comunicare i metadati di navigazione
Le app di navigazione devono comunicare metadati di navigazione aggiuntivi all'host. L'host utilizza le informazioni per fornire informazioni all'unità principale del veicolo e per impedire che le applicazioni di navigazione si scontrino per le risorse condivise.
I metadati di navigazione vengono forniti tramite il
NavigationManager
servizio per auto accessibile da
CarContext:
val navigationManager = carContext.getCarService(NavigationManager::class.java)
Avviare, terminare e interrompere la navigazione
Affinché l'host possa gestire più app di navigazione, notifiche di routing e dati del cluster del veicolo, deve essere a conoscenza dello stato attuale della navigazione. Quando un utente avvia la navigazione, chiama
NavigationManager.navigationStarted.
Allo stesso modo, quando la navigazione termina, ad esempio quando l'utente arriva a
destinazione o annulla la navigazione, chiama
NavigationManager.navigationEnded.
Chiama NavigationManager.navigationEnded solo quando l'utente termina la navigazione. Ad esempio, se devi ricalcolare
il percorso a metà di un viaggio, utilizza
Trip.Builder.setLoading(true)
invece.
A volte, l'host richiede a un'app di interrompere la navigazione e chiama
onStopNavigation in un
NavigationManagerCallback
oggetto fornito dall'app tramite
NavigationManager.setNavigationManagerCallback.
L'app deve quindi interrompere l'emissione di informazioni sulla svolta successiva nel display del cluster, nelle notifiche di navigazione e nelle indicazioni vocali.
Aggiornare le informazioni sul viaggio
Durante la navigazione attiva, chiama
NavigationManager.updateTrip.
Le informazioni fornite in questa chiamata possono essere utilizzate dal cluster e dai display a sovrimpressione del veicolo. A seconda del veicolo specifico guidato, non tutte le informazioni vengono mostrate all'utente.
Ad esempio, l'unità principale del computer (DHU) mostra
il Step aggiunto al
Trip, ma non mostra
le informazioni Destination.
Disegnare sul display del cluster
Per offrire l'esperienza utente più coinvolgente, potresti voler andare oltre la visualizzazione dei metadati di base sul display del cluster del veicolo. A partire dal livello API 6 dell'API Car App, le app di navigazione hanno la possibilità di eseguire il rendering dei propri contenuti direttamente sul display del cluster (nei veicoli supportati), con le seguenti limitazioni:
- L'API del display del cluster non supporta i controlli di input.
- Linee guida per la qualità delle app per auto
NF-9: il display del cluster deve mostrare solo i riquadri della mappa. Su questi riquadri può essere visualizzato facoltativamente un percorso di navigazione attivo. - L'API del display del cluster supporta solo l'utilizzo di
NavigationTemplate- A differenza dei display principali, i display del cluster potrebbero non mostrare in modo coerente tutti gli elementi dell'interfaccia utente di
NavigationTemplate, come le indicazioni passo passo, le schede con l'orario di arrivo stimato e le azioni. I riquadri della mappa sono l'unico elemento dell'interfaccia utente visualizzato in modo coerente.
- A differenza dei display principali, i display del cluster potrebbero non mostrare in modo coerente tutti gli elementi dell'interfaccia utente di
Dichiarare il supporto del cluster
Per comunicare all'applicazione host che la tua app supporta il rendering sui display del cluster
, devi aggiungere un elemento androidx.car.app.category.FEATURE_CLUSTER
<category> a CarAppService's <intent-filter>, come mostrato nel
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>
Gestione del ciclo di vita e dello stato
A partire dal livello API 6, il flusso del ciclo di vita dell'app per auto
rimane lo stesso, ma ora CarAppService::onCreateSession accetta un parametro di
tipo SessionInfo che fornisce
informazioni aggiuntive sulla Session in fase di creazione (ovvero il tipo di display
e l'insieme di modelli supportati).
Le app hanno la possibilità di utilizzare la stessa Session classe per gestire sia il
cluster sia il display principale oppure creare Sessions specifiche per il display per personalizzare il
comportamento su ogni display (come mostrato nel seguente snippet).
override fun onCreateSession(sessionInfo: SessionInfo): Session { return if (sessionInfo.displayType == SessionInfo.DISPLAY_TYPE_CLUSTER) { ClusterSession() } else { MainDisplaySession() } }
Non ci sono garanzie su quando o se il display del cluster viene fornito ed è anche possibile che la Session del cluster sia l'unica Session (ad esempio, l'utente ha sostituito il display principale con un'altra app mentre la tua app sta navigando attivamente). L'accordo "standard" prevede che l'app acquisisca il controllo del display del cluster solo dopo aver chiamato NavigationManager::navigationStarted. Tuttavia, è possibile che all'app venga fornito il display del cluster mentre non è in corso alcuna navigazione attiva o che non venga mai fornito il display del cluster. Spetta alla tua app gestire questi scenari eseguendo il rendering dello stato inattivo dei riquadri della mappa dell'app.
L'host crea istanze di binder e CarContext separate per ogni Session. Ciò significa che, quando si utilizzano metodi come ScreenManager::push o Screen::invalidate, viene interessata solo la Session da cui vengono chiamati. Le app devono creare i propri canali di comunicazione tra queste
istanze se è necessaria la comunicazione tra Session (ad esempio, utilizzando
trasmissioni, un singleton condiviso o altro
).
Testare il supporto del cluster
Puoi testare l'implementazione sia su Android Auto sia su Android Automotive OS. Per Android Auto, questa operazione viene eseguita configurando l'unità principale del computer per emulare un display del cluster secondario. Per Android Automotive OS, le immagini di sistema generiche per il livello API 30 e versioni successive emulano un display del cluster.
Personalizzare TravelEstimate con testo o un'icona
Per personalizzare la stima del viaggio con testo, un'icona o entrambi, utilizza i
TravelEstimate.Builder
della classe
setTripIcon
o
setTripText. The
NavigationTemplate
utilizza
TravelEstimate
per impostare facoltativamente testo e icone accanto o al posto dell'orario di arrivo stimato,
del tempo rimanente e della distanza rimanente.
Il seguente snippet utilizza setTripIcon e setTripText per personalizzare la stima del viaggio:
TravelEstimate.Builder( Distance.create(350.0, Distance.UNIT_METERS), arrivalTimeAtDestination ) .setTripIcon( CarIcon.Builder( IconCompat.createWithResource(carContext, R.drawable.ic_garage) ).build() ) .setTripText(CarText.create("Custom Text")) .build()
Fornire notifiche passo passo
Fornisci indicazioni di navigazione passo passo utilizzando una notifica di navigazione aggiornata di frequente. Per essere considerata una notifica di navigazione nella schermata dell'auto, il builder della notifica deve eseguire le seguenti operazioni:
- Contrassegna la notifica come in corso con il
NotificationCompat.Builder.setOngoingmetodo. - Imposta la categoria della notifica su
Notification.CATEGORY_NAVIGATION. - Estendi la notifica con un
CarAppExtender.
Una notifica di navigazione viene visualizzata nel widget della barra nella parte inferiore della schermata dell'auto. Se il livello di importanza della notifica è impostato su IMPORTANCE_HIGH, viene visualizzata anche come notifica in evidenza (HUN).
Se l'importanza non è impostata con il
CarAppExtender.Builder.setImportance
metodo, viene utilizzata l'importanza del
canale di notifica.
L'app può impostare un PendingIntent nel
CarAppExtender che
viene inviato all'app quando l'utente tocca la HUN o il widget della barra.
Se
NotificationCompat.Builder.setOnlyAlertOnce
viene chiamato con un valore di true, una notifica di alta importanza genera un avviso solo
una volta nella HUN.
Il seguente snippet mostra come creare una notifica di navigazione:
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) ), PendingIntent.FLAG_IMMUTABLE ) ) .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH) .build() ) .build()
Aggiorna regolarmente la notifica passo passo per le modifiche della distanza, che aggiorna il widget della barra, e mostra la notifica solo come HUN.
Puoi controllare il comportamento della HUN impostando l'importanza della notifica con CarAppExtender.Builder.setImportance. Se imposti l'importanza su IMPORTANCE_HIGH, viene visualizzata una HUN. Se imposti un altro valore, viene aggiornato solo il widget della barra laterale.
Aggiornare i contenuti di PlaceListNavigationTemplate
Puoi consentire ai conducenti di aggiornare i contenuti con un tocco di un pulsante mentre sfogliano
elenchi di luoghi creati con
PlaceListNavigationTemplate.
Per attivare l'aggiornamento dell'elenco, implementa il
OnContentRefreshListener
dell'interfaccia
onContentRefreshRequested
e utilizza
PlaceListNavigationTemplate.Builder.setOnContentRefreshListener
per impostare il listener sul modello.
Il seguente snippet mostra come impostare il listener sul modello:
PlaceListNavigationTemplate.Builder() .setOnContentRefreshListener { // Execute any desired logic // Then call invalidate() so onGetTemplate() is called again screen.invalidate() } .build()
Il pulsante di aggiornamento viene mostrato nell'intestazione di PlaceListNavigationTemplate solo se il listener ha un valore.
Quando l'utente fa clic sul pulsante di aggiornamento, viene chiamato il metodo onContentRefreshRequested dell'implementazione di OnContentRefreshListener. All'interno di
onContentRefreshRequested, chiama il
Screen.invalidate metodo.
L'host richiama quindi il metodo dell'app
Screen.onGetTemplate
per recuperare il modello con i contenuti aggiornati. Per ulteriori informazioni sull'aggiornamento dei modelli, consulta
Aggiornare i contenuti di un modello. A condizione che il modello successivo
restituito da
onGetTemplate sia dello
stesso tipo, viene considerato un aggiornamento e non viene conteggiato nella
quota di modelli.
Fornire indicazioni audio
Per riprodurre le indicazioni di navigazione tramite gli altoparlanti dell'auto, la tua app deve richiedere
il focus audio. Come parte di
AudioFocusRequest, imposta
l'utilizzo come AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE. Inoltre, imposta l'acquisizione dell'audio focus come AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK.
Simulare la navigazione
Per verificare la funzionalità di navigazione della tua app quando la invii al
Google Play Store, la tua app deve implementare il
NavigationManagerCallback.onAutoDriveEnabled
callback. Quando viene chiamato questo callback, la tua app deve simulare la navigazione verso la destinazione scelta quando l'utente inizia la navigazione. La tua app può uscire da questa
modalità ogni volta che il ciclo di vita della Session
corrente raggiunge lo
Lifecycle.Event.ON_DESTROY
stato.
Puoi verificare che la tua implementazione di onAutoDriveEnabled venga chiamata eseguendo il seguente comando da una riga di comando:
adb shell dumpsys activity service CAR_APP_SERVICE_NAME AUTO_DRIVE
Questo è mostrato nel seguente esempio:
adb shell dumpsys activity service androidx.car.app.samples.navigation.car.NavigationCarAppService AUTO_DRIVE
App per auto di navigazione predefinita
In Android Auto, l'app per auto di navigazione predefinita corrisponde all'ultima app di navigazione avviata dall'utente. L'app predefinita riceve gli intent di navigazione quando l'utente richiama i comandi di navigazione tramite l'Assistente o quando un'altra app invia un intent per avviare la navigazione.
Mostrare avvisi di navigazione contestuali
Alert mostra informazioni importanti al conducente con azioni facoltative ‐ senza uscire dal contesto della schermata di navigazione. Per offrire la migliore esperienza al conducente,
Alert funziona all'interno di
NavigationTemplate
per evitare di bloccare il percorso di navigazione e ridurre al minimo le distrazioni del conducente.
Alert è disponibile solo all'interno di NavigationTemplate.
Per inviare una notifica all'utente al di fuori di NavigationTemplate,
valuta la possibilità di utilizzare una notifica in evidenza (HUN), come spiegato in
Mostrare le notifiche.
Ad esempio, utilizza Alert per:
- Informare il conducente di un aggiornamento pertinente alla navigazione corrente, ad esempio una modifica delle condizioni del traffico.
- Chiedere al conducente un aggiornamento relativo alla navigazione corrente, ad esempio l'esistenza di un autovelox mobile.
- Proporre un'attività imminente e chiedere se il conducente la accetta, ad esempio se è disposto a prendere qualcuno lungo il percorso.
Nella sua forma base, un Alert è costituito da un titolo e dalla durata di Alert. La durata è rappresentata da una barra di avanzamento. Facoltativamente,
puoi aggiungere un sottotitolo, un'icona e fino a due
Action oggetti.
Una volta visualizzato un Alert, non viene trasferito a un altro modello se l'interazione del conducente comporta l'uscita da NavigationTemplate.
Rimane nel NavigationTemplate originale fino alla scadenza di Alert, all'esecuzione di un'azione da parte dell'utente o alla chiusura di Alert da parte dell'app.
Creare un avviso
Utilizza Alert.Builder
per creare un'istanza di Alert:
Alert.Builder( 1, // alertId CarText.create("Hello"), // title 5000 // durationMillis ) // The fields below are optional .addAction(firstAction) .addAction(secondAction) .setSubtitle(CarText.create("Subtitle")) .setIcon(CarIcon.APP_ICON) .setCallback(alertCallback) .build()
Se vuoi ascoltare l'annullamento o la chiusura, crea un'implementazione dell'interfaccia.AlertAlertCallback
I percorsi di chiamata di AlertCallback sono:
Se
Alertscade, l'host chiama ilAlertCallback.onCancelmetodo con ilAlertCallback.REASON_TIMEOUTvalore. Quindi chiama ilAlertCallback.onDismissmetodo.Se il conducente fa clic su uno dei pulsanti di azione, l'host chiama
Action.OnClickListenere poi chiamaAlertCallback.onDismiss.Se il
Alertnon è supportato, l'host chiamaAlertCallback.onCancelcon ilAlertCallback.REASON_NOT_SUPPORTEDvalore. L'host non chiamaAlertCallback.onDismiss, perchéAlertnon è stato mostrato.
Configurare la durata degli avvisi
Scegli una Alert durata che
soddisfi le esigenze della tua app. La durata consigliata per un Alert di navigazione è di 10 secondi. Per ulteriori informazioni, consulta Avvisi di navigazione.
Mostrare un avviso
Per mostrare un Alert, chiama il
AppManager.showAlert
metodo disponibile tramite
CarContextdella tua app.
carContext.getCarService(AppManager::class.java).showAlert(alert)
- La chiamata di
showAlertcon unAlertche ha unalertIduguale all'ID diAlertgià visualizzato non ha alcun effetto.Alertnon viene aggiornato. Per aggiornare unAlert, devi ricrearlo con un nuovoalertId. - La chiamata di
showAlertcon unAlertche ha un diversoalertIdda quello diAlertgià visualizzato chiude l'avviso visualizzatoAlert.
Chiudere un avviso
Sebbene un Alert si chiuda automaticamente
a causa del timeout o dell'interazione del conducente, puoi anche chiudere manualmente un
Alert, ad esempio se le informazioni diventano obsolete. Per chiudere un
Alert, chiama il
dismissAlert
metodo con l'
alertId
di Alert.
carContext.getCarService(AppManager::class.java).dismissAlert(alert.id)
La chiamata di dismissAlert con un alertId che non corrisponde a Alert già
visualizzato non ha alcun effetto. Non genera un'eccezione.