Instrument Cluster API

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.

CarInstrumentClusterManager
Eine Instanz von 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.
CarManager
Basisklasse aller Manager, die von externen Apps verwendet werden, um mit fahrzeugspezifischen Diensten zu interagieren, die von CarService implementiert werden.
CarService
Android-Plattformdienst, der die Kommunikation zwischen externen Apps (einschließlich Google Maps) und fahrzeugspezifischen Funktionen wie dem Zugriff auf das Kombiinstrument ermöglicht.
Ziel
Das endgültige Ziel, zu dem das Fahrzeug fahren soll.
Voraussichtliche Ankunftszeit
Die voraussichtliche Ankunftszeit an einem Ziel.
Infotainmentsystem (Head Unit, HU)
Die primäre Recheneinheit, die in ein Auto eingebettet ist. Das HU führt den gesamten Android-Code aus und ist mit dem zentralen Display im Auto verbunden.
Kombiinstrument
Sekundäres Display hinter dem Lenkrad und zwischen den Instrumenten des Fahrzeugs. Dies kann eine unabhängige Recheneinheit sein, die über das interne Netzwerk des Fahrzeugs (CAN-Bus) mit der HU verbunden ist, oder ein sekundäres Display, das an der HU angebracht ist.
InstrumentClusterRenderingService
Basisklasse für den Dienst, der für die Schnittstelle zum Kombiinstrument verwendet wird. OEMs müssen eine Erweiterung dieser Klasse bereitstellen, die mit der OEM-spezifischen Hardware interagiert.
KitchenSink-App
Test-App, die in Android Automotive enthalten ist.
Route
Ein bestimmter Pfad, den ein Fahrzeug zurücklegt, um ein Ziel zu erreichen.
Singleton-Dienst
Ein Android-Dienst mit dem Attribut 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

Integrationskomponenten

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:

Integrationssequenz

In dieser Abbildung stehen die Farben für Folgendes:

  • Gelb CarService und CarNavigationStatusManager 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:

  1. CarService initialisiert die InstrumentClusterRenderingService.
  2. Während der Initialisierung aktualisiert InstrumentClusterRenderingService CarService mit den folgenden Informationen:
    1. Anzeigeeigenschaften des Kombiinstruments, z. B. die Begrenzungen, die nicht verdeckt werden dürfen (weitere Informationen zu nicht verdeckten Begrenzungen finden Sie weiter unten).
    2. Aktivitätsoptionen, die zum Starten von Aktivitäten auf dem Kombiinstrument erforderlich sind. Weitere Informationen finden Sie unter ActivityOptions.
  3. Eine Navigations-App (z. B. Google Maps für Android Auto oder eine andere Karten-App mit den erforderlichen Berechtigungen):
    1. Ruft eine CarAppFocusManager mit der Car-Klasse aus der car-lib ab.
    2. Vor Beginn der detaillierten Wegbeschreibung werden Aufrufe an CarAppFocusManager.requestFocus() gesendet, um CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION als Parameter appType zu übergeben.
  4. CarAppFocusManager sendet diese Anfrage an CarService. Wenn die Berechtigung gewährt wird, prüft CarService das Navigations-App-Paket und sucht nach einer Aktivität, die mit der Kategorie android.car.cluster.NAVIGATION gekennzeichnet ist.
  5. Wenn gefunden, verwendet die Navigations-App die vom InstrumentClusterRenderingService gemeldete ActivityOptions, 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 die CarService gebunden ist:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

InstrumentClusterRenderingService implementieren

So erstellen Sie den Dienst:

  1. 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.
  2. 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).
  3. Wenn das oben angegebene Display bereit ist, muss dieser Dienst InstrumentClusterRenderingService#setClusterActivityLaunchOptions() aufrufen, um die genaue ActivityOptions zu definieren, die zum Anzeigen einer Aktivität im Kombiinstrument verwendet werden muss. Verwenden Sie die folgenden Parameter:
    • category. ClusterRenderingService.
    • ActivityOptions. Eine ActivityOptions-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));
  4. 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.
  5. Ü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:

  1. 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.
  2. Schließen Sie ein physisches sekundäres Display an das HU an (falls unterstützt) oder aktivieren Sie das virtuelle sekundäre HU:
    1. Wählen Sie in den Einstellungen die Option Entwicklermodus aus.
    2. Gehen Sie zu Einstellungen > System > Erweitert > Entwickleroptionen > Sekundäre Displays simulieren.
  3. HU neu starten
  4. So starten Sie die KitchenSink-App:
    1. Öffnen Sie die Schublade.
    2. Gehen Sie zu Inst. Cluster.
    3. Klicke auf METADATEN STARTEN.

KitchenSink fordert den NAVIGATION-Fokus an, wodurch der DirectRenderingCluster-Dienst angewiesen wird, eine simulierte Benutzeroberfläche auf dem Kombiinstrument anzuzeigen.