應用程序開發

要實現語音交互應用程序 (VIA),您需要完成以下步驟:

  1. 創建一個 VIA 骨架。
  2. 可選)實施設置/登錄流程。
  3. 可選)實施設置屏幕。
  4. 在清單文件中聲明所需的權限。
  5. 實現語音板 UI。
  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" />

VoiceInteractionServiceVoiceInteractionSessionServiceVoiceInteractionSession

下圖描述了每個實體的生命週期:

生命週期

圖 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()的實現是處理Voice Assistant 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的文檔完整列表。

實施設置/登錄流程

可以進行設置和登錄:

  • 在設備載入期間(設置嚮導)。
  • 在語音交互服務交換期間(設置)。
  • 首次啟動時選擇應用程序。

有關推薦的用戶體驗和視覺指導的詳細信息,請參閱預加載助手:UX 指導

語音業務交換期間的設置

用戶始終可以選擇未正確配置的 VIA。這可能是因為:

  • 用戶完全跳過了設置嚮導或用戶跳過了語音交互配置步驟。
  • 用戶選擇的 VIA 與設備載入期間配置的 VIA 不同。

無論如何, VoiceInteractionService有幾種方法可以鼓勵用戶完成設置:

  • 通知提醒。
  • 用戶嘗試使用時自動語音回复。

注意:強烈建議不要在沒有明確用戶請求的情況下提供 VIA 設置流程。這意味著 VIA 應避免在設備啟動期間或由於用戶切換或解鎖而在 HU 上自動顯示內容。

1. 通知提醒

通知提醒是一種非侵入式的方式來指示設置的需要,並為用戶提供導航到助手設置流程的提示。

通知提醒

圖 2.通知提醒

以下是此流程的工作方式:

通知提醒流程

圖 3.通知提醒流程

Note :根據用戶體驗限制規則(請參閱駕駛員分心指南),駕駛時可能不允許設置流程。當用戶單擊通知並且不允許設置時,應用程序應該使用話語向用戶解釋情況,而不是嘗試顯示將立即被阻止的 UI。

2.語音回复

這是最簡單的實現流程,在VoiceInteractionSession#onShow()回調上啟動話語,向用戶解釋需要做什麼,然後詢問他們(如果在 UX Restriction 狀態下允許設置)他們是否想要啟動設置流程。如果當時無法設置,也請說明這種情況。

首次使用時設置

用戶總是有可能觸發未正確配置的 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()啟動 Activity

使用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 的處理委託給常規 Activity。使用此選項時, VoiceInteractionSession實現必須在onPrepareShow()回調中禁用其默認內容窗口的創建(請參閱使用 onCreateContentView() )。在VoiceInteractionSession#onShow() ,會話將使用VoiceInteractionSession#startAssistantActivity()啟動語音板活動。此方法使用正確的 Window 設置和 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 啟動指令檢測可能不適用於所有設備。威盛開發人員應使用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 準備好提供口頭答复時,請務必遵循下一組準則: