Instrument Cluster API

Używaj interfejsu Instrument Cluster API (interfejsu Androida), aby wyświetlać aplikacje do nawigacji, w tym Mapy Google, na dodatkowym wyświetlaczu w samochodzie, np. za kierownicą na desce rozdzielczej. Na tej stronie dowiesz się, jak utworzyć usługę do sterowania tym dodatkowym wyświetlaczem i zintegrować ją z CarService, aby aplikacje do nawigacji mogły wyświetlać interfejs użytkownika.

Terminologia

Na tej stronie używane są te terminy:

CarInstrumentClusterManager
Instancja CarManager, która umożliwia aplikacjom zewnętrznym uruchamianie aktywności w klastrze przyrządów i otrzymywanie wywołań zwrotnych, gdy klaster przyrządów jest gotowy do wyświetlania aktywności.
CarManager
Klasa bazowa wszystkich menedżerów używanych przez aplikacje zewnętrzne do interakcji z usługami specyficznymi dla samochodu zaimplementowanymi przez CarService.
CarService
Usługa platformy Android, która zapewnia komunikację między aplikacjami zewnętrznymi (w tym Mapami Google) a funkcjami specyficznymi dla samochodu, takimi jak dostęp do zestawu wskaźników.
Miejsce docelowe
Miejsce docelowe, do którego ma dotrzeć pojazd.
Szacowany czas dotarcia (ETA)
Szacowany czas dotarcia do miejsca docelowego.
Jednostka główna (HU)
Główna jednostka obliczeniowa wbudowana w samochód. Jednostka główna uruchamia cały kod Androida i jest połączona z centralnym wyświetlaczem w samochodzie.
Zestaw wskaźników
Dodatkowy wyświetlacz znajduje się za kierownicą, między wskaźnikami samochodu. Może to być niezależna jednostka obliczeniowa połączona z HU za pomocą wewnętrznej sieci samochodu (szyny CAN) lub dodatkowy wyświetlacz podłączony do HU.
InstrumentClusterRenderingService
Klasa bazowa usługi używanej do komunikacji z wyświetlaczem zestawu wskaźników. Producenci OEM muszą udostępnić rozszerzenie tej klasy, które wchodzi w interakcję ze sprzętem specyficznym dla danego producenta.
Aplikacja KitchenSink
Aplikacja testowa jest dołączona do Androida Automotive.
Trasa
Konkretna ścieżka, po której porusza się pojazd, aby dotrzeć do miejsca docelowego.
Usługa singleton
Usługa na Androida z atrybutem android:singleUser. W danym momencie w systemie Android może działać co najwyżej 1 instancja usługi.

Wymagania wstępne

Zanim przejdziesz dalej, przygotuj te elementy:

  • Środowisko programistyczne Androida Aby skonfigurować środowisko programistyczne Androida, zapoznaj się z wymaganiami dotyczącymi kompilacji.
  • Pobierz kod źródłowy Androida. Pobierz najnowszą wersję kodu źródłowego Androida z gałęzi pi-car-release (lub nowszej) na stronie https://android.googlesource.com.
  • Jednostka główna (HU) urządzenie z Androidem 9 (lub nowszym), Urządzenie musi mieć własny wyświetlacz i możliwość wyświetlania nowych wersji Androida.
  • Tablica wskaźników jest jednym z tych elementów:
    • Fizyczny wyświetlacz dodatkowy podłączony do HU. jeśli sprzęt i jądro urządzenia obsługują zarządzanie wieloma wyświetlaczami;
    • Jednostka niezależna. Każda jednostka obliczeniowa połączona z HU za pomocą połączenia sieciowego, która może odbierać i wyświetlać strumień wideo na własnym wyświetlaczu.
    • Emulowany wyświetlacz. Podczas programowania możesz użyć jednego z tych emulowanych środowisk:
      • Symulowane ekrany dodatkowe. Aby włączyć symulowany dodatkowy wyświetlacz w dowolnej dystrybucji Androida AOSP, otwórz Opcje programisty w aplikacji systemowej Ustawienia, a następnie wybierz Symuluj dodatkowe wyświetlacze. Ta konfiguracja jest równoważna z podłączeniem fizycznego dodatkowego wyświetlacza, z tym ograniczeniem, że ten wyświetlacz jest nałożony na wyświetlacz główny.
      • Emulowana tablica wskaźników Emulator Androida dołączony do AAOS umożliwia wyświetlanie zestawu wskaźników za pomocą ClusterRenderingService.

Architektura integracji

Komponenty integracji

Każda integracja interfejsu Instrument Cluster API składa się z tych 3 komponentów:

  • CarService
  • Aplikacje do nawigacji
  • Usługa tablicy wskaźników OEM

Komponenty integracji

CarService

CarService pośredniczy między aplikacjami do nawigacji a samochodem, zapewniając, że w danym momencie aktywna jest tylko jedna aplikacja do nawigacji, a tylko aplikacje z uprawnieniem android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL mogą wysyłać dane do samochodu.

CarService uruchamia wszystkie usługi związane z samochodem i zapewnia do nich dostęp za pomocą szeregu menedżerów. Aby korzystać z usług, aplikacje działające w samochodzie mogą uzyskiwać dostęp do tych menedżerów.

W przypadku implementacji zestawu wskaźników producenci OEM muszą utworzyć niestandardową implementację InstrumentClusterRendererService i zaktualizować ClusterRenderingService.

Podczas renderowania klastra przyrządów w trakcie procesu uruchamiania CarService odczytuje klucz InstrumentClusterRendererService usługi ClusterRenderingService, aby znaleźć implementację interfejsu InstrumentClusterService. W AOSP ten wpis wskazuje usługę renderowania przykładowej implementacji klastra interfejsu Navigation State API:

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

Usługa, o której mowa w tym wpisie, jest zainicjowana i powiązana z CarService. Gdy aplikacje nawigacyjne, takie jak Mapy Google, wysyłają żądanie CarInstrumentClusterManager, CarService udostępnia menedżera, który aktualizuje stan grupy przyrządów na podstawie powiązanego InstrumentClusterRenderingService. (W tym przypadku powiązane oznacza Usługi Androida.)

Usługa klastra przyrządów

Producenci OEM muszą utworzyć pakiet Androida (APK), który zawiera podklasę ClusterRenderingService.

Ta klasa służy 2 celom:

  • Udostępnia interfejs Androida i urządzenia renderującego zestaw wskaźników (cel tej strony).
  • Otrzymuje i wyświetla aktualizacje stanu nawigacji, np. szczegółowe wskazówki dojazdu.

W pierwszym przypadku implementacje OEM InstrumentClusterRendererServicemuszą zainicjować dodatkowy wyświetlacz używany do renderowania informacji na ekranach w kabinie samochodu i przekazać te informacje do CarService, wywołując metody InstrumentClusterRendererService.setClusterActivityOptions()InstrumentClusterRendererService.setClusterActivityState().

W przypadku drugiej funkcji usługa Instrument Cluster musi udostępniać implementację interfejsu ClusterRenderingService, który odbiera zdarzenia aktualizacji stanu nawigacji zakodowane jako eventType i dane zdarzenia zakodowane w pakiecie.

Sekwencja integracji

Poniższy diagram ilustruje implementację stanu nawigacji, który renderuje aktualizacje:

Sekwencja integracji

Na tej ilustracji kolory oznaczają:

  • Żółty CarServiceCarNavigationStatusManager udostępniane przez platformę Androida. Więcej informacji znajdziesz w sekcjach SamochódCAR_NAVIGATION_SERVICE.
  • Cyjan InstrumentClusterRendererService wdrożone przez producenta OEM.
  • Fioletowy. Aplikacja do nawigacji wdrożona przez Google i deweloperów zewnętrznych.
  • Zielony CarAppFocusManager. Więcej informacji znajdziesz w sekcji Korzystanie z interfejsu CarAppFocusManager API poniżej oraz w artykule CarAppFocusManager.

Przepływ informacji o stanie nawigacji przebiega w tej kolejności:

  1. CarService inicjuje InstrumentClusterRenderingService.
  2. Podczas inicjowania InstrumentClusterRenderingService aktualizuje CarService za pomocą:
    1. Właściwości wyświetlacza zestawu wskaźników, takie jak niezasłonięte granice (więcej informacji o niezasłoniętych granicach znajdziesz poniżej).
    2. Opcje aktywności potrzebne do uruchamiania aktywności na wyświetlaczu klastra przyrządów. Więcej informacji znajdziesz w artykule ActivityOptions.
  3. Aplikacja do nawigacji (np. Mapy Google na Androida Automotive lub dowolna aplikacja do map z wymaganymi uprawnieniami):
    1. Uzyskuje CarAppFocusManager za pomocą klasy Car z biblioteki car-lib.
    2. Zanim rozpoczną się szczegółowe wskazówki dojazdu, wywołaj funkcję CarAppFocusManager.requestFocus(), aby przekazać CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION jako parametr appType.
  4. CarAppFocusManager przekazuje tę prośbę do CarService. Jeśli uprawnienie zostanie przyznane, CarService sprawdzi pakiet aplikacji do nawigacji i znajdzie aktywność oznaczoną kategorią android.car.cluster.NAVIGATION.
  5. Jeśli zostanie znaleziony, aplikacja do nawigacji użyje ActivityOptions zgłoszonego przez InstrumentClusterRenderingService, aby uruchomić aktywność, i uwzględni właściwości wyświetlania na tablicy wskaźników jako dodatki w intencji.

Integracja interfejsu API

Implementacja usługi InstrumentClusterRenderingService musi:

  • Oznacz usługę jako pojedynczą, dodając do pliku AndroidManifest.xml tę wartość: Jest to konieczne, aby zapewnić działanie pojedynczej kopii usługi Instrument Cluster, nawet podczas inicjowania i przełączania użytkowników:
    android:singleUser="true"
  • mają uprawnienia systemowe BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE; Daje to gwarancję, że tylko usługa renderowania zestawu wskaźników dołączona do obrazu systemu Android jest kiedykolwiek powiązana przez CarService:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

Implementowanie InstrumentClusterRenderingService

Aby skompilować usługę:

  1. Napisz klasę, która rozszerza ClusterRenderingService, a następnie dodaj odpowiedni wpis do pliku AndroidManifest.xml. Ta klasa steruje wyświetlaczem grupy przyrządów i może (opcjonalnie) renderować dane interfejsu Navigation State API.
  2. Podczas onCreate() użyj tej usługi, aby zainicjować komunikację ze sprzętem renderującym. Dostępne opcje to:
    • Określ dodatkowy wyświetlacz, który ma być używany w przypadku zestawu wskaźników.
    • Utwórz wirtualny wyświetlacz, aby aplikacja Instrument Cluster renderowała i przesyłała wyrenderowany obraz do urządzenia zewnętrznego (w formacie strumieniowania wideo, np. H.264).
  3. Gdy wyświetlacz wskazany powyżej jest gotowy, ta usługa musi wywołać InstrumentClusterRenderingService#setClusterActivityLaunchOptions(), aby określić dokładny ActivityOptions, który musi być używany do wyświetlania aktywności na zestawie wskaźników. Użyj tych parametrów:
    • category. ClusterRenderingService
    • ActivityOptions. Instancja ActivityOptions, której można użyć do uruchomienia aktywności w klastrze przyrządów. Na przykład w przykładowej implementacji zestawu wskaźników w AOSP:
      getService().setClusterActivityLaunchOptions(
        CATEGORY_NAVIGATION,
        ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
  4. Gdy zestaw wskaźników jest gotowy do wyświetlania aktywności, ta usługa musi wywołać funkcję InstrumentClusterRenderingService#setClusterActivityState(). Użyj tych parametrów:
    • category ClusterRenderingService
    • state Pakiet wygenerowany za pomocą usługi ClusterRenderingService. Podaj te dane:
      • visible Określa, że zestaw wskaźników jest widoczny i gotowy do wyświetlania treści.
      • unobscuredBounds Prostokąt określający obszar na wyświetlaczu zestawu wskaźników, w którym można bezpiecznie wyświetlać treści. Na przykład obszary pokryte tarczami i wskaźnikami.
  5. Zastąp metodę Service#dump() i zgłoś informacje o stanie przydatne do debugowania (więcej informacji znajdziesz w artykule o dumpsys).

Przykładowa implementacja usługi InstrumentClusterRenderingService

Poniższy przykład przedstawia InstrumentClusterRenderingServiceimplementację, która tworzy VirtualDisplay do wyświetlania treści Instrument Cluster na zdalnym wyświetlaczu fizycznym.

Może też przekazywać displayId fizycznego wyświetlacza dodatkowego podłączonego do HU, jeśli wiadomo, że jest on dostępny.

/**
* 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);
  }
}

Korzystanie z interfejsu CarAppFocusManager API

Interfejs CarAppFocusManager API udostępnia metodę o nazwie getAppTypeOwner(), która umożliwia usłudze klastra napisanej przez producentów OEM określanie, która aplikacja do nawigacji ma w danym momencie zaznaczenie nawigacji. Producenci OEM mogą używać dotychczasowej metody CarAppFocusManager#addFocusListener(), a następnie używać getAppTypeOwner(), aby dowiedzieć się, która aplikacja jest aktywna. Dzięki tym informacjom producenci OEM mogą:

  • Przełącz aktywność wyświetlaną w klastrze na aktywność klastra dostarczaną przez aplikację do nawigacji, która jest aktywna.
  • Może wykrywać, czy aktywna aplikacja do nawigacji ma aktywność klastra. Jeśli aplikacja nawigacyjna nie ma aktywności klastra (lub jeśli taka aktywność jest wyłączona), producenci OEM mogą wysłać ten sygnał do DIM samochodu, aby całkowicie pominąć aspekt nawigacji w klastrze.

Użyj CarAppFocusManager, aby ustawić i odsłuchać bieżący fokus aplikacji, np. aktywną nawigację lub polecenie głosowe. Zwykle tylko jedno wystąpienie takiej aplikacji jest aktywnie uruchomione (lub aktywne) w systemie.

Użyj metody CarAppFocusManager#addFocusListener(..), aby nasłuchiwać zmian aktywności aplikacji:

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
}

Użyj metody CarAppFocusManager#getAppTypeOwner(..), aby pobrać nazwy pakietów bieżącego właściciela danego typu aplikacji, który jest w centrum uwagi. Ta metoda może zwrócić więcej niż jedną nazwę pakietu, jeśli obecny właściciel korzysta z funkcji 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
}

...

Identyfikowanie aplikacji szablonowych

W przypadku aplikacji do nawigacji opartych na szablonach, które korzystają z biblioteki aplikacji do samochodu, funkcja CarAppFocusManager#getAppTypeOwner() zwraca nazwę pakietu hosta (np. com.google.android.apps.automotive.templates.host) , ponieważ host utrzymuje fokus systemu w imieniu aplikacji klienta.

Aby zidentyfikować aplikację kliencką, która inicjuje nawigację, producenci OEM mogą wyodrębnić nazwę pakietu z pakietu stanu nawigacji wysyłanego z CarNavigationStatusManager. Nazwa pakietu jest przechowywana pod kluczem active_app_package_name w pakiecie otrzymanym przez 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)
    }
}

Dodatek: korzystanie z przykładowej aplikacji

AOSP udostępnia przykładową aplikację, która implementuje interfejs Navigation State API.

Aby uruchomić tę przykładową aplikację:

  1. Skompiluj i zainstaluj Androida Auto na obsługiwanym panelu. Postępuj zgodnie z instrukcjami kompilacji i flashowania Androida dla konkretnego urządzenia. Instrukcje znajdziesz w artykule Korzystanie z tablic referencyjnych.
  2. Podłącz fizyczny wyświetlacz dodatkowy do HU (jeśli jest obsługiwany) lub włącz wirtualny wyświetlacz dodatkowy:
    1. W aplikacji Ustawienia wybierz Tryb programisty.
    2. Otwórz kolejno Ustawienia > System > Zaawansowane > Opcje programisty > Symuluj wyświetlacze dodatkowe.
  3. Uruchom ponownie HU
  4. Aby uruchomić aplikację KitchenSink:
    1. Otwórz szufladę.
    2. Otwórz Inst. Cluster (Klaster instancji).
    3. Kliknij ROZPOCZNIJ METADANE.

Usługa KitchenSink wysyła żądanie NAVIGATION focus, które nakazuje DirectRenderingClusterwyświetlenie w zestawie wskaźników makiety interfejsu.