Android Automotive считает голосовую связь важнейшим компонентом безопасного взаимодействия при вождении и одним из самых безопасных способов взаимодействия пользователей с ОС Android Automotive во время вождения. В результате мы расширили API голосовых помощников Android (включая VoiceInteractionSession
), чтобы голосовые помощники могли выполнять для пользователей задачи, которые может быть сложно выполнить во время вождения.
Функция Tap-to-Read позволяет голосовым помощникам читать текстовые сообщения и отвечать на них от имени пользователя, когда пользователь взаимодействует с уведомлениями о сообщениях. Чтобы обеспечить эту функциональность, вы можете интегрировать голосового помощника с CarVoiceInteractionSession
.
В автомобильной промышленности уведомления, публикуемые в Центре уведомлений с именем INBOX
или INBOX_IN_GROUP
(например, SMS-сообщения), включают кнопку «Воспроизвести» . Пользователь может нажать «Воспроизвести» , чтобы выбранный голосовой помощник прочитал уведомление вслух и, при необходимости, ответил голосом.
Рисунок 1. Уведомление «Tap-to-Read» с кнопкой «Воспроизвести».
Интеграция с CarVoiceInteractionSession
В следующих разделах описывается, как интегрировать голосового помощника с CarVoiceInteractionSession
.
Поддержка голосового взаимодействия
Приложения, предоставляющие услуги голосового взаимодействия в автомобиле, должны интегрироваться с существующими голосовыми взаимодействиями Android. Чтобы узнать больше, см. Google Assistant для Android (за исключением VoiceInteractionSession
). Хотя все элементы API голосового взаимодействия остаются такими же, как реализованные на мобильных устройствах, CarVoiceInteractionSession
(описанный в разделе «Реализация CarVoiceInteractionSession ») заменяет VoiceInteractionSession
. Для получения дополнительной информации посетите эти страницы:
Реализация CarVoiceInteractionSession
CarVoiceInteractionSession
предоставляет API-интерфейсы, которые можно использовать, чтобы голосовые помощники могли читать текстовые сообщения вслух, а затем отвечать на эти сообщения от имени пользователя.
Ключевое различие между классами CarVoiceInteractionSession
и VoiceInteractionSession
заключается в том, что CarVoiceInteractionSession
передает действие в onShow
, поэтому голосовой помощник может определить контекст запроса пользователя, как только CarVoiceInteractionSession
запускает сеанс. Параметры onShow
для каждого класса перечислены в следующей таблице:
АвтомобильГолосовоеВзаимодействиеСессия | Сеанс голосового взаимодействия |
---|---|
onShow принимает эти три параметра:
| onShow принимает эти два параметра:
|
Изменения в Android 10
Начиная с Android 10, платформа вызывает VoiceInteractionService.onGetSupportedVoiceActions
чтобы определить, какие действия поддерживаются. Голосовой помощник переопределяет и реализует VoiceInteractionService.onGetSupportedVoiceActions
, как показано в следующем примере:
public class MyInteractionService extends VoiceInteractionService { private static final ListSUPPORTED_VOICE_ACTIONS = Arrays.asList( CarVoiceInteractionSession.VOICE_ACTION_READ_NOTIFICATION); @Override public Set onGetSupportedVoiceActions(@NonNull Set voiceActions) { Set result = new HashSet<>(voiceActions); result.retainAll(SUPPORTED_VOICE_ACTIONS); return result; } }
Допустимые действия описаны в следующей таблице. Подробную информацию о каждом действии см. в разделе Диаграммы последовательности .
Действие | Ожидаемая полезная нагрузка | Ожидаемое действие голосового взаимодействия |
---|---|---|
VOICE_ACTION_READ_NOTIFICATION | Прочитайте сообщения вслух пользователю, а затем активируйте ожидающее намерение «Отметить как прочитанное», когда сообщения будут прочитаны успешно. При необходимости запросите у пользователя ответ. | |
VOICE_ACTION_REPLY_NOTIFICATION | Возможна посылка с ключом.KEY_NOTIFICATION , который соответствует StatusBarNotification .Требуется android.permission.BIND_NOTIFICATION_LISTENER_SERVICE . | Предложите пользователю указать ответное сообщение, введите ответное сообщение в RemoteInputReply ожидающего намерения, а затем активируйте ожидающее намерение. |
VOICE_ACTION_HANDLE_EXCEPTION | Веревка с ключом.KEY_EXCEPTION , который сопоставляется с ExceptionValue (описанным в разделе «Значения исключений» ).KEY_FALLBACK_ASSISTANT_ENABLED , который соответствует логическому значению. Если значение равно true , резервный помощник, который может обработать запрос пользователя, отключен. | Ожидаемое действие, которое необходимо предпринять в отношении исключения, определено в документации по этому исключению. |
Значения исключений
EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
указывает голосовому помощнику, что ему не хватает разрешения Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE
и необходимо получить это разрешение от пользователя.
Запросить разрешение на прослушивание уведомлений
Если голосовой помощник по умолчанию не имеет разрешения на прослушивание уведомлений, FallbackAssistant
платформы (если он включен производителем автомобиля) может прочитать сообщение вслух до того, как голосовой помощник получит уведомление о запросе разрешения. Чтобы определить, включен ли FallbackAssistant
и прочитал ли сообщение, голосовой помощник должен проверить логическое значение KEY_FALLBACK_ASSISTANT_ENABLED
в полезных данных.
Платформа рекомендует голосовому помощнику добавить логику ограничения скорости для количества раз, когда запрашивается это разрешение. Это уважает пользователя, который не хочет предоставлять голосовому помощнику это разрешение и предпочитает, чтобы FallbackAssistant
читал текстовые сообщения вслух. Запрос у пользователя разрешения каждый раз, когда он нажимает «Воспроизвести» в уведомлении о сообщении, может быть негативным для пользователя. Платформа не накладывает ограничения на скорость голосового помощника.
При запросе разрешения на прослушивание уведомлений голосовой помощник должен использовать CarUxRestrictionsManager
, чтобы определить, припаркован ли пользователь или находится за рулем. Если пользователь за рулем, голосовой помощник отображает уведомление с инструкциями о том, как предоставить разрешение. Это помогает (и напоминает) пользователю предоставить разрешение, когда это безопаснее.
Работа с StatusBarNotification
StatusBarNotification
переданный вместе с голосовыми действиями «Чтение» и «Ответить», всегда присутствует в уведомлении о сообщениях, совместимом с автомобилем, как описано в разделе «Уведомление пользователей о сообщениях» . Хотя некоторые уведомления могут не иметь намерения «Ожидание ответа», все они имеют ожидающее намерение «Отметить как прочитанное».
Чтобы упростить взаимодействие с уведомлениями, используйте NotificationPayloadHandler
, который предоставляет методы для извлечения сообщений из уведомления и записи ответных сообщений в соответствующее ожидающее намерение уведомления. После того как голосовой помощник прочитает сообщение, он должен активировать намерение «Отметить как прочитанное».
Соблюдение предварительных условий для чтения по касанию
Только VoiceInteractionSession
голосового помощника по умолчанию уведомляется, когда пользователь запускает голосовое действие для чтения сообщений и ответа на них. Как упоминалось выше, этот голосовой помощник по умолчанию также должен иметь разрешение на прослушивание уведомлений.
Диаграммы последовательности
На этих рисунках показаны логические потоки CarVoiceInteractionSession actions
:
Рисунок 2. Диаграмма последовательности для VOICE_ACTION_READ_NOTIFICATION.
В случае с Рисунком 3 рекомендуется применять ограничения скорости запросов на разрешения:
Рисунок 3. Диаграмма последовательности для VOICE_ACTION_REPLY_NOTIFICATION.
Рисунок 4. Диаграмма последовательности для VOICE_ACTION_HANDLE_EXCEPTION.
Прочитать название приложения
Если вы хотите, чтобы ваш голосовой помощник читал вслух имя приложения для обмена сообщениями во время чтения сообщения (например, «Сэм из Hangouts сказал...»), создайте функцию, подобную той, что показана в следующем примере кода, чтобы гарантировать, что помощник читает сообщение. правильное имя:
@Nullable String getMessageApplicationName(Context context, StatusBarNotification statusBarNotification) { ApplicationInfo info = getApplicationInfo(context, statusBarNotification.getPackageName()); if (info == null) return null; Notification notification = statusBarNotification.getNotification(); // Sometimes system packages will post on behalf of other apps, so check this // field for a system app notification. if (isSystemApp(info) && notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) { return notification.extras.getString(Notification.EXTRA_SUBSTITUTE_APP_NAME); } else { PackageManager pm = context.getPackageManager(); return String.valueOf(pm.getApplicationLabel(info)); } } @Nullable ApplicationInfo getApplicationInfo(Context context, String packageName) { final PackageManager pm = context.getPackageManager(); ApplicationInfo info; try { info = pm.getApplicationInfo(packageName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } return info; } boolean isSystemApp(ApplicationInfo info) { return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; }