API Instrument Cluster

Utilizza l'API Instrument Cluster (un'API Android) per visualizzare le app di navigazione, tra cui Google Maps, su un display secondario di un'auto, ad esempio dietro il volante sul cruscotto. Questa pagina descrive come creare un servizio per controllare il display secondario e integrarlo con CarService in modo che le app di navigazione possano visualizzare un'interfaccia utente.

Terminologia

In questa pagina vengono utilizzati i seguenti termini.

CarInstrumentClusterManager
Un'istanza di CarManager che consente alle app esterne di avviare un'attività sul quadro strumenti e ricevere callback quando il quadro strumenti è pronto per visualizzare le attività.
CarManager
Classe base di tutti i gestori utilizzati da app esterne per interagire con servizi specifici per l'auto implementati da CarService.
CarService
Servizio della piattaforma Android che fornisce la comunicazione tra app esterne (inclusa Google Maps) e funzionalità specifiche dell'auto, come l'accesso al quadro strumenti.
Destinazione
La destinazione finale a cui si dirigerà il veicolo.
Orario di arrivo stimato (ATE)
L'orario di arrivo stimato a una destinazione.
Unità principale (HU)
Unità di calcolo principale integrata in un'auto. L'unità principale esegue tutto il codice Android ed è collegata al display centrale dell'auto.
Quadro strumenti
Display secondario situato dietro il volante e tra gli strumenti dell'auto. Può trattarsi di un'unità di calcolo indipendente collegata all'HU tramite la rete interna dell'auto (bus CAN) o di un display secondario collegato all'HU.
InstrumentClusterRenderingService
Classe base per il servizio utilizzato per interfacciarsi con il display del quadro strumenti. Gli OEM devono fornire un'estensione di questa classe che interagisce con l'hardware specifico dell'OEM.
App KitchenSink
App di test inclusa in Android Automotive.
Route
Un percorso specifico lungo il quale un veicolo naviga per arrivare a una destinazione.
Servizio singleton
Un servizio Android con l'attributo android:singleUser. In un determinato momento, sul sistema Android viene eseguita al massimo un'istanza del servizio.

Prerequisiti

Prima di continuare, assicurati di avere a disposizione quanto segue:

  • Ambiente di sviluppo Android.Per configurare l'ambiente di sviluppo Android, consulta Requisiti di compilazione.
  • Scarica il codice sorgente di Android.Scarica l'ultima versione del codice sorgente di Android dal ramo pi-car-release (o successivo) all'indirizzo https://android.googlesource.com.
  • Unità principale. Un dispositivo Android in grado di eseguire Android 9 (o versioni successive). Questo dispositivo deve avere un proprio display ed essere in grado di aggiornarlo con nuove build di Android.
  • Instrument Cluster è uno dei seguenti:
    • Display secondario fisico collegato all'HU.Se l'hardware e il kernel del dispositivo supportano la gestione di più display.
    • Unità indipendente.Qualsiasi unità di calcolo connessa all'HU tramite una connessione di rete, in grado di ricevere e visualizzare uno stream video sul proprio display.
    • Display emulato.Durante lo sviluppo, puoi utilizzare uno di questi ambienti emulati:
      • Display secondari simulati. Per attivare un display secondario simulato su qualsiasi distribuzione AOSP Android, vai alle impostazioni delle Opzioni sviluppatore nell'app di sistema Impostazioni e seleziona Simula display secondari. Questa configurazione equivale a collegare un display secondario fisico, con la limitazione che questo display è sovrapposto al display principale.
      • Quadro strumenti emulato.L'emulatore Android incluso in AAOS offre un'opzione per visualizzare un quadro strumenti con ClusterRenderingService.

Architettura di integrazione

Componenti di integrazione

Qualsiasi integrazione dell'API Instrument Cluster è costituita da questi tre componenti:

  • CarService
  • App di navigazione
  • OEM Instrument Cluster Service

Componenti di integrazione

CarService

CarService funge da intermediario tra le app di navigazione e l'auto, assicurandosi che solo un'app di navigazione sia attiva in un determinato momento e che solo le app con l'autorizzazione android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL possano inviare dati all'auto.

CarService esegue il bootstrap di tutti i servizi specifici per l'auto e fornisce l'accesso a questi servizi tramite una serie di gestori. Per interagire con i servizi, le app in esecuzione nell'auto possono accedere a questi gestori.

Per l'implementazione del quadro strumenti, gli OEM automobilistici devono creare un'implementazione personalizzata di InstrumentClusterRendererService e aggiornare ClusterRenderingService.

Durante il rendering di un quadro strumenti, durante la procedura di avvio CarService legge la chiave InstrumentClusterRendererService di ClusterRenderingService per individuare un'implementazione di InstrumentClusterService. In AOSP, questa voce rimanda al servizio di rendering dell'implementazione del cluster di esempio dell'API Navigation State:

<string name="instrumentClusterRendererService">
android.car.cluster/.ClusterRenderingService
</string>

Il servizio a cui si fa riferimento in questa voce è inizializzato e associato a CarService. Quando le app di navigazione, come Google Maps, richiedono un CarInstrumentClusterManager, CarService fornisce un gestore che aggiorna lo stato del quadro strumenti dal InstrumentClusterRenderingService associato. In questo caso, vincolato si riferisce ai servizi Android.

Servizio quadro strumenti

Gli OEM devono creare un pacchetto Android (APK) che contenga una sottoclasse di ClusterRenderingService.

Questo corso ha due scopi:

  • Fornisce un'interfaccia tra Android e il dispositivo di rendering del quadro strumenti (lo scopo di questa pagina).
  • Riceve e visualizza gli aggiornamenti dello stato di navigazione, ad esempio le indicazioni stradali passo passo.

Per il primo scopo, le implementazioni OEM di InstrumentClusterRendererService devono inizializzare il display secondario utilizzato per visualizzare le informazioni sugli schermi nell'abitacolo dell'auto e comunicare queste informazioni a CarService chiamando i metodi InstrumentClusterRendererService.setClusterActivityOptions() e InstrumentClusterRendererService.setClusterActivityState().

Per la seconda funzione, il servizio Instrument Cluster deve fornire un'implementazione dell'interfaccia ClusterRenderingService che riceve eventi di aggiornamento dello stato di navigazione, codificati come eventType e dati sugli eventi codificati in un bundle.

Sequenza di integrazione

Il seguente diagramma illustra l'implementazione di uno stato di navigazione che esegue il rendering degli aggiornamenti:

Sequenza di integrazione

In questa illustrazione, i colori indicano quanto segue:

  • Giallo.CarService e CarNavigationStatusManager forniti dalla piattaforma Android. Per saperne di più, consulta Car e CAR_NAVIGATION_SERVICE.
  • Ciano.InstrumentClusterRendererService implementato dall'OEM.
  • Viola.L'app di navigazione implementata da Google e da sviluppatori di terze parti.
  • Green. CarAppFocusManager. Per saperne di più, consulta Utilizzo dell'API CarAppFocusManager di seguito e CarAppFocusManager.

Il flusso di informazioni sullo stato di navigazione segue questa sequenza:

  1. CarService inizializza InstrumentClusterRenderingService.
  2. Durante l'inizializzazione, InstrumentClusterRenderingService aggiorna CarService con:
    1. Proprietà di visualizzazione del quadro strumenti, ad esempio limiti non oscurati (vedi maggiori dettagli sui limiti non oscurati più avanti).
    2. Opzioni di attività necessarie per avviare le attività all'interno del display del quadro strumenti. Per saperne di più, consulta ActivityOptions.
  3. Un'app di navigazione (come Google Maps per Android Automotive o qualsiasi app di mappe con le autorizzazioni richieste):
    1. Ottiene un CarAppFocusManager utilizzando la classe Car di car-lib.
    2. Prima dell'inizio delle indicazioni passo passo, chiama CarAppFocusManager.requestFocus() per trasmettere CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION come parametro appType.
  4. CarAppFocusManager comunica questa richiesta a CarService. Se viene concesso, CarService ispeziona il pacchetto applicativo dell'app di navigazione e individua un'attività contrassegnata con la categoria android.car.cluster.NAVIGATION.
  5. Se viene trovato, l'app di navigazione utilizza ActivityOptions segnalato da InstrumentClusterRenderingService per avviare l'attività e include le proprietà di visualizzazione del quadro strumenti come extra nell'intent.

Integra l'API

L'implementazione di InstrumentClusterRenderingService deve:

  • Essere designato come servizio singleton aggiungendo il seguente valore a AndroidManifest.xml. Ciò è necessario per garantire che venga eseguita una sola copia del servizio Instrument Cluster, anche durante l'inizializzazione e il cambio utente:
    android:singleUser="true"
  • Tieni l'autorizzazione di sistema BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. Questo garantisce che solo il servizio di rendering del quadro strumenti incluso nell'immagine di sistema Android sia mai associato a CarService:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

Implementare InstrumentClusterRenderingService

Per creare il servizio:

  1. Scrivi una classe che si estenda da ClusterRenderingService e poi aggiungi una voce corrispondente al file AndroidManifest.xml. Questa classe controlla la visualizzazione del quadro strumenti e può (facoltativamente) eseguire il rendering dei dati dell'API Navigation State.
  2. Durante onCreate(), utilizza questo servizio per inizializzare la comunicazione con l'hardware di rendering. Sono disponibili le seguenti opzioni:
    • Determina il display secondario da utilizzare per il quadro strumenti.
    • Crea un display virtuale in modo che l'app Quadro strumenti esegua il rendering e trasmetta l'immagine renderizzata a un'unità esterna (utilizzando un formato di streaming video, ad esempio H.264).
  3. Quando il display sopra indicato è pronto, questo servizio deve chiamare InstrumentClusterRenderingService#setClusterActivityLaunchOptions() per definire l'ActivityOptions esatto da utilizzare per visualizzare un'attività sul quadro strumenti. Utilizza questi parametri:
    • category. ClusterRenderingService.
    • ActivityOptions. Un'istanza ActivityOptions che può essere utilizzata per avviare un'attività nel quadro strumenti. Ad esempio, dall'implementazione di esempio del quadro strumenti su AOSP:
      getService().setClusterActivityLaunchOptions(
        CATEGORY_NAVIGATION,
        ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
  4. Quando il quadro strumenti è pronto per visualizzare le attività, questo servizio deve richiamare InstrumentClusterRenderingService#setClusterActivityState(). Utilizza questi parametri:
    • category ClusterRenderingService.
    • state Bundle generato con ClusterRenderingService. Assicurati di fornire questi dati:
      • visible Specifica il quadro strumenti come visibile e pronto per visualizzare i contenuti.
      • unobscuredBounds Un rettangolo che definisce l'area all'interno del display del quadro strumenti in cui è sicuro visualizzare i contenuti. Ad esempio, le aree coperte da quadranti e indicatori.
  5. Esegui l'override del metodo Service#dump() e segnala informazioni sullo stato utili per il debug (vedi dumpsys per maggiori informazioni).

Esempio di implementazione di InstrumentClusterRenderingService

L'esempio seguente descrive un'implementazione di InstrumentClusterRenderingService che crea un VirtualDisplay per presentare i contenuti del cluster di strumenti su un display fisico remoto.

In alternativa, questo codice potrebbe superare il displayId di un display secondario fisico collegato all'HU, se è noto che è disponibile.

/**
* Sample {@link InstrumentClusterRenderingService} implementation
*/
public class SampleClusterServiceImpl extends InstrumentClusterRenderingService {
   // Used to retrieve or create displays
   private final DisplayManager mDisplayManager;
   // Unique identifier for the display to be used for instrument
   // cluster
   private final String mUniqueId = UUID.randomUUID().toString();
   // Format of the instrument cluster display
   private static final int DISPLAY_WIDTH = 1280;
   private static final int DISPLAY_HEIGHT = 720;
   private static final int DISPLAY_DPI = 320;
   // Area not covered by instruments
   private static final int DISPLAY_UNOBSCURED_LEFT = 40;
   private static final int DISPLAY_UNOBSCURED_TOP = 0;
   private static final int DISPLAY_UNOBSCURED_RIGHT = 1200;
   private static final int DISPLAY_UNOBSCURED_BOTTOM = 680;
   @Override
   public void onCreate() {
      super.onCreate();
      // Create a virtual display to render instrument cluster activities on
      mDisplayManager = getSystemService(DisplayManager.class);
      VirtualDisplay display = mDisplayManager.createVirtualDisplay(
          mUniqueId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_DPI, null,
          0 /* flags */, null, null);
      // Do any additional initialization (e.g.: start a video stream
      // based on this virtual display to present activities on a remote
      // display).
      onDisplayReady(display.getDisplay());
}
private void onDisplayReady(Display display) {
    // Report activity options that should be used to launch activities on
    // the instrument cluster.
    String category = CarInstrumentClusterManager.CATEGORY_NAVIGATION;
    ActionOptions options = ActivityOptions.makeBasic()
        .setLaunchDisplayId(display.getDisplayId());
    setClusterActivityOptions(category, options);
    // Report instrument cluster state.
    Rect unobscuredBounds = new Rect(DISPLAY_UNOBSCURED_LEFT,
        DISPLAY_UNOBSCURED_TOP, DISPLAY_UNOBSCURED_RIGHT,
        DISPLAY_UNOBSCURED_BOTTOM);
    boolean visible = true;
    ClusterActivityState state = ClusterActivityState.create(visible,
       unobscuredBounds);
    setClusterActivityState(category, options);
  }
}

Utilizzare l'API CarAppFocusManager

L'API CarAppFocusManager fornisce un metodo denominato getAppTypeOwner(), che consente al servizio cluster scritto dagli OEM di sapere quale app di navigazione ha la selezione della navigazione in un determinato momento. Gli OEM possono utilizzare il metodo CarAppFocusManager#addFocusListener() esistente e poi utilizzare getAppTypeOwner() per scoprire quale app è in primo piano. Con queste informazioni, gli OEM possono:

  • Passa dall'attività mostrata nel cluster all'attività del cluster fornita dall'app di navigazione che mantiene lo stato attivo.
  • Può rilevare se l'app di navigazione selezionata ha un'attività di cluster o meno. Se l'app di navigazione mirata non ha un'attività del cluster (o se questa attività è disattivata), gli OEM possono inviare questo segnale al DIM dell'auto in modo che la sfaccettatura di navigazione del cluster venga ignorata del tutto.

Utilizza CarAppFocusManager per impostare e ascoltare l'app corrente in primo piano, ad esempio la navigazione attiva o un comando vocale. In genere, nel sistema è attiva (o in primo piano) una sola istanza di un'app di questo tipo.

Utilizza il metodo CarAppFocusManager#addFocusListener(..) per rilevare le modifiche della messa a fuoco dell'app:

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
mAppFocusManager.addFocusListener(this, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

...

public void onAppFocusChanged(int appType, boolean active) {
    // Use the CarAppFocusManager#getAppTypeOwner(appType) method call
    // to retrieve a list of active package names
}

Utilizza il metodo CarAppFocusManager#getAppTypeOwner(..) per recuperare i nomi dei pacchetti del proprietario attuale di un determinato tipo di app in primo piano. Questo metodo può restituire più di un nome pacchetto se il proprietario attuale utilizza la funzionalità android:sharedUserId.

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
List<String> focusOwnerPackageNames = mAppFocusManager.getAppTypeOwner(
              CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

if (focusOwnerPackageNames == null || focusOwnerPackageNames.isEmpty()) {
        // No Navigation app has focus
        // OEM may choose to show their default cluster view
} else {
       // focusOwnerPackageNames
       // Use the PackageManager to retrieve the cluster activity for the package(s)
       // returned in focusOwnerPackageNames
}

...

Identificare le app modello

Per le app di navigazione basate su modelli che utilizzano la libreria Car App, CarAppFocusManager#getAppTypeOwner() restituisce il nome del pacchetto dell'host (ad esempio, com.google.android.apps.automotive.templates.host) perché l'host mantiene lo stato attivo del sistema per conto dell'app client.

Per identificare l'app client di navigazione, gli OEM possono estrarre il nome del pacchetto dal bundle dello stato di navigazione inviato con CarNavigationStatusManager. Il nome del pacchetto è memorizzato nella chiave active_app_package_name nel bundle ricevuto da NavigationRenderer#onNavigationStateChanged(Bundle):

// In your NavigationRenderer implementation
@Override
public void onNavigationStateChanged(Bundle bundle) {
    if (bundle.containsKey("active_app_package_name")) {
        String activeAppPackage = bundle.getString("active_app_package_name");
        // Use the package name to identify the navigating app (e.g., com.waze)
    }
}

Appendice: utilizzare l'app di esempio

AOSP fornisce un'app di esempio che implementa l'API Navigation State.

Per eseguire questa app di esempio:

  1. Crea ed esegui il flashing di Android Auto su una HU supportata. Utilizza le istruzioni di creazione ed esecuzione del flashing di Android specifiche per il tuo dispositivo. Per istruzioni, vedi Utilizzo delle schede di riferimento.
  2. Collega un display secondario fisico all'HU (se supportato) o attiva l'HU secondario virtuale:
    1. Seleziona Modalità sviluppatore nell'app Impostazioni.
    2. Vai a Impostazioni > Sistema > Avanzate > Opzioni sviluppatore > Simula display secondari.
  3. Riavvia l'HU
  4. Per avviare l'app KitchenSink:
    1. Apri il riquadro a scomparsa.
    2. Vai a Inst. Cluster.
    3. Fai clic su AVVIA METADATI.

KitchenSink richiede il focus NAVIGATION, che indica al servizio DirectRenderingCluster di visualizzare un'interfaccia utente simulata sul quadro strumenti.