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.
CarManager
che consente alle app esterne di avviare un'attività sul quadro strumenti e di ricevere callback quando il quadro strumenti è pronto per visualizzare le attività.android:singleUser
. In qualsiasi momento, sul sistema Android viene eseguita al massimo un'istanza del servizio.Prerequisiti
Prima di continuare, assicurati di disporre dei seguenti elementi:
- Ambiente di sviluppo Android. Per configurare l'ambiente di sviluppo Android, consulta Requisiti di compilazione.
- Scarica il codice sorgente di Android. Scarica la versione più recente del codice sorgente di Android dal ramo pi-car-release (o successivo) all'indirizzo https://android.googlesource.com.
- Unità principale (HU). Un dispositivo Android in grado di eseguire Android 9 (o versioni successive). Questo dispositivo deve avere un proprio display ed essere in grado di eseguire il flashing del display con nuove build di Android.
- Quadro di strumentazione è 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 simulato. Durante lo sviluppo, puoi utilizzare uno di questi ambienti simulati:
- Display secondari simulati. Per attivare un display secondario simulato su qualsiasi distribuzione Android AOSP, vai alle impostazioni Opzioni sviluppatore nell'app di sistema Impostazioni e seleziona Simula display secondari. Questa configurazione è equivalente all'attacco di un display secondario fisico, con la limitazione che questo display è sovrapposto al display principale.
- Gruppo di strumenti simulato. L'emulatore Android incluso con 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
- Servizio quadro strumenti OEM
CarService
CarService
agisce da intermediario tra le app di navigazione e l'auto, garantendo che in un determinato momento sia attiva una sola app di navigazione e che solo le app con l'autorizzazione android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL
possano inviare dati all'auto.
CarService
avvia tutti i servizi specifici dell'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 cruscotto, gli OEM nel settore auto e motori devono creare un'implementazione personalizzata di InstrumentClusterRendererService e aggiornare ClusterRenderingService.
Durante la visualizzazione di un quadro strumenti, durante la procedura di avvio, CarService
legge la chiave InstrumentClusterRendererService
del ClusterRenderingService per individuare un'implementazione di InstrumentClusterService
. In AOSP, questa voce
indica il 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, bound si riferisce a
Android
Services.
Servizio Quadro strumenti
Gli OEM devono creare un pacchetto Android (APK) contenente una sottoclasse di ClusterRenderingService.
Questo corso ha due scopi:
- Fornisce un'interfaccia per Android e il dispositivo di rendering del cruscotto (scopo di questa pagina).
- Riceve e mostra 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 dell'abitacolo dell'auto e
comunicarle a CarService
chiamando i metodi
InstrumentClusterRendererService.setClusterActivityOptions()
e
InstrumentClusterRendererService.setClusterActivityState()
.
Per la seconda funzione, il servizio del quadro strumenti deve fornire un'implementazione dell'interfaccia ClusterRenderingService che riceve gli 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:
In questa illustrazione, i colori indicano quanto segue:
- Giallo.
CarService
eCarNavigationStatusManager
forniti dalla piattaforma Android. Per scoprire di più, consulta Auto e CAR_NAVIGATION_SERVICE. - Ciano.
InstrumentClusterRendererService
implementato dall'OEM. - Viola. L'app di navigazione implementata da Google e da sviluppatori di terze parti.
- Verde.
CarAppFocusManager
. Per saperne di più, consulta Utilizzo dell'API CarAppFocusManager di seguito e CarAppFocusManager.
Il flusso di informazioni dello stato di navigazione segue questa sequenza:
CarService
inizializzaInstrumentClusterRenderingService
.- Durante l'inizializzazione,
InstrumentClusterRenderingService
aggiornaCarService
con:- Proprietà di visualizzazione del cruscotto, ad esempio i confini non oscurati (vedi più dettagli sui confini non oscurati di seguito).
- Opzioni di attività necessarie per avviare le attività all'interno del display del quadro strumenti. Per saperne di più, consulta ActivityOptions.
- Un'app di navigazione (ad esempio Google Maps per Android Automotive o qualsiasi app di mappe con le autorizzazioni richieste):
- Ottiene un
CarAppFocusManager
utilizzando la classe Car di car-lib. - Prima dell'inizio delle indicazioni stradali passo passo, le chiamate a
CarAppFocusManager.requestFocus()
devono passareCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION
come parametroappType
.
- Ottiene un
CarAppFocusManager
comunica questa richiesta aCarService
. Se concessa,CarService
ispeziona il pacchetto dell'app di navigazione e individua un'attività contrassegnata con la categoriaandroid.car.cluster.NAVIGATION
.- Se viene trovato, l'app di navigazione utilizza il
ActivityOptions
segnalato dalInstrumentClusterRenderingService
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 al file AndroidManifest.xml. Questo è necessario per garantire l'esecuzione di una singola copia del servizio Instrument Cluster, anche durante l'inizializzazione e il passaggio da un utente all'altro:
android:singleUser="true"
- Devi disporre dell'autorizzazione di sistema
BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE
. In questo modo, viene garantito che solo il servizio di rendering del cruscotto incluso nell'immagine di sistema Android sia vincolato daCarService
:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
Implementare InstrumentClusterRenderingService
Per compilare il servizio:
- Scrivi una classe che espanda ClusterRenderingService e poi aggiungi una voce corrispondente al file
AndroidManifest.xml
. Questa classe controlla il display del quadro strumenti e può (facoltativamente) visualizzare i dati dell'API Stato di navigazione. - Durante
onCreate()
, utilizza questo servizio per inizializzare la comunicazione con l'hardware di rendering. Le opzioni includono:- 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 visualizzata a un'unità esterna (utilizzando un formato di streaming video, ad esempio H.264).
- Quando il display indicato sopra è pronto, questo servizio deve chiamare
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()
per definire il valoreActivityOptions
esatto da utilizzare per visualizzare un'attività sul quadro strumenti. Utilizza questi parametri:category.
ClusterRenderingService.ActivityOptions.
Un'istanzaActivityOptions
che può essere impiegata per avviare un'attività nel quadro strumenti. Ad esempio, dall'implementazione di un cluster di strumenti di esempio su AOSP:getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- 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 che il quadro strumenti è visibile e pronto per visualizzare i contenuti.unobscuredBounds
Un rettangolo che definisce l'area all'interno del display del quadro strumenti in cui è possibile mostrare i contenuti in sicurezza. Ad esempio, le aree coperte da quadranti e indicatori.
- Sostituisci il metodo
Service#dump()
e segnala le informazioni sullo stato utili per il debugging (consulta dumpsys per ulteriori informazioni).
Esempio di implementazione di InstrumentClusterRenderingService
L'esempio seguente illustra 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 passare 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 il focus di navigazione in un determinato momento. Gli OEM possono utilizzare il metodo CarAppFocusManager#addFocusListener()
esistente e poi getAppTypeOwner()
per sapere quale app è attiva. Con queste informazioni,
gli OEM possono:
- Passare dall'attività mostrata nel cluster all'attività del cluster fornita dall'app di navigazione attiva.
- Può rilevare se l'app di navigazione attiva ha o meno un'attività di cluster. Se l'app di navigazione attiva 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 funzionalità di navigazione del cluster venga ignorata del tutto.
Usa CarAppFocusManager
per impostare e ascoltare l'app attualmente attiva, ad esempio la navigazione attiva o un comando vocale. In genere, nel sistema è in esecuzione (o attiva) solo un'istanza di questo tipo di app.
Utilizza il metodo CarAppFocusManager#addFocusListener(..)
per rilevare le modifiche allo stato attivo 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 corrente 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 } ...
Appendice: utilizzare l'app di esempio
AOSP fornisce un'app di esempio che implementa l'API Navigation State.
Per eseguire questa app di esempio:
- Crea e esegui il flashing di Android Auto su un'unità principale supportata. Utilizza le istruzioni per la compilazione e il flashing di Android specifiche per il tuo dispositivo. Per le istruzioni, consulta Utilizzare le schede di riferimento.
- Collega un display secondario fisico all'HU (se supportato) o attiva l'HU secondario virtuale:
- Seleziona Modalità sviluppatore nell'app Impostazioni.
- Vai a Impostazioni > Sistema > Avanzate > Opzioni sviluppatore > Simula display secondari.
- Riavvia l'HU
- Per avviare l'app KitchenSink:
- Apri il cassetto.
- Vai a Inst. Cluster.
- Fai clic su AVVIA METADATI.
KitchenSink richiede l'attenzione NAVIGATION, che indica al servizio DirectRenderingCluster
di visualizzare un'interfaccia utente simulata sul quadro strumenti.