Instrument Cluster API

Użyj interfejsu Instrument Cluster API (interfejsu API Androida), aby wyświetlać aplikacje nawigacyjne, 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 jak zintegrować ją z CarService, aby aplikacje nawigacyjne mogły wyświetlać interfejs użytkownika.

Terminologia

Na tej stronie używamy tych terminów.

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, które są implementowane 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 klastra przyrządów.
Miejsce docelowe
Ostateczne miejsce docelowe, do którego będzie prowadzić nawigacja w pojeździe.
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.
Klaster przyrządów
Dodatkowy wyświetlacz umieszczony za kierownicą i między przyrządami samochodowymi. Może to być niezależna jednostka obliczeniowa połączona z jednostką główną przez wewnętrzną sieć samochodu (CAN bus) lub dodatkowy wyświetlacz podłączony do jednostki głównej.
InstrumentClusterRenderingService
Klasa bazowa usługi używanej do komunikacji z wyświetlaczem klastra przyrządów. Producenci OEM muszą udostępnić rozszerzenie tej klasy, które będzie współpracować ze sprzętem specyficznym dla danego producenta.
Aplikacja KitchenSink
Aplikacja testowa dołączona do Androida Automotive.
Trasa
Określona ścieżka, którą pojazd podąża, aby dotrzeć do miejsca docelowego.
Usługa singleton
Usługa 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, upewnij się, że masz te elementy:

  • Środowisko programistyczne Androida. Aby skonfigurować środowisko programistyczne Androida, zapoznaj się z wymaganiami dotyczącymi kompilacji.
  • Pobierz kod źródłowy Androida. Najnowszą wersję kodu źródłowego Androida pobierz z gałęzi pi-car-release (lub nowszej) na stronie https://android.googlesource.com.
  • Jednostka główna (HU). Urządzenie z Androidem, na którym można uruchomić Androida 9 (lub nowszego). To urządzenie musi mieć własny wyświetlacz i możliwość flashowania wyświetlacza nowymi kompilacjami Androida.
  • Klaster przyrządów to jedna z tych opcji:
    • Fizyczny dodatkowy wyświetlacz podłączony do jednostki głównej. Jeśli sprzęt i jądro urządzenia obsługują zarządzanie wieloma wyświetlaczami.
    • Niezależna jednostka. Dowolna jednostka obliczeniowa połączona z jednostką główną przez połączenie sieciowe, która może odbierać i wyświetlać strumień wideo na własnym wyświetlaczu.
    • Emulowany wyświetlacz. Podczas programowania możesz używać jednego z tych emulowanych środowisk:
      • Symulowane wyświetlacze dodatkowe. Aby włączyć symulowany wyświetlacz dodatkowy w dowolnej dystrybucji Androida AOSP, otwórz Opcje programisty w aplikacji systemowej Ustawienia i wybierz Symuluj wyświetlacze dodatkowe . Ta konfiguracja jest równoważna z podłączeniem fizycznego wyświetlacza dodatkowego , z tym ograniczeniem, że ten wyświetlacz jest nałożony na wyświetlacz główny .
      • Emulowany klaster przyrządów. Emulator Androida dołączony do AAOS umożliwia wyświetlanie klastra przyrządów za pomocą ClusterRenderingService.

Architektura integracji

Komponenty integracji

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

  • CarService
  • Aplikacje nawigacyjne
  • Usługa klastra przyrządów OEM

Komponenty integracji

CarService

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

CarService uruchamia wszystkie usługi specyficzne dla samochodu i zapewnia do nich dostęp za pomocą serii 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 klastra przyrządó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 w ClusterRenderingService, aby znaleźć implementację 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 inicjowana i powiązana z CarService. Gdy aplikacje nawigacyjne, takie jak Mapy Google, poproszą o CarInstrumentClusterManager, CarService udostępnia menedżera, który aktualizuje stan klastra przyrządów na podstawie powiązanej usługi InstrumentClusterRenderingService. (W tym przypadku powiązany odnosi się do usług Androida).

Usługa klastra przyrządów

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

Ta klasa służy do 2 celów:

  • Udostępnia interfejs Androida i urządzenia renderującego klaster przyrządów (cel tej strony).
  • Odbiera i renderuje aktualizacje stanu nawigacji, takie jak wskazówki dojazdu.

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

W drugim przypadku usługa klastra przyrządów musi udostępniać implementację interfejsu ClusterRenderingService , która odbiera aktualizacje stanu nawigacji zdarzenia zakodowane jako eventType i dane zdarzenia zakodowane w pakiecie.

Sekwencja integracji

Ten diagram ilustruje implementację stanu nawigacji, która renderuje aktualizacje:

Sekwencja integracji

Na tej ilustracji kolory oznaczają:

  • Żółty CarService i CarNavigationStatusManager udostępniane przez platformę Android. Więcej informacji znajdziesz w artykułach Car i CAR_NAVIGATION_SERVICE.
  • Cyjan InstrumentClusterRendererService zaimplementowana przez producenta OEM.
  • Fioletowy Aplikacja nawigacyjna zaimplementowana 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ą tych informacji:
    1. Właściwości wyświetlacza klastra przyrządów, takie jak granice niezasłonięte (więcej informacji o granicach niezasłoniętych 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 nawigacyjna (np. Mapy Google na Androida Automotive lub dowolna aplikacja map z wymaganymi uprawnieniami):
    1. Pobiera CarAppFocusManager za pomocą klasy Car z car-lib.
    2. Przed rozpoczęciem wskazówek dojazdu wywołuje CarAppFocusManager.requestFocus() aby przekazać CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION jako appType parametr.
  4. CarAppFocusManager przekazuje to żądanie do CarService. Jeśli żądanie zostanie przyznane, CarService sprawdza pakiet aplikacji nawigacyjnej i znajduje aktywność oznaczoną kategorią android.car.cluster.NAVIGATION.
  5. Jeśli zostanie znaleziona, aplikacja nawigacyjna używa ActivityOptions zgłoszonych przez InstrumentClusterRenderingService aby uruchomić aktywność, i dołącza właściwości wyświetlacza klastra przyrządów jako dodatki w intencji.

Integracja z interfejsem API

Implementacja InstrumentClusterRenderingService musi:

  • Być oznaczona jako usługa singleton przez dodanie tej wartości do pliku AndroidManifest.xml. Jest to konieczne, aby zapewnić, że działa tylko 1 kopia usługi klastra przyrządów, nawet podczas inicjowania i przełączania użytkowników:
    android:singleUser="true"
  • Mieć uprawnienie systemowe BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. Gwarantuje to, że tylko usługa renderowania klastra przyrządów dołączona do obrazu systemu Android będzie kiedykolwiek powiązana z CarService:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

Implementowanie InstrumentClusterRenderingService

Aby utworzyć usługę:

  1. Napisz klasę, która rozszerza ClusterRenderingService a następnie dodaj odpowiedni wpis do pliku AndroidManifest.xml. Ta klasa steruje wyświetlaczem klastra przyrządów i może (opcjonalnie) renderować dane interfejsu Navigation State API data.
  2. Podczas onCreate() użyj tej usługi, aby zainicjować komunikację ze sprzętem renderującym. Dostępne opcje:
    • Określ dodatkowy wyświetlacz, który ma być używany w klastrze przyrządów.
    • Utwórz wyświetlacz wirtualny, aby aplikacja klastra przyrządów renderowała i przesyłała renderowany obraz do jednostki zewnętrznej (w formacie strumieniowania wideo, np. H.264).
  3. Gdy wyświetlacz wskazany powyżej będzie gotowy, ta usługa musi wywołać InstrumentClusterRenderingService#setClusterActivityLaunchOptions() aby zdefiniować dokładne ActivityOptions które mają być używane do wyświetlania aktywności w klastrze przyrządó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 z przykładowej implementacji klastra przyrządów w AOSP:
      getService().setClusterActivityLaunchOptions(
        CATEGORY_NAVIGATION,
        ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
  4. Gdy klaster przyrządów będzie gotowy do wyświetlania aktywności, ta usługa musi wywołać InstrumentClusterRenderingService#setClusterActivityState(). Użyj tych parametrów:
    • category ClusterRenderingService.
    • state Pakiet wygenerowany za pomocą ClusterRenderingService. Podaj te dane:
      • visible Określa, że klaster przyrządów jest widoczny i gotowy do wyświetlania treści.
      • unobscuredBounds Prostokąt, który określa obszar na wyświetlaczu klastra przyrządów, w którym można bezpiecznie wyświetlać treści. Na przykład obszary zasłonięte przez tarcze i wskaźniki.
  5. Zastąp metodę Service#dump() i zgłoś informacje o stanie przydatne do debugowania (więcej informacji znajdziesz w artykule dumpsys ).

Przykładowa implementacja InstrumentClusterRenderingService

Ten przykład przedstawia implementację InstrumentClusterRenderingService, która tworzy VirtualDisplay, aby wyświetlać treści klastra przyrządów na zdalnym wyświetlaczu fizycznym.

Ten kod może też przekazywać displayId fizycznego wyświetlacza dodatkowego podłączonego do jednostki głównej, 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ę getAppTypeOwner(), która umożliwia usłudze klastra napisanej przez producentów OEM sprawdzenie, która aplikacja nawigacyjna ma w danym momencie zaznaczenie nawigacji. Producenci OEM mogą używać dotychczasowej metody CarAppFocusManager#addFocusListener(), a następnie użyć getAppTypeOwner(), aby dowiedzieć się, która aplikacja ma fokus. Dzięki tym informacjom, producenci OEM mogą:

  • Przełączyć aktywność wyświetlaną w klastrze na aktywność klastra udostępnianą przez aplikację nawigacyjną która ma fokus.
  • Wykryć, czy aplikacja nawigacyjna z fokusem ma aktywność klastra. Jeśli aplikacja nawigacyjna z fokusem 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 nasłuchiwać bieżący fokus aplikacji, np. aktywną nawigację lub polecenie głosowe. Zwykle w systemie aktywnie działa (lub ma fokus) tylko 1 instancja takiej aplikacji.

Aby nasłuchiwać zmiany fokusu aplikacji, użyj metody CarAppFocusManager#addFocusListener(..):

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
}

Aby pobrać nazwy pakietów bieżącego właściciela danego typu aplikacji, która ma fokus, użyj metody CarAppFocusManager#getAppTypeOwner(..). Ta metoda może zwrócić więcej niż 1 nazwę pakietu, jeśli bieżący właściciel używa 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 nawigacyjnych opartych na szablonach, które korzystają z biblioteki aplikacji samochodowych, CarAppFocusManager#getAppTypeOwner() zwraca nazwę pakietu hosta (np. com.google.android.apps.automotive.templates.host), ponieważ host ma fokus systemu w imieniu aplikacji klienta.

Aby zidentyfikować aplikację klienta nawigującego, producenci OEM mogą wyodrębnić nazwę pakietu z pakietu stanu nawigacji wysłanego za pomocą 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 flashuj Androida Auto na obsługiwanej jednostce głównej. Postępuj zgodnie z instrukcjami kompilowania i flashowania Androida, które są specyficzne dla Twojego urządzenia. Instrukcje znajdziesz w artykule Korzystanie z płyt referencyjnych.
  2. Podłącz fizyczny wyświetlacz dodatkowy do jednostki głównej (jeśli jest obsługiwany) lub włącz wirtualną jednostkę główną dodatkową:
    1. W aplikacji Ustawienia wybierz Tryb programisty.
    2. Otwórz kolejno Ustawienia > System > Zaawansowane > Opcje programisty > Symuluj wyświetlacze dodatkowe.
  3. Uruchom ponownie jednostkę główną.
  4. Aby uruchomić aplikację KitchenSink:
    1. Otwórz szufladę.
    2. Otwórz Klaster przyrządów.
    3. Kliknij URUCHOM METADANE.

KitchenSink prosi o fokus NAWIGACJI, co powoduje, że usługa DirectRenderingCluster wyświetla w klastrze przyrządów symulowany interfejs użytkownika.