Разработка приложения

Чтобы внедрить приложение голосового взаимодействия (VIA), выполните следующие действия:

  1. Создайте скелет VIA.
  2. ( необязательно ) Реализуйте процесс настройки/входа.
  3. ( необязательно ) Реализуйте экран настроек.
  4. Объявите необходимые разрешения в файле манифеста.
  5. Реализовать пользовательский интерфейс голосовой пластины.
  6. Реализовать распознавание голоса (должно включать реализацию RecognitionService API).
  7. Реализовать произнесение (опционально можно реализовать TextToSpeech API).
  8. Реализовать выполнение команд. См. этот контент в разделе «Выполнение команд» .

В следующих разделах описано, как выполнить каждый шаг, упомянутый выше.

Создание скелета VIA

Манифесты

Приложение определяется как приложение с голосовым взаимодействием, если в манифест включено следующее:

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myvoicecontrol">
    ...

  <application ... >
    <service android:name=".MyInteractionService"
        android:label="@string/app_name"
        android:permission="android.permission.BIND_VOICE_INTERACTION"
        android:process=":interactor">
      <meta-data
          android:name="android.voice_interaction"
          android:resource="@xml/interaction_service" />
      <intent-filter>
        <action android:name=
          "android.service.voice.VoiceInteractionService" />
      </intent-filter>
    </service>
  </application>
</manifest>

В этом примере:

  • VIA должны предоставить службу, которая расширяет VoiceInteractionService с фильтром намерений для действия VoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService") .
  • Эта служба должна иметь разрешение системной подписи BIND_VOICE_INTERACTION .
  • Эта служба должна включать файл метаданных android.voice_interaction , содержащий следующее:

    res/xml/interaction_service.xml

    <voice-interaction-service
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:sessionService=
          "com.example.MyInteractionSessionService"
        android:recognitionService=
          "com.example.MyRecognitionService"
        android:settingsActivity=
          "com.example.MySettingsActivity"
        android:supportsAssist="true"
        android:supportsLaunchVoiceAssistFromKeyguard="true"
        android:supportsLocalInteraction="true" />
    

Дополнительные сведения о каждом поле см. в разделе R.styleable#VoiceInteractionService . Учитывая, что все VIA также являются службами распознавания голоса, вы также должны включить в свой манифест следующее:

AndroidManifest.xml

<manifest ...>
  <uses-permission android:name="android.permission.RECORD_AUDIO"/>
  <application ...>
    ...
    <service android:name=".RecognitionService" ...>
      <intent-filter>
        <action android:name="android.speech.RecognitionService" />
        <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <meta-data
        android:name="android.speech"
        android:resource="@xml/recognition_service" />
    </service>
  </application>
</manifest>

Службам распознавания голоса также требуется следующая часть метаданных:

res/xml/recognition_service.xml

<recognition-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:settingsActivity="com.example.MyRecognizerSettingsActivity" />

VoiceInteractionService , VoiceInteractionSessionService и VoiceInteractionSession

На следующей диаграмме показан жизненный цикл каждого из этих объектов:

Жизненные циклы

Рисунок 1. Жизненные циклы

Как было сказано ранее, VoiceInteractionService является точкой входа в VIA. Основными обязанностями этой службы являются:

  • Инициализируйте все процессы, которые должны продолжать работать, пока этот VIA является активным. Например, обнаружение горячих слов.
  • Сообщает о поддерживаемых голосовых действиях (см. Voice Assistant Tap-to-Read ).
  • Запуск сеансов голосового взаимодействия с экрана блокировки (keyguard).

В простейшей форме реализация VoiceInteractionService будет выглядеть так:

public class MyVoiceInteractionService extends VoiceInteractionService {
    private static final List<String> SUPPORTED_VOICE_ACTIONS =
        Arrays.asList(
            CarVoiceInteractionSession.VOICE_ACTION_READ_NOTIFICATION,
            CarVoiceInteractionSession.VOICE_ACTION_REPLY_NOTIFICATION,
            CarVoiceInteractionSession.VOICE_ACTION_HANDLE_EXCEPTION
    );

    @Override
    public void onReady() {
        super.onReady();
        // TODO: Setup hotword detector
    }

    @NonNull
    @Override
    public Set<String> onGetSupportedVoiceActions(
            @NonNull Set<String> voiceActions) {
        Set<String> result = new HashSet<>(voiceActions);
        result.retainAll(SUPPORTED_VOICE_ACTIONS);
        return result;
    }
    ...
}

Реализация VoiceInteractionService#onGetSupportedVoiceActions() требуется для обработки голосового помощника Tap-to-Read . VoiceInteractionSessionService используется системой для создания VoiceInteractionSession и взаимодействия с ним. У него есть только одна обязанность — начинать новые сеансы по запросу.

public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService {
    @Override
    public VoiceInteractionSession onNewSession(Bundle args) {
        return new MyVoiceInteractionSession(this);
    }
}

Наконец, VoiceInteractionSession — это место, где будет выполняться большая часть работы. Один экземпляр сеанса можно повторно использовать для выполнения нескольких пользовательских взаимодействий. В AAOS существует вспомогательный CarVoiceInteractionSession , помогающий реализовать некоторые уникальные автомобильные функции.

public class MyVoiceInteractionSession extends CarVoiceInteractionSession {

    public InteractionSession(Context context) {
        super(context);
    }

    @Override
    protected void onShow(String action, Bundle args, int showFlags) {
        closeSystemDialogs();
        // TODO: Unhide UI and update UI state
        // TODO: Start processing audio input
    }
    ...
}

VoiceInteractionSession имеет большой набор методов обратного вызова, которые будут описаны в следующих разделах. полный список см. в документации по VoiceInterationSession .

Внедрение процесса настройки/входа

Настройка и вход могут происходить:

  • Во время подключения устройства (мастер установки).
  • При переключении сервисов голосового взаимодействия (Настройки).
  • При первом запуске при выборе приложения.

Дополнительные сведения о рекомендуемом взаимодействии с пользователем и визуальном руководстве см. в разделе Предварительно загруженные помощники: руководство по пользовательскому интерфейсу.

Настройка во время переключения голосовых услуг

Пользователь всегда может выбрать неправильно сконфигурированный VIA. Это может произойти, потому что:

  • Пользователь полностью пропустил мастер настройки или пользователь пропустил этап настройки голосового взаимодействия.
  • Пользователь выбрал VIA, отличный от того, который был настроен во время подключения устройства.

В любом случае у VoiceInteractionService есть несколько способов побудить пользователя завершить настройку:

  • Напоминание об уведомлении.
  • Автоматический голосовой ответ, когда пользователь пытается его использовать.

Примечание . Настоятельно не рекомендуется представлять процесс установки VIA без явного запроса пользователя. Это означает, что VIA должны избегать автоматического отображения контента на HU во время загрузки устройства или в результате переключения пользователя или разблокировки.

1. Напоминание об уведомлении

Напоминание об уведомлении — это ненавязчивый способ указать на необходимость настройки и предоставить пользователям возможность перейти к процессу настройки помощника.

Напоминание об уведомлении

Рисунок 2. Напоминание об уведомлении

Вот как будет работать этот поток:

Поток напоминаний об уведомлениях

Рис. 3. Поток уведомлений-напоминаний

Note . В зависимости от правил ограничения взаимодействия с пользователем (см. Рекомендации по отвлечению внимания водителя ) потоки настройки могут быть запрещены во время вождения. Когда пользователь нажимает на уведомление, а установка не разрешена, приложение должно использовать высказывание, чтобы объяснить пользователю ситуацию, а не пытаться отобразить пользовательский интерфейс, который будет немедленно заблокирован.

2. Голосовой ответ

Это простейший процесс для реализации, инициирующий высказывание в VoiceInteractionSession#onShow() , объясняя пользователю, что нужно сделать, а затем спрашивая его (если настройка разрешена с учетом состояния ограничения UX), хотят ли они инициировать поток настройки. Если в данный момент установка невозможна, объясните и эту ситуацию.

Настройка при первом использовании

Пользователь всегда может запустить VIA, который не был должным образом настроен. В таких случаях:

  1. Устно сообщите пользователю об этой ситуации (например, «Для правильной работы мне нужно, чтобы вы выполнили несколько шагов…»).
  2. Если механизм ограничений UX позволяет (см. UX_RESTRICTIONS_NO_SETUP ), спросите пользователя, хотят ли они начать процесс установки, а затем откройте экран настроек для VIA.
  3. В противном случае (например, если пользователь за рулем) оставьте уведомление для пользователя, чтобы он щелкнул параметр, когда это будет безопасно.

Создание экранов настройки голосового взаимодействия

Экраны настройки и входа в систему следует разрабатывать как регулярные действия . Ознакомьтесь с рекомендациями по пользовательскому интерфейсу и визуальным элементам для разработки пользовательского интерфейса в разделе Предварительно загруженные помощники: руководство по пользовательскому интерфейсу.

Общие рекомендации:

  • VIA должны позволять пользователям прерывать и возобновлять настройку в любое время.
  • Установка не должна быть разрешена, если действует ограничение UX_RESTRICTIONS_NO_SETUP . Дополнительные сведения см. в разделе «Рекомендации по отвлечению внимания водителя» .
  • Экраны настройки должны соответствовать системе проектирования для каждого транспортного средства. Общая компоновка экрана, значки, цвета и другие аспекты должны соответствовать остальному пользовательскому интерфейсу. Подробнее см. в разделе Настройка .

Реализовать экран настроек

Интеграция настроек

Рисунок 4. Интеграция настроек

Экраны настроек — это обычные действия Android. Если они реализованы, их точка входа должна быть объявлена ​​в res/xml/interaction_service.xml как часть манифестов VIA (см. Манифесты ). В разделе «Настройки» можно продолжить настройку и войти в систему (если пользователь не завершил ее) или предложить вариант выхода или смены пользователя , если это необходимо. Подобно экранам настройки, описанным выше, эти экраны должны:

  • Предоставьте возможность вернуться к предыдущему экрану в стеке экранов (например, к настройкам автомобиля).
  • Не допускать во время вождения. Дополнительные сведения см. в разделе «Рекомендации по отвлечению внимания водителя» .
  • Сопоставьте каждую систему проектирования транспортных средств. Подробнее см. в разделе Настройка .

Объявите необходимые разрешения в файле манифеста

Разрешения, требуемые VIA, можно разделить на три категории:

  • Разрешения системной подписи. Это разрешения, предоставляемые только предустановленным APK-файлам, подписанным системой. Пользователи не могут предоставлять эти разрешения, только OEM-производители могут предоставлять их при создании своих системных образов. Дополнительные сведения о получении разрешений на подпись см. в разделе Предоставление системных привилегированных разрешений .
  • Опасные разрешения. Это разрешения, которые пользователь должен предоставить с помощью диалогового окна PermissionsController. OEM-производители могут предварительно предоставить некоторые из этих разрешений службе VoiceInteractionService по умолчанию. Но учитывая, что это значение по умолчанию может меняться от устройства к устройству, приложения должны иметь возможность запрашивать эти разрешения при необходимости.
  • Другие разрешения. Это все остальные разрешения, которые не требуют вмешательства пользователя. Эти разрешения будут автоматически предоставлены системой.

Учитывая вышеизложенное, следующий раздел будет посвящен только запросу опасных разрешений. Разрешения следует запрашивать только тогда, когда пользователь находится на экранах входа или настроек.

Если у приложения нет разрешений, необходимых для работы, рекомендуется использовать голосовое высказывание, чтобы объяснить ситуацию пользователю, и уведомление, чтобы предоставить возможность, которую пользователь может использовать для возврата к экранам настроек VIA. . Подробности см. в разделе 1. Напоминание об уведомлении .

Запрос разрешений как часть экрана настроек

Опасные разрешения запрашиваются с помощью обычного метода ActivityCompat#requestPermission() (или эквивалентного). Дополнительные сведения о том, как запрашивать разрешения, см. в разделе Запрос разрешений для приложений .

Запросить разрешения

Рисунок 5. Запрос разрешений

Разрешение прослушивателя уведомлений

Чтобы реализовать поток TTR, VIA должны быть назначены прослушивателем уведомлений. Это не разрешение как таковое, а конфигурация, которая позволяет системе отправлять уведомления зарегистрированным слушателям. Чтобы узнать, получил ли VIA доступ к этой информации, приложения могут:

Если этот доступ не предоставлен заранее, VIA должен направить пользователя в раздел «Доступ к уведомлениям» в настройках автомобиля, используя комбинацию фраз и уведомлений. Следующий код можно использовать для открытия соответствующего раздела приложения настроек:

private void requestNotificationListenerAccess() {
    Intent intent = new Intent(Settings
        .ACTION_NOTIFICATION_LISTENER_SETTINGS);
    intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
    startActivity(intent);
}

Реализовать пользовательский интерфейс Voice Plate

Когда VoiceInteractionSession получает обратный вызов onShow() , он может представить пользовательский интерфейс голосовой пластины. Рекомендации по визуальному оформлению и пользовательскому интерфейсу по реализации голосовой пластины см. в разделе Предварительно загруженные помощники: руководство по пользовательскому интерфейсу.

Отображение голосовой пластины

Рисунок 6. Отображение голосовой таблички

Есть два варианта реализации этого пользовательского интерфейса:

  • Переопределить VoiceInteractionSession#onCreateContentView()
  • Запустите действие с помощью VoiceInteractionSession#startAssistantActivity()

Использование onCreateContentView()

Это способ представления голосовой пластины по умолчанию. Базовый класс VoiceInteractionSession создаст окно и будет управлять его жизненным циклом, пока активен голосовой сеанс. Приложения должны переопределять VoiceInteractionSession#onCreateContentView() и возвращать представление, которое будет присоединено к этому окну, как только сеанс будет создан. Изначально этот вид должен быть невидимым. Когда начинается голосовое взаимодействие, это представление должно стать видимым в VoiceInteractionSession#onShow() а затем снова стать невидимым в VoiceInteractionSession#onHide() .

public class MyVoiceInteractionSession extends CarVoiceInteractionSession {
    private View mVoicePlate;
    …

    @Override
    public View onCreateContentView() {
        mVoicePlate = inflater.inflate(R.layout.voice_plate, null);
        …
   }

    @Override
    protected void onShow(String action, Bundle args, int showFlags) {
        // TODO: Update UI state to "listening"
        mVoicePlate.setVisibility(View.VISIBLE);
    }

    @Override
    public void onHide() {
        mVoicePlate.setVisibility(View.GONE);
    }
    …
}

При использовании этого метода вы можете настроить VoiceInteractionSession#onComputeInsets() для учета скрытых областей вашего пользовательского интерфейса.

Использование startAssistantActivity()

В этом случае VoiceInteractionSession делегирует обработку пользовательского интерфейса голосовой пластины обычному действию. При использовании этого параметра реализация VoiceInteractionSession должна отключить создание своего окна содержимого по умолчанию (см. Использование onCreateContentView() ) при onPrepareShow() . В VoiceInteractionSession#onShow() сеанс запустит активность голосовой пластины с помощью VoiceInteractionSession#startAssistantActivity() . Этот метод инициирует пользовательский интерфейс с правильными настройками окна и флагами активности.

public class MyVoiceInteractionSession extends CarVoiceInteractionSession {
    …

    @Override
    public void onPrepareShow(Bundle args, int showFlags) {
        super.onPrepareShow(args, showFlags);
        setUiEnabled(false);
    }

    @Override
    protected void onShow(String action, Bundle args, int showFlags) {
        closeSystemDialogs();
        Intent intent = new Intent(getContext(), VoicePlateActivity.class);
        intent.putExtra(VoicePlateActivity.EXTRA_ACTION, action);
        intent.putExtra(VoicePlateActivity.EXTRA_ARGS, args);
        startAssistantActivity(intent);
    }

    …
}

Для поддержания связи между этим действием и VoiceInteractionSession может потребоваться набор внутренних намерений или привязка службы. Например, когда VoiceInteractionSession#onHide() , сеанс должен иметь возможность передать этот запрос действию.

Важный. В Automotive во время вождения могут отображаться только специально аннотированные действия или действия, перечисленные в «белом списке» UXR. Это также относится к действиям, запущенным с помощью VoiceInteractionSession#startAssistantActivity() . Не забудьте либо аннотировать свои действия с помощью <meta-data android:name="distractionOptimized" android:value="true"/> , либо включить это действие в ключ systemActivityWhitelist /packages/services/Car/service/res/values/config.xml файл /packages/services/Car/service/res/values/config.xml . Для получения дополнительной информации см. Руководство по отвлечению внимания водителя .

Реализовать распознавание голоса

В этом разделе вы узнаете, как реализовать распознавание голоса посредством обнаружения и распознавания горячих слов. Горячее слово — это триггерное слово, используемое для запуска нового запроса или действия голосом. Например, «Окей, Google» или «Привет, Google».

Обнаружение горячих слов DSP

Android предоставляет доступ к постоянно включенному детектору горячих слов на уровне DSP с помощью класса AlwaysOnHotwordDetector . Это обеспечивает удобный способ реализации обнаружения горячих слов с низкой загрузкой процессора. Использование этой функции разделено на две части:

  • Создание экземпляра AlwaysOnHotwordDetector .
  • Регистрация звуковой модели обнаружения горячих слов.

Реализация VoiceInteractionService может создать детектор горячих слов с помощью VoiceInteractionService#createAlwaysOnHotwordDetector() , передав ключевую фразу и языковой стандарт, которые они хотят использовать для обнаружения. В результате приложение получит обратный вызов onAvailabilityChanged() с одним из следующих возможных значений:

  • STATE_HARDWARE_UNAVAILABLE . Возможности DSP недоступны на устройстве. В этом случае будет использоваться программное обнаружение горячих слов.
  • STATE_HARDWARE_UNSUPPORTED . Поддержка DSP обычно недоступна, но DSP не поддерживает данное сочетание ключевой фразы и локали. Приложение может выбрать использование Software Hotword Detection .
  • STATE_HARDWARE_ENROLLED . Обнаружение горячих слов готово и может быть запущено вызовом startRecognition() .
  • STATE_HARDWARE_UNENROLLED . Звуковая модель для запрошенной ключевой фразы недоступна, но регистрация возможна.

Регистрация звуковых моделей обнаружения горячих слов может быть выполнена с помощью IVoiceInteractionManagerService#updateKeyphraseSoundModel() . В системе одновременно может быть зарегистрировано несколько моделей, но только одна модель будет связана с AlwaysOnHotwordDetector . Обнаружение горячих слов DSP может быть доступно не на всех устройствах. Разработчикам VIA следует проверять аппаратные возможности с помощью getDspModuleProperties() . Пример кода, показывающий, как зарегистрировать звуковые модели, см. в разделе VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java . См. Параллельный захват относительно одновременного распознавания горячих слов.

Программное обнаружение горячих слов

Как указано выше, обнаружение горячих слов DSP может быть доступно не на всех устройствах (например, эмулятор Android не поддерживает эмуляцию DSP). В этом случае единственной альтернативой является программное распознавание голоса. Чтобы не мешать другим приложениям, которым может потребоваться доступ к микрофону, VIA должны получить доступ к аудиовходу, используя:

Обе эти константы являются @hide и доступны только для связанных приложений.

Управление аудиовходом и распознаванием голоса

Аудиовход будет реализован с использованием MediaRecorder API . Для получения дополнительной информации о том, как использовать этот API, см. Обзор MediaRecorder . Ожидается, что службы голосового взаимодействия также будут реализациями RecognitionService . Любое приложение в системе, которому требуется распознавание голоса, будет использовать SpeechRecognizer API для доступа к этой возможности. Чтобы распознавать голос и иметь доступ к микрофону, VIA должны иметь android.permission.RECORD_AUDIO . Ожидается, что приложения, обращающиеся к реализации RecognitionService , также будут иметь это разрешение.

До Android 10 доступ к микрофону предоставлялся только одному приложению одновременно (за исключением обнаружения горячих слов, см. выше). Начиная с Android 10 доступ к микрофону может быть общим. Для получения дополнительной информации см. Совместное использование аудиовхода .

Доступ к аудиовыходу

Когда VIA будет готов предоставить устные ответы, важно следовать следующему набору рекомендаций: