Mit der Instrument Cluster API (einer Android API) können Sie Navigations-Apps wie Google Maps auf einem sekundären Display in einem Auto anzeigen, z. B. hinter dem Lenkrad auf dem Armaturenbrett. Auf dieser Seite wird beschrieben, wie Sie einen Dienst zum Steuern dieses sekundären Displays erstellen und den Dienst in CarService
einbinden, damit Navigations-Apps eine Benutzeroberfläche anzeigen können.
Terminologie
Auf dieser Seite werden die folgenden Begriffe verwendet.
CarManager
, die es externen Apps ermöglicht, eine Aktivität auf dem Kombiinstrument zu starten und Rückrufe zu erhalten, wenn das Kombiinstrument bereit ist, Aktivitäten anzuzeigen.android:singleUser
. Auf dem Android-System wird immer nur eine Instanz des Dienstes ausgeführt.Voraussetzungen
Bevor Sie fortfahren, benötigen Sie Folgendes:
- Android-Entwicklungsumgebung Informationen zum Einrichten der Android-Entwicklungsumgebung finden Sie unter Build-Anforderungen.
- Laden Sie den Android-Quellcode herunter. Die neueste Version des Android-Quellcodes finden Sie im Branch „pi-car-release“ oder höher unter https://android.googlesource.com.
- Infotainmentsystem (Head Unit, HU). Ein Android-Gerät, auf dem Android 9 oder höher ausgeführt werden kann. Dieses Gerät muss ein eigenes Display haben und in der Lage sein, das Display mit neuen Android-Builds zu flashen.
- Kombiinstrument ist eine der folgenden Optionen:
- Physisches sekundäres Display, das an das HU angeschlossen ist. Ob die Gerätehardware und der Kernel die Verwaltung mehrerer Displays unterstützen.
- Unabhängige Einheit Jede Recheneinheit, die über eine Netzwerkverbindung mit der HU verbunden ist und einen Videostream auf ihrem eigenen Display empfangen und anzeigen kann.
- Emuliertes Display Während der Entwicklung können Sie eine der folgenden emulierten Umgebungen verwenden:
- Simulierte sekundäre Displays Wenn Sie ein simuliertes sekundäres Display auf einer beliebigen AOSP-Android-Distribution aktivieren möchten, rufen Sie in der System-App Einstellungen die Entwickleroptionen auf und wählen Sie Sekundäre Displays simulieren aus. Diese Konfiguration entspricht dem Anschließen eines physischen sekundären Displays, mit der Einschränkung, dass dieses Display über dem primären Display eingeblendet wird.
- Emuliertes Kombiinstrument Der in AAOS enthaltene Android-Emulator bietet die Möglichkeit, ein Kombiinstrument mit ClusterRenderingService anzuzeigen.
Integrationsarchitektur
Integrationskomponenten
Jede Integration der Instrument Cluster API besteht aus diesen drei Komponenten:
CarService
- Navigations-Apps
- OEM-Kombiinstrumentdienst
CarService
CarService
vermittelt zwischen Navigations-Apps und dem Auto und sorgt dafür, dass immer nur eine Navigations-App aktiv ist und nur Apps mit der Berechtigung android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL
Daten an das Auto senden können.
CarService
startet alle fahrzeugspezifischen Dienste und bietet über eine Reihe von Managern Zugriff auf diese Dienste. Um mit den Diensten zu interagieren, können Apps, die im Auto ausgeführt werden, auf diese Manager zugreifen.
Für die Implementierung des Kombiinstruments müssen OEMs aus der Automobilbranche eine benutzerdefinierte Implementierung von InstrumentClusterRendererService erstellen und den ClusterRenderingService aktualisieren.
Beim Rendern eines Kombiinstruments liest CarService
während des Bootvorgangs den InstrumentClusterRendererService
-Schlüssel des ClusterRenderingService, um eine Implementierung von InstrumentClusterService
zu finden. In AOSP verweist dieser Eintrag auf den Renderdienst der Navigation State API-Beispielclusterimplementierung:
<string name="instrumentClusterRendererService"> android.car.cluster/.ClusterRenderingService </string>
Der in diesem Eintrag erwähnte Dienst wird initialisiert und an CarService
gebunden. Wenn Navigations-Apps wie Google Maps eine CarInstrumentClusterManager
anfordern, stellt CarService
einen Manager bereit, der den Status des Kombi-Instruments anhand der verknüpften InstrumentClusterRenderingService
aktualisiert.
(In diesem Fall bezieht sich gebunden auf Android-Dienste.)
Kombiinstrument-Dienst
OEMs müssen ein Android-Paket (APK) erstellen, das eine Unterklasse von ClusterRenderingService enthält.
Diese Klasse dient zwei Zwecken:
- Bietet eine Schnittstelle zwischen Android und dem Instrumentencluster-Renderinggerät (Zweck dieser Seite).
- Erhält und rendert Updates zum Navigationsstatus, z. B. zur detaillierten Routenführung.
Für den ersten Zweck müssen OEM-Implementierungen von InstrumentClusterRendererService
das sekundäre Display initialisieren, das zum Rendern von Informationen auf Bildschirmen im Auto verwendet wird, und diese Informationen an CarService
weitergeben, indem sie die Methoden InstrumentClusterRendererService.setClusterActivityOptions()
und InstrumentClusterRendererService.setClusterActivityState()
aufrufen.
Für die zweite Funktion muss der Kombiinstrumenten-Dienst eine Implementierung der ClusterRenderingService-Schnittstelle bereitstellen, die Ereignisse zum Aktualisieren des Navigationsstatus empfängt, die als eventType
und Ereignisdaten in einem Bundle codiert sind.
Integrationssequenz
Das folgende Diagramm zeigt die Implementierung eines Navigationsstatus, der Aktualisierungen rendert:
In dieser Abbildung stehen die Farben für Folgendes:
- Gelb
CarService
undCarNavigationStatusManager
werden von der Android-Plattform bereitgestellt. Weitere Informationen finden Sie unter Auto und CAR_NAVIGATION_SERVICE. - Cyan
InstrumentClusterRendererService
vom OEM implementiert. - Lila Die Navigations-App, die von Google und Drittanbietern implementiert wird.
- Grün
CarAppFocusManager
. Weitere Informationen finden Sie unten unter CarAppFocusManager API verwenden und CarAppFocusManager.
Der Informationsfluss für den Navigationsstatus folgt dieser Abfolge:
CarService
initialisiert dieInstrumentClusterRenderingService
.- Während der Initialisierung aktualisiert
InstrumentClusterRenderingService
CarService
mit den folgenden Informationen:- Anzeigeeigenschaften des Kombiinstruments, z. B. die Begrenzungen, die nicht verdeckt werden dürfen (weitere Informationen zu nicht verdeckten Begrenzungen finden Sie weiter unten).
- Aktivitätsoptionen, die zum Starten von Aktivitäten auf dem Kombiinstrument erforderlich sind. Weitere Informationen finden Sie unter ActivityOptions.
- Eine Navigations-App (z. B. Google Maps für Android Auto oder eine andere Karten-App mit den erforderlichen Berechtigungen):
- Ruft eine
CarAppFocusManager
mit der Car-Klasse aus der car-lib ab. - Vor Beginn der detaillierten Wegbeschreibung werden Aufrufe an
CarAppFocusManager.requestFocus()
gesendet, umCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION
als ParameterappType
zu übergeben.
- Ruft eine
CarAppFocusManager
sendet diese Anfrage anCarService
. Wenn die Berechtigung gewährt wird, prüftCarService
das Navigations-App-Paket und sucht nach einer Aktivität, die mit der Kategorieandroid.car.cluster.NAVIGATION
gekennzeichnet ist.- Wenn gefunden, verwendet die Navigations-App die vom
InstrumentClusterRenderingService
gemeldeteActivityOptions
, um die Aktivität zu starten, und fügt die Displayeigenschaften des Kombiinstruments als Extras in den Intent ein.
API einbinden
Die InstrumentClusterRenderingService
-Implementierung muss:
- Sie müssen als Singleton-Dienst gekennzeichnet sein. Fügen Sie dazu der Datei „AndroidManifest.xml“ den folgenden Wert hinzu. Dies ist erforderlich, damit immer eine einzige Kopie des Kombiinstrumenten-Dienstes ausgeführt wird, auch während der Initialisierung und des Nutzerwechsels:
android:singleUser="true"
- Sie haben die Systemberechtigung
BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE
. So wird sichergestellt, dass nur der im Android-System-Image enthaltene Renderingdienst für das Kombiinstrument an dieCarService
gebunden ist:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
InstrumentClusterRenderingService implementieren
So erstellen Sie den Dienst:
- Erstellen Sie eine Klasse, die von ClusterRenderingService abgeleitet ist, und fügen Sie der Datei
AndroidManifest.xml
einen entsprechenden Eintrag hinzu. Diese Klasse steuert das Kombiinstrumenten-Display und kann (optional) Navigationsstatus-API-Daten rendern. - Verwenden Sie diesen Dienst während
onCreate()
, um die Kommunikation mit der Rendering-Hardware zu initialisieren. Zu den Optionen gehören:- Legen Sie das sekundäre Display fest, das für das Kombiinstrument verwendet werden soll.
- Erstellen Sie ein virtuelles Display, damit die Instrumentencluster-App das gerenderte Bild rendert und an ein externes Gerät überträgt (mit einem Videostreaming-Format wie H.264).
- Wenn das oben angegebene Display bereit ist, muss dieser Dienst
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()
aufrufen, um die genaueActivityOptions
zu definieren, die zum Anzeigen einer Aktivität im Kombiinstrument verwendet werden muss. Verwenden Sie die folgenden Parameter:category.
ClusterRenderingService.ActivityOptions.
EineActivityOptions
-Instanz, mit der eine Aktivität im Kombiinstrument gestartet werden kann. Beispiel aus der Beispielimplementierung des Kombiinstruments in AOSP:getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- Wenn das Kombiinstrument bereit ist, Aktivitäten anzuzeigen, muss dieser Dienst
InstrumentClusterRenderingService#setClusterActivityState()
aufrufen. Verwenden Sie die folgenden Parameter:category
ClusterRenderingService.state
Bundle, das mit ClusterRenderingService generiert wurde. Geben Sie unbedingt folgende Daten an:visible
Gibt an, dass das Kombiinstrument sichtbar ist und Inhalte anzeigen kann.unobscuredBounds
Ein Rechteck, das den Bereich auf dem Kombiinstrument definiert, in dem Inhalte sicher angezeigt werden können. Beispielsweise Bereiche, die von Zifferblättern und Messinstrumenten abgedeckt sind.
- Überschreiben Sie die
Service#dump()
-Methode und melden Sie Statusinformationen, die für die Fehlerbehebung nützlich sind. Weitere Informationen finden Sie unter dumpsys.
Beispielimplementierung von InstrumentClusterRenderingService
Im folgenden Beispiel wird eine InstrumentClusterRenderingService
-Implementierung beschrieben, bei der ein VirtualDisplay
erstellt wird, um die Inhalte des Instrumentenclusters auf einem externen physischen Display anzuzeigen.
Alternativ kann dieser Code die displayId
eines physischen sekundären Displays übergeben, das mit der HU verbunden ist, sofern bekannt ist, dass eines verfügbar ist.
/** * 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); } }
CarAppFocusManager API verwenden
Die CarAppFocusManager API bietet eine Methode namens getAppTypeOwner()
, mit der der von OEMs geschriebene Clusterdienst jederzeit erkennen kann, welche Navigations-App den Navigationsfokus hat. OEMs können die vorhandene CarAppFocusManager#addFocusListener()
-Methode verwenden und dann mit getAppTypeOwner()
herausfinden, welche App den Fokus hat. Mit diesen Informationen können OEMs:
- Wechseln Sie die im Cluster angezeigte Aktivität zur Clusteraktivität, die von der Navigations-App bereitgestellt wird, die den Fokus hat.
- Kann erkennen, ob die aktive Navigations-App eine Clusteraktivität hat oder nicht. Wenn die fokussierte Navigations-App keine Clusteraktivität hat (oder diese Aktivität deaktiviert ist), können OEMs dieses Signal an das DIM des Autos senden, damit die Navigationsfacette des Clusters vollständig übersprungen wird.
Mit CarAppFocusManager
können Sie den aktuellen App-Effekt festlegen und auf ihn warten, z. B. auf aktive Navigation oder einen Sprachbefehl. Normalerweise wird im System nur eine Instanz einer solchen App aktiv ausgeführt (oder ist im Fokus).
Verwenden Sie die Methode CarAppFocusManager#addFocusListener(..)
, um Änderungen am App-Fokus zu überwachen:
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 }
Mit der Methode CarAppFocusManager#getAppTypeOwner(..)
können Sie die Paketnamen des aktuellen Inhabers eines bestimmten App-Typs abrufen, der im Fokus steht. Diese Methode kann mehr als einen Paketnamen zurückgeben, wenn der aktuelle Inhaber die Funktion android:sharedUserId
verwendet.
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 } ...
Anhang: Beispiel-App verwenden
AOSP bietet eine Beispielanwendung, die die Navigation State API implementiert.
So führen Sie diese Beispielanwendung aus:
- Android Auto auf einer unterstützten Infotainmentanlage erstellen und flashen Folgen Sie der Anleitung zum Erstellen und Flashen von Android-Firmware, die für Ihr Gerät spezifisch ist. Eine Anleitung finden Sie unter Referenzboards verwenden.
- Schließen Sie ein physisches sekundäres Display an das HU an (falls unterstützt) oder aktivieren Sie das virtuelle sekundäre HU:
- Wählen Sie in den Einstellungen die Option Entwicklermodus aus.
- Gehen Sie zu Einstellungen > System > Erweitert > Entwickleroptionen > Sekundäre Displays simulieren.
- HU neu starten
- So starten Sie die KitchenSink-App:
- Öffnen Sie die Schublade.
- Gehen Sie zu Inst. Cluster.
- Klicke auf METADATEN STARTEN.
KitchenSink fordert den NAVIGATION-Fokus an, wodurch der DirectRenderingCluster
-Dienst angewiesen wird, eine simulierte Benutzeroberfläche auf dem Kombiinstrument anzuzeigen.