На этой странице описано, как выполнять команды с помощью голосового взаимодействия.
Выполнить команды мультимедиа
Команды, связанные с мультимедиа, можно разделить на три группы:
- Внешние медиаисточники (например, Spotify, установленный в AAOS).
- Источники медиаконтента на стороне сервера (например, музыка, транслируемая через VIA).
- Местные средства массовой информации (например, автомобильное радио).
Обработка команд внешних источников мультимедиа
Внешние источники мультимедиа определяются как приложения Android, поддерживающие API MediaSessionCompat и MediaBrowseCompat (подробное объяснение использования этих API см. в разделе « Создание мультимедийных приложений для автомобилей »).
Важно: Для того чтобы приложение-помощник могло подключиться к службе MediaBrowseService всех установленных в системе медиаприложений, оно должно:
- Устанавливать с системной подписью (см. рекомендации по разработке медиаприложений для AAOS и пример кода
PackageValidator). - Удерживайте разрешение
android.permission.MEDIA_CONTENT_CONTROLс системными привилегиями (см. Предоставление разрешений с системными привилегиями ).
Помимо MediaBrowserCompat и MediaControllerCompat , AAOS предоставляет следующее:
-
CarMediaServiceпредоставляет централизованную информацию о текущем выбранном источнике мультимедиа. Он также используется для возобновления воспроизведения предыдущего источника мультимедиа после выключения и перезапуска автомобиля. -
car-media-commonпредоставляет удобные способы для отображения, подключения и взаимодействия с медиаприложениями.
Ниже приведены рекомендации, касающиеся реализации распространенных команд голосового взаимодействия.
Получить список установленных источников мультимедиа
Источники мультимедиа можно определить с помощью PackageManager , отфильтровав службы, соответствующие параметру MediaBrowserService.SERVICE_INTERFACE . В некоторых автомобилях могут быть реализованы специальные службы просмотра мультимедиа, которые следует исключить. Вот пример такой логики:
private Map<String, MediaSource> getAvailableMediaSources() { List<String> customMediaServices = Arrays.asList(mContext.getResources() .getStringArray(R.array.custom_media_packages)); List<ResolveInfo> mediaServices = mPackageManager.queryIntentServices( new Intent(MediaBrowserService.SERVICE_INTERFACE), PackageManager.GET_RESOLVED_FILTER); Map<String, MediaSource> result = new HashMap<>(); for (ResolveInfo info : mediaServices) { String packageName = info.serviceInfo.packageName; if (customMediaServices.contains(packageName)) { // Custom media sources should be ignored, as they might have a // specialized handling (e.g., radio). continue; } String className = info.serviceInfo.name; ComponentName componentName = new ComponentName(packageName, className); MediaSource source = MediaSource.create(mContext, componentName); result.put(source.getDisplayName().toString().toLowerCase(), source); } return result; }
Обратите внимание, что источники мультимедиа могут быть установлены или удалены в любое время. Для поддержания актуальности списка рекомендуется использовать экземпляр BroadcastReceiver для действий намерений ACTION_PACKAGE_ADDED , ACTION_PACKAGE_CHANGED , ACTION_PACKAGE_REPLACED и ACTION_PACKAGE_REMOVED .
Подключиться к воспроизводимому в данный момент медиаисточнику
CarMediaService предоставляет методы для получения информации о текущем выбранном источнике мультимедиа и об изменении этого источника. Изменения могут происходить, например, в результате прямого взаимодействия пользователя с пользовательским интерфейсом или использования аппаратных кнопок в автомобиле. С другой стороны, библиотека car-media-common предлагает удобные способы подключения к заданному источнику мультимедиа. Вот упрощенный фрагмент кода, демонстрирующий подключение к текущему выбранному медиаприложению:
public class MediaActuator implements MediaBrowserConnector.onConnectedBrowserChanged { private final Car mCar; private CarMediaManager mCarMediaManager; private MediaBrowserConnector mBrowserConnector; … public void initialize(Context context) { mCar = Car.createCar(context); mBrowserConnector = new MediaBrowserConnector(context, this); mCarMediaManager = (CarMediaManager) mCar.getCarManager(Car.CAR_MEDIA_SERVICE); mBrowserConnector.connectTo(mCarMediaManager.getMediaSource()); … } @Override public void onConnectedBrowserChanged( @Nullable MediaBrowserCompat browser) { // TODO: Handle connected/disconnected browser } … }
Управление воспроизведением текущего воспроизводимого медиафайла
При подключении MediaBrowserCompat легко отправлять команды управления воспроизведением целевому приложению. Вот упрощенный пример:
public class MediaActuator … { … private MediaControllerCompat mMediaController; @Override public void onConnectedBrowserChanged( @Nullable MediaBrowserCompat browser) { if (browser != null && browser.isConnected()) { mMediaController = new MediaControllerCompat(mContext, browser.getSessionToken()); } else { mMediaController = null; } } private boolean playSongOnCurrentSource(String song) { if (mMediaController == null) { // No source selected. return false; } MediaControllerCompat.TransportControls controls = mMediaController.getTransportControls(); PlaybackStateCompat state = controller.getPlaybackState(); if (state == null || ((state.getActions() & PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH) == 0)) { // Source can't play from search return false; } controls.playFromSearch(query, null); return true; } … }
Обработка команд выбора локального источника мультимедиа (радио, CD-проигрыватель, Bluetooth, USB).
Локальные медиаисточники предоставляют доступ к своим функциям системе, используя те же API MediaSession и MediaBrowse, описанные выше. Для учета особенностей каждого типа оборудования, службы MediaBrowse используют определенные соглашения для организации информации и команд управления медиафайлами.
Рукоятка радио
Сервис Radio MediaBrowseService можно идентифицировать по фильтру намерений ACTION_PLAY_BROADCASTRADIO . Предполагается, что он будет следовать элементам управления воспроизведением и структуре просмотра медиафайлов, описанным в разделе «Реализация радио» . AAOS предлагает библиотеку car-broadcastradio-support содержащую константы и методы, которые помогают производителям оборудования создавать реализации MediaBrowseService для своих собственных радиосервисов, соответствующих определенному протоколу, и обеспечивает поддержку приложений, использующих их дерево просмотра (например, VIA).
Поддержка дополнительного входа, CD-аудио и USB-носителей.
В стандартной реализации AOSP эти медиаисточники отсутствуют. Предлагаемый подход заключается в следующем:
- Предложите производителям автомобилей внедрить мультимедийные сервисы для каждого из них. Подробнее см. раздел «Создание мультимедийных приложений для автомобилей» .
- Эти реализации MediaBrowseService будут идентифицированы и обработаны в действиях намерений, определенных в разделе «Общие намерения воспроизведения» .
- Эти сервисы будут отображать дерево просмотра в соответствии с рекомендациями, описанными в разделе «Другие типы источников» .
Обработайте Bluetooth
Медиаконтент, передаваемый по Bluetooth, доступен через профиль Bluetooth AVRCP. Для упрощения доступа к этой функциональности AAOS включает в себя реализацию MediaBrowserService и MediaSession, которые абстрагируют детали связи (см. packages/apps/Bluetooth ).
Соответствующая древовидная структура медиабраузера определяется в классе BrowseTree . Команды управления воспроизведением могут передаваться аналогично любому другому приложению, используя его реализацию MediaSession.
Обработка команд потоковой передачи мультимедиа
Для реализации потоковой передачи мультимедиа на стороне сервера, VIA должен сам стать источником мультимедиа, реализовав API MediaBrowse и MediaSession. См. раздел «Создание мультимедийных приложений для автомобилей» . Реализация этих API позволит приложению голосового управления (среди прочего):
- Принимайте беспрепятственное участие в выборе источников информации.
- Автоматическое возобновление работы после перезапуска автомобиля
- Обеспечьте управление воспроизведением и просмотром контента с помощью пользовательского интерфейса Media Center.
- Принимать стандартные события нажатия кнопок аппаратного мультимедиа
Выполняйте команды навигации.
Единого стандартного способа взаимодействия со всеми навигационными приложениями не существует. Для интеграции с Google Maps см. Google Maps для Android Automotive Intents . Для интеграции с другими приложениями обратитесь напрямую к разработчикам приложения. Перед запуском интента в любое приложение (включая Google Maps) убедитесь, что интент может быть обработан (см. Google Maps Intents ). Это позволит уведомить пользователя, если целевое приложение недоступно.
Выполнять команды транспортного средства
Доступ к свойствам транспортного средства как для чтения, так и для записи обеспечивается через CarPropertyManager . Типы свойств транспортного средства, их реализация и другие детали описаны в разделе «Конфигурации свойств» . Для точного описания свойств, поддерживаемых Android, лучше всего обратиться непосредственно к hardware/interfaces/automotive/vehicle/2.0/types.hal . Определенное там перечисление VehicleProperty содержит как стандартные, так и специфичные для поставщика свойства, типы данных, режим изменения, единицы измерения и определение доступа на чтение/запись.
Для доступа к этим же константам из Java можно использовать VehiclePropertyIds и сопутствующие классы. Разные свойства имеют разные разрешения Android, контролирующие их доступ. Эти разрешения объявляются в манифесте CarService , а сопоставление между свойствами и разрешениями описывается в документации Javadoc для VehiclePropertyIds и обеспечивается в PropertyHalServiceIds .
Прочитайте характеристики транспортного средства
Ниже приведён пример, демонстрирующий способ измерения скорости автомобиля:
public class CarActuator ... { private final Car mCar; private final CarPropertyManager mCarPropertyManager; private final TextToSpeech mTTS; /** Global VHAL area id */ public static final int GLOBAL_AREA_ID = 0; public CarActuator(Context context, TextToSpeech tts) { mCar = Car.createCar(context); mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE); mTTS = tts; ... } @Nullable private void getSpeedInMetersPerSecond() { if (!mCarPropertyManager.isPropertyAvailable(VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID)) { mTTS.speak("I'm sorry, but I can't read the speed of this vehicle"); return; } // Data type and unit can be found in // automotive/vehicle/2.0/types.hal float speedInMps = mCarPropertyManager.getFloatProperty( VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID); int speedInMph = (int)(speedInMetersPerSecond * 2.23694f); mTTS.speak(String.format("Sure. Your current speed is %d miles " + "per hour", speedInUserUnit); } ... }
Задать свойства транспортного средства
Ниже приведён пример, показывающий, как включить и выключить передний кондиционер.
public class CarActuator … {
…
private void changeFrontAC(boolean turnOn) {
List<CarPropertyConfig> configs = mCarPropertyManager
.getPropertyList(new ArraySet<>(Arrays.asList(
VehiclePropertyIds.HVAC_AC_ON)));
if (configs == null || configs.size() != 1) {
mTTS.speak("I'm sorry, but I can't control the AC of your vehicle");
return;
}
// Find the front area Ids for the AC property.
int[] areaIds = configs.get(0).getAreaIds();
List<Integer> areasToChange = new ArrayList<>();
for (int areaId : areaIds) {
if ((areaId & (VehicleAreaSeat.SEAT_ROW_1_CENTER
| VehicleAreaSeat.SEAT_ROW_1_LEFT
| VehicleAreaSeat.SEAT_ROW_1_RIGHT)) == 0) {
continue;
}
boolean isACInAreaAlreadyOn = mCarPropertyManager
.getBooleanProperty(VehiclePropertyIds.HVAC_AC_ON, areaId);
if ((!isACInAreaAlreadyOn && turnOn) || (isACInAreaAlreadyOn && !turnOn)) {
areasToChange.add(areaId);
}
}
if (areasToChange.isEmpty()) {
mTTS.speak(String.format("The AC is already %s", turnOn ? "on" : "off"));
return;
}
for (int areaId : areasToChange) {
mCarPropertyManager.setBooleanProperty(
VehiclePropertyIds.HVAC_AC_ON, areaId, turnOn);
}
mTTS.speak(String.format("Okay, I'm turning your front AC %s",
turnOn ? "on" : "off"));
}
…
}Выполнять команды связи
Обработка команд обмена сообщениями
Устройства VIA должны обрабатывать входящие сообщения в соответствии с алгоритмом «нажатие для чтения», описанным в разделе «Голосовой помощник Tap-to-Read» , и при необходимости могут отправлять ответы отправителю входящего сообщения. Кроме того, устройства VIA могут использовать SmsManager (часть пакета android.telephony ) для составления и отправки SMS-сообщений непосредственно из автомобиля или через Bluetooth.
Обработка команд вызова
Аналогичным образом, VIAs могут использовать TelephonyManager для совершения телефонных звонков и звонков на номер голосовой почты пользователя. В этих случаях VIAs будут взаимодействовать с телефонной системой напрямую или с приложением Car Dialer. В любом случае, именно приложение Car Dialer должно отображать пользователю интерфейс, связанный с голосовыми вызовами.
Выполнить другие команды
Список других возможных точек интеграции между VIA и системой можно найти в списке известных интентов Android . Многие пользовательские команды могут обрабатываться на стороне сервера (например, чтение электронных писем и событий календаря пользователей) и не требуют никакого взаимодействия с системой, кроме самого голосового взаимодействия.
Иммерсивные действия (отображение визуального контента)
В тех случаях, когда это улучшает действия или понимание пользователя, VIA может предоставлять дополнительный визуальный контент на экране автомобиля. Чтобы свести к минимуму отвлечение водителя, такой контент должен быть простым, кратким и понятным. Подробную информацию о рекомендациях по пользовательскому интерфейсу и пользовательскому опыту в отношении иммерсивных действий см. в разделе «Предварительно загруженные помощники: рекомендации по пользовательскому опыту» .
Для обеспечения возможности индивидуальной настройки и согласованности с остальным дизайном головного устройства (ГУ) VIAs следует использовать компоненты библиотеки Car UI Library для большинства элементов пользовательского интерфейса. Подробнее см. раздел «Настройка» .