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

Автосервис
 CarService посредником между навигационными приложениями и автомобилем, гарантируя, что только одно навигационное приложение активно в любой момент времени, и только приложения с разрешением android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL могут отправлять данные в автомобиль.
 CarService загружает все сервисы для конкретных автомобилей и предоставляет доступ к этим сервисам через ряд менеджеров. Для взаимодействия со службами запущенные в автомобиле приложения могут обращаться к этим менеджерам.
 Для реализации кластера приборов OEM-производители автомобилей должны создать пользовательскую реализацию InstrumentClusterRendererService и обновить файл config.xml , чтобы он указывал на эту настроенную реализацию.
 При рендеринге Instrument Cluster в процессе загрузки CarService считывает ключ InstrumentClusterRendererService config.xml , чтобы найти реализацию InstrumentClusterService . В AOSP эта запись указывает на службу рендеринга реализации примера API состояния навигации:
<string name="instrumentClusterRendererService"> android.car.cluster/.ClusterRenderingService </string>
 Служба, упомянутая в этой записи, инициализирована и привязана к CarService . Когда навигационные приложения, такие как Google Maps, запрашивают CarInstrumentClusterManager , CarService предоставляет диспетчер, который обновляет состояние кластера инструментов из связанного InstrumentClusterRenderingService . (В данном случае привязка относится к службам Android .)
Служба комбинации приборов
 OEM-производители должны создать пакет Android (APK), содержащий подкласс InstrumentClusterRendererService . См. ClusterRenderingService для примера.
Этот класс служит двум целям:
- Предоставляет интерфейс Android и устройство рендеринга комбинации приборов (цель этой страницы).
- Получает и отображает обновления состояния навигации, например пошаговые инструкции по навигации.
 Во-первых, OEM-реализации InstrumentClusterRendererService должны инициализировать дополнительный дисплей, используемый для отображения информации на экранах в салоне автомобиля, и передавать эту информацию в CarService , вызывая методы InstrumentClusterRendererService.setClusterActivityOptions() и InstrumentClusterRendererService.setClusterActivityState() .
 Для второй функции служба Instrument Cluster должна предоставить реализацию интерфейса NavigationRenderer , который получает события обновления состояния навигации, которые кодируются как eventType события, и данные события кодируются в пакете.
Последовательность интеграции
На следующей диаграмме показана реализация состояния навигации, отображающего обновления:
На этой иллюстрации цвета обозначают следующее:
-  Желтый. CarServiceиCarNavigationStatusManager, предоставляемые платформой Android.
-  Голубой. InstrumentClusterRendererService, реализованный OEM.
- Пурпурный. Навигационное приложение реализовано Google и сторонними разработчиками.
-  Зеленый. 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. Это необходимо для того, чтобы единая копия службы кластера приборов работала даже во время инициализации и переключения пользователей:
 android:singleUser="true"
-  Удерживайте системное разрешение BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. Это гарантирует, что только сервис рендеринга кластера приборов, включенный как часть образа системы Android, когда-либо будет привязан кCarService:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/> 
Реализация InstrumentClusterRenderingService
Чтобы построить сервис:
-  Напишите класс, который наследуется от InstrumentClusterRenderingService, а затем добавьте соответствующую запись в файлAndroidManifest.xml. Этот класс управляет отображением приборной панели и может ( необязательно ) отображать данные API состояния навигации.
-  Во время onCreate()используйте эту службу для инициализации связи с оборудованием для рендеринга. Варианты включают:- Определите дополнительный дисплей, который будет использоваться для комбинации приборов.
- Создайте виртуальный дисплей, чтобы приложение Instrument Cluster визуализировало и передало визуализированное изображение на внешнее устройство (используя формат потокового видео, например H.264).
 
-  Когда отображение, указанное выше, готово, эта служба должна вызвать InstrumentClusterRenderingService#setClusterActivityLaunchOptions(), чтобы определить точные параметрыActivityOptions, которые должны использоваться для отображения действия в кластере инструментов. Используйте эти параметры:- категория. CarInstrumentClusterManager#CATEGORY_NAVIGATION
-  ActivityOptions.ЭкземплярActivityOptions, который можно использовать для запуска действия в кластере инструментов. Например, из примера реализации кластера инструментов на AOSP:getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
 
-  Когда кластер инструментов готов отображать действия, эта служба должна вызвать InstrumentClusterRenderingService#setClusterActivityState(). Используйте эти параметры:-  categoryCarInstrumentClusterManager#CATEGORY_NAVIGATION
-  stateBundle, сгенерированный с помощью ClusterActivityState . Обязательно укажите следующие данные:-  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 that will 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 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 application 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 (если поддерживается) или включите виртуальный дополнительный дисплей:- Выберите « Режим разработчика» в приложении «Настройки».
- Выберите « Настройки» > «Система» > «Дополнительно» > «Параметры разработчика» > «Имитировать дополнительные дисплеи» .
 
- Перезагрузите ГУ. Служба ClusterRenderingService подключена к дополнительному дисплею.
-  Чтобы запустить приложение KitchenSink:- Откройте ящик.
- Перейти в Инст. Кластер .
- Нажмите НАЧАТЬ МЕТАДАННЫЕ .
 
 KitchenSink запрашивает фокус NAVIGATION, который дает указание службе DirectRenderingCluster отобразить макет пользовательского интерфейса в кластере инструментов.
