Используйте API-интерфейс Instrument Cluster (API Android) для отображения навигационных приложений, включая Карты Google, на дополнительном дисплее в автомобиле, например, за рулем на приборной панели. На этой странице описано, как создать службу для управления этим дополнительным дисплеем и интегрировать эту службу с CarService , чтобы навигационные приложения могли отображать пользовательский интерфейс.
Терминология
На этой странице используются следующие термины.
CarManager , который позволяет внешним приложениям запускать действие в кластере инструментов и получать обратные вызовы, когда кластер инструментов готов отображать действия.android:singleUser . В любой момент времени в системе Android работает не более одного экземпляра службы.Предварительные условия
Прежде чем продолжить, убедитесь, что у вас есть следующие элементы:
- Среда разработки Android. Чтобы настроить среду разработки Android, см. раздел Требования к сборке .
- Загрузите исходный код Android. Получите последнюю версию исходного кода Android из ветки pi-car-release (или более поздней версии) по адресу https://android.googlesource.com .
- Головное устройство (ГУ). Устройство Android, работающее под управлением Android 9 (или более поздней версии). Это устройство должно иметь собственный дисплей и иметь возможность прошивать дисплей новыми сборками Android.
-  Комбинация приборов является одной из следующих:- Физический дополнительный дисплей, подключенный к HU. Если аппаратное обеспечение и ядро устройства поддерживают управление несколькими дисплеями.
- Независимый блок. Любой вычислительный блок, подключенный к ГУ через сетевое соединение, способный принимать и отображать видеопоток на собственном дисплее.
-  Эмулируемый дисплей. Во время разработки вы можете использовать одну из этих эмулируемых сред:- Имитация вторичных дисплеев. Чтобы включить имитацию дополнительного дисплея в любом дистрибутиве AOSP Android, перейдите к настройкам «Параметры разработчика» в системном приложении «Настройки» и выберите «Имитировать дополнительные дисплеи». Эта конфигурация эквивалентна подключению физического вторичного дисплея с тем ограничением, что этот дисплей накладывается на основной дисплей.
- Эмулируемая комбинация приборов. Эмулятор Android, входящий в состав AAOS, предоставляет возможность отображать комбинацию приборов с помощью ClusterRenderingService .
 
 
Интеграционная архитектура
Компоненты интеграции
Любая интеграция API инструментального кластера состоит из этих трех компонентов:
-  CarService
- Навигационные приложения
- OEM-сервис кластера приборов

АвтоСервис
 CarService выступает посредником между навигационными приложениями и автомобилем, гарантируя, что в любой момент времени активно только одно навигационное приложение, и только приложения с разрешением android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL могут отправлять данные в автомобиль.
 CarService загружает все сервисы, специфичные для автомобиля, и обеспечивает доступ к этим сервисам через ряд менеджеров. Для взаимодействия со службами приложения, работающие в автомобиле, могут получить доступ к этим менеджерам.
Для реализации кластера приборов производители автомобильной техники должны создать собственную реализацию InstrumentClusterRendererService и обновить ClusterRenderingService .
 При рендеринге кластера инструментов во время процесса загрузки CarService считывает ключ InstrumentClusterRendererService ClusterRenderingService , чтобы найти реализацию InstrumentClusterService . В AOSP эта запись указывает на пример службы рендеринга реализации кластера API состояния навигации:
<string name="instrumentClusterRendererService"> android.car.cluster/.ClusterRenderingService </string>
 Служба, упомянутая в этой записи, инициализируется и привязывается к CarService . Когда навигационные приложения, такие как Google Maps, запрашивают CarInstrumentClusterManager , CarService предоставляет менеджер, который обновляет состояние Instrument Cluster из связанного InstrumentClusterRenderingService . (В данном случае «привязка» относится к службам Android .)
Сервис кластера приборов
OEM-производители должны создать пакет Android (APK), содержащий подкласс ClusterRenderingService .
Этот класс служит двум целям:
- Предоставляет интерфейс Android и устройство рендеринга комбинации приборов (цель этой страницы).
- Получает и отображает обновления состояния навигации, например пошаговые инструкции по навигации.
 Для первой цели OEM-реализации InstrumentClusterRendererService должны инициализировать вторичный дисплей, используемый для отображения информации на экранах в салоне автомобиля, и передать эту информацию CarService путем вызова методов InstrumentClusterRendererService.setClusterActivityOptions() и InstrumentClusterRendererService.setClusterActivityState() .
 Для второй функции служба кластера инструментов должна предоставить реализацию ClusterRenderingService. интерфейс, который получает события обновления статуса навигации, которые закодированы как eventType , и данные о событии, закодированные в пакете.
Последовательность интеграции
На следующей диаграмме показана реализация состояния навигации, отображающего обновления:
На этой иллюстрации цвета обозначают следующее:
-  Желтый. CarServiceиCarNavigationStatusManagerпредоставляемые платформой Android. Дополнительные сведения см. в разделе Автомобиль и CAR_NAVIGATION_SERVICE .
-  Голубой. InstrumentClusterRendererService, реализованный OEM.
- Фиолетовый. Приложение «Навигация», созданное Google и сторонними разработчиками.
-  Зеленый. CarAppFocusManager. Дополнительные сведения см. в разделах Использование API CarAppFocusManager ниже и CarAppFocusManager .
Информационный поток состояния навигации следует следующей последовательности:
-  CarServiceинициализируетInstrumentClusterRenderingService.
-  Во время инициализации InstrumentClusterRenderingServiceобновляетCarService:- Свойства отображения кластера инструментов, такие как неясные границы (более подробную информацию о неясных границах см. ниже).
- Параметры действий, необходимые для запуска действий на дисплее комбинации приборов. Дополнительные сведения см. в разделе ActivityOptions .
 
-  Навигационное приложение (например, Google Maps для Android Automotive или любое картографическое приложение с необходимыми разрешениями):-  Получает CarAppFocusManager, используя класс Car из car-lib.
-  Прежде чем начать пошаговые инструкции, вызывается CarAppFocusManager.requestFocus()для передачиCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATIONв качестве параметраappType.
 
-  Получает 
-  CarAppFocusManagerпередает этот запрос вCarService. Если предоставлено,CarServiceпроверяет пакет навигационного приложения и находит действие, отмеченное категориейandroid.car.cluster.NAVIGATION.
-  Если оно найдено, навигационное приложение использует ActivityOptions, сообщаемыеInstrumentClusterRenderingService, для запуска действия и включает свойства отображения кластера инструментов в качестве дополнительных элементов в намерении.
Интегрируйте API
 Реализация InstrumentClusterRenderingService должна:
-  Обозначьте его как одноэлементную службу, добавив следующее значение в AndroidManifest.xml. Это необходимо для того, чтобы гарантировать запуск единственной копии службы Instrument Cluster даже во время инициализации и переключения пользователей:
 android:singleUser="true"
-  Удерживайте системное разрешение BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. Это гарантирует, что только служба рендеринга Instrument Cluster, включенная в образ системы Android, будет привязана кCarService:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/> 
Реализация InstrumentClusterRenderingService
Чтобы создать сервис:
-  Напишите класс, наследуемый от ClusterRenderingService , а затем добавьте соответствующую запись в файл AndroidManifest.xml. Этот класс управляет отображением панели инструментов и может ( необязательно ) отображать данные API состояния навигации.
-  Во время onCreate()используйте эту службу для инициализации связи с оборудованием рендеринга. Опции включают в себя:- Определите дополнительный дисплей, который будет использоваться для комбинации приборов.
- Создайте виртуальный дисплей, чтобы приложение Instrument Cluster отображало и передавало визуализированное изображение на внешнее устройство (используя формат потокового видео, например H.264).
 
-  Когда указанное выше отображение будет готово, эта служба должна вызвать InstrumentClusterRenderingService#setClusterActivityLaunchOptions()чтобы определить точные параметрыActivityOptions, которые необходимо использовать для отображения действия в кластере инструментов. Используйте эти параметры:-  category.Служба кластерного рендеринга .
-  ActivityOptions.ЭкземплярActivityOptions, который можно использовать для запуска действия в кластере инструментов. Например, из примера реализации кластера инструментов на AOSP:getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
 
-  
-  Когда кластер инструментов готов отображать действия, эта служба должна вызвать InstrumentClusterRenderingService#setClusterActivityState(). Используйте эти параметры:-  categoryClusterRenderingService .
-  stateBundle, созданный с помощью ClusterRenderingService . Обязательно укажите данные:-  visibleУказывает комбинацию приборов как видимую и готовую к отображению содержимого.
-  unobscuredBoundsПрямоугольник, определяющий область на дисплее комбинации приборов, в которой безопасно отображать контент. Например, области, покрытые циферблатами и датчиками.
 
-  
 
-  
-  Переопределите метод Service#dump()и сообщите информацию о состоянии, полезную для отладки (дополнительную информацию см. в dumpsys ).
Пример реализации InstrumentClusterRenderingService
 В следующем примере описывается реализация InstrumentClusterRenderingService , которая создает VirtualDisplay для представления содержимого кластера инструментов на удаленном физическом дисплее.
 В качестве альтернативы этот код может передавать displayId физического вторичного дисплея, подключенного к HU, если известно, что он доступен.
/** * 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); } }
Используйте API CarAppFocusManager.
 API CarAppFocusManager предоставляет метод getAppTypeOwner() , который позволяет службе кластеров, написанной OEM-производителями, знать, какое навигационное приложение имеет фокус навигации в любой момент времени. OEM-производители могут использовать существующий метод CarAppFocusManager#addFocusListener() , а затем использовать getAppTypeOwner() чтобы узнать, какое приложение имеет фокус. Имея эту информацию, OEM-производители могут:
- Переключите действие, отображаемое в кластере, на действие кластера, предоставляемое навигационным приложением, удерживающим фокус.
- Может определить, имеет ли сфокусированное навигационное приложение активность кластера или нет. Если в целевом навигационном приложении нет активности кластера (или если такая активность отключена), OEM-производители могут отправить этот сигнал в автомобильный DIM, чтобы навигационный аспект кластера был полностью пропущен.
 Используйте CarAppFocusManager , чтобы устанавливать и прослушивать текущий фокус приложения, например активную навигацию или голосовую команду. Обычно в системе активно работает (или фокусируется) только один экземпляр такого приложения.
 Используйте метод 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 }
 Используйте метод CarAppFocusManager#getAppTypeOwner(..) для получения имен пакетов текущего владельца данного типа приложения, которое находится в фокусе. Этот метод может возвращать более одного имени пакета, если текущий владелец использует функцию 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 } ...
Приложение. Использование примера приложения
AOSP предоставляет пример приложения, реализующего API состояния навигации.
Чтобы запустить этот пример приложения:
- Сборка и прошивка Android Auto на поддерживаемом HU. Используйте инструкции по сборке и перепрошивке Android, специфичные для вашего устройства. Инструкции см. в разделе «Использование эталонных плат» .
-  Подключите дополнительный физический дисплей к HU (если поддерживается) или включите виртуальный вторичный HU:- Выберите режим разработчика в приложении «Настройки».
- Откройте «Настройки» > «Система» > «Дополнительно» > «Параметры разработчика» > «Имитировать дополнительные дисплеи» .
 
- Перезагрузите ГУ.
-  Чтобы запустить приложение KitchenSink:- Откройте ящик.
- Перейти в Инст. Кластер .
- Нажмите НАЧАТЬ МЕТАДАННЫЕ .
 
 KitchenSink запрашивает фокус NAVIGATION, который дает указание службе DirectRenderingCluster отобразить макет пользовательского интерфейса в кластере инструментов.
