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

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