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.
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.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

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:
Na tej ilustracji kolory oznaczają:
- Żółty
CarServiceiCarNavigationStatusManagerudostępniane przez platformę Android. Więcej informacji znajdziesz w artykułach Car i CAR_NAVIGATION_SERVICE. - Cyjan
InstrumentClusterRendererServicezaimplementowana 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:
CarServiceinicjujeInstrumentClusterRenderingService.- Podczas inicjowania
InstrumentClusterRenderingServiceaktualizujeCarServiceza pomocą tych informacji:- 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).
- Opcje aktywności potrzebne do uruchamiania aktywności na wyświetlaczu klastra przyrządów. Więcej informacji znajdziesz w artykule ActivityOptions.
- Aplikacja nawigacyjna (np. Mapy Google na Androida Automotive lub dowolna aplikacja map
z wymaganymi uprawnieniami):
- Pobiera
CarAppFocusManagerza pomocą klasy Car z car-lib. - Przed rozpoczęciem wskazówek dojazdu wywołuje
CarAppFocusManager.requestFocus()aby przekazaćCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATIONjakoappTypeparametr.
- Pobiera
CarAppFocusManagerprzekazuje to żądanie doCarService. Jeśli żądanie zostanie przyznane,CarServicesprawdza pakiet aplikacji nawigacyjnej i znajduje aktywność oznaczoną kategoriąandroid.car.cluster.NAVIGATION.- Jeśli zostanie znaleziona, aplikacja nawigacyjna używa
ActivityOptionszgłoszonych przezInstrumentClusterRenderingServiceaby 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 zCarService:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
Implementowanie InstrumentClusterRenderingService
Aby utworzyć usługę:
- 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. - 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).
- Gdy wyświetlacz wskazany powyżej będzie gotowy, ta usługa musi wywołać
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()aby zdefiniować dokładneActivityOptionsktóre mają być używane do wyświetlania aktywności w klastrze przyrządów. Użyj tych parametrów:category.ClusterRenderingService.ActivityOptions.InstancjaActivityOptions, 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));
- 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:categoryClusterRenderingService.statePakiet wygenerowany za pomocą ClusterRenderingService. Podaj te dane:visibleOkreśla, że klaster przyrządów jest widoczny i gotowy do wyświetlania treści.unobscuredBoundsProstoką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.
- 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ę:
- 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.
- Podłącz fizyczny wyświetlacz dodatkowy do jednostki głównej (jeśli jest obsługiwany) lub włącz wirtualną
jednostkę główną dodatkową:
- W aplikacji Ustawienia wybierz Tryb programisty.
- Otwórz kolejno Ustawienia > System > Zaawansowane > Opcje programisty > Symuluj wyświetlacze dodatkowe.
- Uruchom ponownie jednostkę główną.
- Aby uruchomić aplikację KitchenSink:
- Otwórz szufladę.
- Otwórz Klaster przyrządów.
- 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.