Crea un'app di navigazione

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

L'app di navigazione deve dichiarare la categoria di app auto androidx.car.app.category.NAVIGATION nel filtro per intent del suo 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 dall'Assistente Google tramite una query vocale, l'app deve gestire l'intent CarContext.ACTION_NAVIGATE nelle sue impostazioni Session.onCreateScreen e Session.onNewIntent.

Consulta la documentazione relativa a CarContext.startCarApp per i dettagli sul formato dell'intent.

Accedere ai modelli di navigazione

Le app di navigazione possono accedere ai seguenti modelli, che mostrano un'area sullo sfondo con la mappa e, durante la navigazione attiva, le indicazioni passo passo.

  • 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 della mappa con un qualche tipo di contenuti (ad esempio, un elenco). In genere, i contenuti vengono visualizzati 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, 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 file AndroidManifest.xml:

<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, le MapTemplate, PlaceListNavigationTemplate e RoutePreviewNavigationTemplate sono deprecate. I modelli deprecati continueranno a essere supportati, ma ti consigliamo vivamente di eseguire la migrazione a MapWithContentTemplate.

La funzionalità fornita da questi modelli può essere implementata utilizzando 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();

Le app di navigazione devono comunicare metadati di navigazione aggiuntivi con l'host. L'host utilizza le informazioni per fornire informazioni all'unità principale del veicolo e per evitare conflitti tra le applicazioni di navigazione e risorse condivise.

I metadati di navigazione vengono forniti tramite il servizio auto 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

Affinché l'host possa gestire più app di navigazione, notifiche di percorso e dati del cluster del veicolo, deve essere a conoscenza dello stato attuale della navigazione. Quando un utente avvia la navigazione, chiama NavigationManager.navigationStarted. Analogamente, al termine della navigazione, 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 una corsa, utilizza invece Trip.Builder.setLoading(true).

A volte, l'host ha bisogno di un'app per interrompere la navigazione e chiamare onStopNavigation in un oggetto 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, nelle notifiche di navigazione e nella 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 dalle visualizzazioni di avviso. A seconda del veicolo specifico, non vengono mostrate tutte le informazioni all'utente. Ad esempio, l'unità principale desktop (DHU) mostra la Step aggiunta all'Trip, ma non le informazioni su Destination.

Disegno sulla visualizzazione del cluster

Per offrire un'esperienza utente più immersiva, potresti voler andare oltre la visualizzazione dei metadati di base sul display del cluster del veicolo. A partire dall'API Car App Livello 6, 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 cluster display non supporta i controlli di input
  • La visualizzazione del cluster dovrebbe mostrare solo riquadri della mappa. In questi riquadri è possibile visualizzare una navigazione del percorso attiva.
  • L'API Cluster Display supporta solo l'utilizzo dell'API NavigationTemplate
    • A differenza delle visualizzazioni principali, le visualizzazioni del cluster potrebbero non mostrare in modo coerente tutti gli elementi UI di NavigationTemplate, come le istruzioni passo passo, le schede ETA e le azioni. I riquadri della mappa sono l'unico elemento UI visualizzato in modo coerente.

Dichiara l'assistenza per i 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 <intent-filter> di CarAppService 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>

Ciclo di vita e gestione degli stati

A partire dal livello API 6, il flusso del ciclo di vita dell'app per auto rimane lo stesso, ma ora CarAppService::onCreateSession utilizza un parametro di tipo SessionInfo che fornisce ulteriori informazioni sull'oggetto Session creato (ovvero il tipo di visualizzazione e l'insieme di modelli supportati).

Le app possono scegliere di utilizzare la stessa classe Session per gestire sia il cluster che la visualizzazione principale oppure di creare un elemento Sessions specifico per la visualizzazione al fine di personalizzare il comportamento su ogni display (come mostrato 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 o se verrà fornita la visualizzazione del cluster ed è anche possibile che il cluster Session sia l'unico Session (ad esempio, l'utente ha scambiato il display principale con un'altra app mentre la tua app stava navigando attivamente). L'accordo "standard" prevede che l'app acquisisca il controllo della visualizzazione del cluster solo dopo la chiamata di NavigationManager::navigationStarted. Tuttavia, è possibile che all'app venga fornita la visualizzazione del cluster mentre non è in corso alcuna navigazione attiva o che non venga mai fornita la visualizzazione del cluster. Spetta all'app gestire questi scenari eseguendo il rendering dello stato di inattività dei riquadri della mappa dell'app.

L'host crea binder e istanze CarContext separate per Session. Ciò significa che, quando utilizzi metodi come ScreenManager::push o Screen::invalidate, viene interessato solo il Session da cui vengono chiamati. Le app devono creare i propri canali di comunicazione tra queste istanze se è necessaria una comunicazione tra Session (ad esempio, utilizzando trasmissioni, un singleton condiviso o 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 in modo da 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.

Personalizza Stima di viaggio con testo o un'icona

Per personalizzare la stima del viaggio con testo, un'icona o entrambi, utilizza i metodi setTripIcon o setTripText del corso.TravelEstimate.Builder L'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.

Figura 1. Stima di viaggio con icona e testo personalizzati.

Il seguente snippet utilizza setTripIcon e setTripText per personalizzare la 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 una notifica di navigazione aggiornata di frequente. Per essere trattato come una notifica di navigazione sullo schermo dell'auto, il generatore della notifica deve:

  1. Contrassegna la notifica come in corso con il metodo NotificationCompat.Builder.setOngoing.
  2. Imposta la categoria della notifica su Notification.CATEGORY_NAVIGATION.
  3. Estendi la notifica con un CarAppExtender.

Viene visualizzata una notifica di navigazione nel widget Ferrovia nella parte inferiore dello 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 metodo CarAppExtender.Builder.setImportance, viene utilizzata l'importanza del canale di notifica.

L'app può impostare un elemento PendingIntent in CarAppExtender che viene inviato all'app quando l'utente tocca il widget HUN o il widget Rail.

Se NotificationCompat.Builder.setOnlyAlertOnce viene chiamato con il valore true, una notifica di importanza elevata avvisa solo una volta nell'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 i cambiamenti della distanza, il 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. Se imposti l'importanza su IMPORTANCE_HIGH viene visualizzato un HUN. Se viene impostato su qualsiasi altro valore, viene aggiornato solo il widget ferroviario.

Aggiorna i contenuti PlaceListNavigatorTemplate

Puoi consentire ai conducenti di aggiornare i contenuti semplicemente toccando un pulsante mentre sfogliano gli elenchi di luoghi creati con PlaceListNavigationTemplate. Per abilitare l'aggiornamento dell'elenco, implementa il metodo onContentRefreshRequested dell'interfaccia OnContentRefreshListener e utilizza 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 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 metodo Screen.invalidate. L'host richiama quindi il metodo Screen.onGetTemplate della tua app per recuperare il modello con i contenuti aggiornati. Consulta Aggiornare i contenuti di un modello per ulteriori informazioni sull'aggiornamento dei modelli. Se il modello successivo restituito da onGetTemplate è dello stesso tipo, viene conteggiato come un aggiornamento e non viene conteggiato ai fini della quota del modello.

Fornire indicazioni audio

Per riprodurre le indicazioni stradali sugli altoparlanti dell'auto, la tua app deve richiedere audio focus. Come parte di AudioFocusRequest, imposta l'utilizzo su 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 della tua app quando la invii al Google Play Store, l'app deve implementare il callback NavigationManagerCallback.onAutoDriveEnabled. Quando viene chiamato questo callback, l'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 dell'attuale Session raggiunge lo stato Lifecycle.Event.ON_DESTROY.

Puoi verificare che la tua implementazione di onAutoDriveEnabled venga chiamata eseguendo quanto segue 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. L'app predefinita riceve intent di navigazione quando l'utente richiama comandi di navigazione tramite l'assistente o quando un'altra app invia un intent per avviare la navigazione.

Mostra avvisi di navigazione contestualizzati

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 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 sezione Visualizzare le notifiche.

Ad esempio, utilizza Alert per:

  • Comunica al conducente un aggiornamento pertinente alla navigazione attuale, ad esempio un cambiamento delle condizioni del traffico.
  • Chiedi al conducente un aggiornamento relativo alla navigazione corrente, ad esempio l'esistenza di un autovelox mobile.
  • Proponi un'attività imminente e chiedi al conducente se la accetta, ad esempio se è disposto a prendere qualcuno lungo la strada.

Nella forma base, un Alert è costituito da un titolo e dal tempo di durata di Alert. La durata è rappresentata da una barra di avanzamento. Se vuoi, puoi aggiungere un sottotitolo, un'icona e fino a due oggetti Action.

Figura 2. Avviso di navigazione contestuale.

Una volta visualizzato, un Alert non viene trasferito in un altro modello se l'interazione del conducente comporta l'uscita da NavigationTemplate. Rimane nell'NavigationTemplate originale fino al timeout del Alert, l'utente compie un'azione o 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 rimanere in ascolto per l'annullamento o il rifiuto di Alert, crea un'implementazione dell'interfaccia di AlertCallback. I percorsi di chiamata AlertCallback sono:

Configura la durata dell'avviso

Scegli una durata per il periodo Alert che corrisponda alle esigenze della tua app. La durata consigliata per una navigazione Alert è 10 secondi. Per ulteriori informazioni, consulta Avvisi di navigazione.

Mostra un avviso

Per mostrare un elemento Alert, chiama il metodo AppManager.showAlert disponibile tramite il CarContext della tua app.

// Show an alert
carContext.getCarService(AppManager.class).showAlert(alert)
  • Chiamare showAlert con un Alert il cui valore alertId corrisponde all'ID del dispositivo Alert attualmente non ha alcun effetto. Alert non si aggiorna. Per aggiornare un Alert, devi ricrearlo con un nuovo alertId.
  • Se chiami showAlert con un Alert che ha un alertId diverso da quello di Alert attualmente visualizzato, il Alert attualmente visualizzato verrà ignorato.

Ignorare un avviso

Mentre un Alert si chiude automaticamente a causa di un timeout o di un'interazione con il conducente, puoi anche ignorare manualmente un Alert, ad esempio se le sue informazioni diventano obsolete. Per ignorare un Alert, chiama il metodo dismissAlert con alertId di Alert.

// Dismiss the same alert
carContext.getCarService(AppManager.class).dismissAlert(alert.getId())

La chiamata di dismissAlert con un alertId che non corrisponde all'elemento Alert attualmente visualizzato non ha alcun effetto. Non genera un'eccezione.