应用开发

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

要实施语音交互应用程序 (VIA),您需要完成以下步骤:

  1. 创建一个 VIA 框架。
  2. 可选)实施设置/登录流程。
  3. 可选)实现设置屏幕。
  4. 在清单文件中声明所需的权限。
  5. 实现语音板 UI。
  6. 实现语音识别(必须包括 RecognitionService API 实现)。
  7. 实施话语(可选,您可以实施 TextToSpeech API)。
  8. 执行命令执行。在Fulfilling Commands中查看此内容。

以下部分描述了如何完成上述每个步骤。

创建一个 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 , VoiceInteractionSessionServiceVoiceInteractionSession

下图描述了每个实体的生命周期:

生命周期

图 1.生命周期

如前所述, VoiceInteractionService是 VIA 的入口点。该服务的主要职责是:

  • 只要此 VIA 处于活动状态,就应初始化任何应保持运行的进程。例如,热词检测。
  • 报告支持的语音操作(请参阅语音助手点击阅读)。
  • 从锁定屏幕(键盘锁)启动语音交互会话。

在其最简单的形式中,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()的实现需要处理语音助手点击阅读。系统使用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文档的完整列表。

实施设置/登录流程

可以进行设置和登录:

  • 在设备载入期间(设置向导)。
  • 在语音交互服务交换(设置)期间。
  • 在选择应用程序时首次启动。

有关推荐的用户体验和视觉指导的详细信息,请参阅预加载助手:UX 指导

语音服务交换期间的设置

用户总是有可能选择未正确配置的 VIA。这可能发生,因为:

  • 用户完全跳过了设置向导,或者用户跳过了语音交互配置步骤。
  • 用户选择的 VIA 与设备载入期间配置的 VIA 不同。

在任何情况下, VoiceInteractionService都有几种方法来鼓励用户完成设置:

  • 通知提醒。
  • 当用户尝试使用它时自动语音回复。

注意:强烈建议在没有明确用户请求的情况下提供 VIA 设置流程。这意味着 VIA 应避免在设备启动期间或由于用户切换或解锁而自动在 HU 上显示内容。

1.通知提醒

通知提醒是一种非侵入式方式,用于指示设置的需要,并为用户提供导航到助手设置流程的方式。

通知提醒

图 2.通知提醒

以下是此流程的工作原理:

通知提醒流程

图 3.通知提醒流程

Note :根据 UX 限制规则(请参阅驾驶员分心指南),驾驶时可能不允许设置流程。当用户点击通知并且不允许设置时,应用程序应该使用话语向用户解释情况,而不是试图显示将立即被阻止的 UI。

2.语音回复

这是最简单的实现流程,在VoiceInteractionSession#onShow()回调中发起一个话语,向用户解释需要做什么,然后询问他们(如果在 UX 限制状态下允许设置)他们是否想要发起设置流程。如果当时无法进行设置,也请说明这种情况。

首次使用时设置

用户总是有可能触发未正确配置的 VIA。在这种情况下:

  1. 口头告知用户这种情况(例如,“为了正常工作,我需要你完成几个步骤……”)。
  2. 如果 UX 限制引擎允许(请参阅UX_RESTRICTIONS_NO_SETUP ),请询问用户是否要开始设置过程,然后打开 VIA 的设置屏幕。
  3. 否则(例如,如果用户正在开车),留下一条通知,让用户在安全时点击该选项。

构建语音交互设置屏幕

设置和登录屏幕应作为常规活动进行开发。请参阅Preloaded Assistants: UX Guidance中 UI 开发的 UX 和视觉指南。

一般准则:

  • VIA 应允许用户随时中断和恢复设置。
  • 如果UX_RESTRICTIONS_NO_SETUP限制生效,则不应允许设置。有关详细信息,请参阅驾驶员分心指南
  • 设置屏幕应与每辆车的设计系统相匹配。总体屏幕布局、图标、颜色和其他方面应与 UI 的其余部分保持一致。有关详细信息,请参阅自定义

实施设置屏幕

设置集成

图 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);
}

实现语音板 UI

VoiceInteractionSession收到onShow()回调时,它可以呈现语音板 UI。有关语音板实现的视觉和 UX 指南,请参阅预加载助手:UX 指南

显示语音板

图 6.显示语音板

关于如何实现此 UI,有两个选项:

  • 覆盖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()以解决 UI 的模糊区域。

使用startAssistantActivity()

在这种情况下, VoiceInteractionSession会将语音板 UI 的处理委托给常规活动。使用此选项时, VoiceInteractionSession实现必须在onPrepareShow()回调中禁用其默认内容窗口的创建(请参阅使用 onCreateContentView() )。在VoiceInteractionSession#onShow()中,会话将使用VoiceInteractionSession#startAssistantActivity()启动语音板 Activity。此方法使用适当的窗口设置和活动标志启动 UI。

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之间的通信,可能需要一组内部 Intent 或服务绑定。例如,当调用VoiceInteractionSession#onHide()时,会话必须能够将此请求传递给活动。

重要的。在汽车中,驾驶时只能显示特别注释的活动或 UXR“白名单”中列出的活动。这也适用于以VoiceInteractionSession#startAssistantActivity()开始的活动。请记住使用<meta-data android:name="distractionOptimized" android:value="true"/>注释您的活动,或将此活动包含在/packages/services/Car/service/res/values/config.xmlsystemActivityWhitelist键中/packages/services/Car/service/res/values/config.xml文件。有关详细信息,请参阅驾驶员分心指南

实现语音识别

在本部分中,您将学习如何通过热词的检测和识别来实现语音识别。热词是用于通过语音启动新查询或操作的触发词。例如,“OK Google”或“Hey Google”。

DSP 热词检测

Android 通过AlwaysOnHotwordDetector类在 DSP 级别提供对始终在线的热词检测器的访问。这提供了一种以低 CPU 实现热词检测的便捷方法。该功能的使用分为两部分:

VoiceInteractionService 实现可以使用VoiceInteractionService#createAlwaysOnHotwordDetector()创建热词检测器,传递他们希望用于检测的关键短语和语言环境。因此,应用程序将收到一个带有以下可能值之一的onAvailabilityChanged()回调:

  • STATE_HARDWARE_UNAVAILABLE 。 DSP 功能在设备上不可用。在这种情况下,将使用软件热词检测。
  • STATE_HARDWARE_UNSUPPORTED 。 DSP 支持一般不可用,但 DSP 不支持给定的关键字和语言环境组合。该应用程序可以选择使用软件热词检测
  • 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 准备好提供口头答复时,遵循下一组准则非常重要: