應用程式開發

如要實作語音互動應用程式 (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" />

VoiceInteractionService、VoiceInteractionSessionService 和 VoiceInteractionSession

下圖顯示這些實體的生命週期:

Lifecycles

圖 1. Lifecycles

如先前所述,VoiceInteractionService 是 VIA 的進入點。這項服務的主要職責如下:

  • 初始化任何程序,只要此 VIA 是有效的,就應持續執行。例如啟動字詞偵測。
  • 回報支援的語音指令 (請參閱「Google 助理輕觸朗讀」)。
  • 從螢幕鎖定畫面 (鎖定畫面) 啟動語音互動工作階段。

以最簡單的形式來說,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(),才能處理 Google 助理輕觸朗讀功能。系統會使用 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 提供大量回呼方法,這些方法會在後續章節中說明。如需 VoiceInteractionSession 的完整清單,請參閱說明文件。

實作設定/登入流程

設定和登入作業可在以下情況發生:

  • 在裝置加入期間 (設定精靈)。
  • 在語音互動服務切換期間 (設定)。
  • 選取應用程式後,首次啟動時。

如需建議的使用者體驗和視覺指南詳細資訊,請參閱「預先載入的助理:使用者體驗指南」。

在語音服務切換期間設定

使用者隨時可以選取未正確設定的 VIA。可能的原因如下:

  • 使用者完全略過設定精靈,或略過語音互動設定步驟。
  • 使用者選取的 VIA 與裝置新手上路期間設定的不同。

無論如何,VoiceInteractionService 有幾種方式可鼓勵使用者完成設定:

  • 通知提醒。
  • 使用者嘗試使用時,自動回覆語音。

注意:強烈建議您不要在沒有明確使用者要求的情況下,顯示 VIA 設定流程。也就是說,VIA 應避免在裝置啟動期間,或在使用者切換或解鎖時,自動在車用多媒體系統上顯示內容。

通知提醒

通知提醒是一種不具侵入性的方式,可用來指出設定需求,並為使用者提供導覽至 Google 助理設定流程的操作元素。

通知提醒

圖 2. 通知提醒

這個流程的運作方式如下:

通知提醒流程

圖 3. 通知提醒流程

語音回覆

這是最簡單的實作流程,可在 VoiceInteractionSession#onShow() 回呼上啟動語音,向使用者說明需要採取的步驟,然後詢問使用者是否要啟動設定流程 (如果允許設定,則會顯示使用者體驗限制狀態)。如果無法在當下完成設定,也請說明這個情況。

首次使用時設定

使用者一律可以觸發未正確設定的 VIA。在這種情況下:

  1. 口頭告知使用者這個情況 (例如:「為了讓系統正常運作,請完成幾個步驟……」)。
  2. 如果使用者體驗限制引擎允許 (請參閱 UX_RESTRICTIONS_NO_SETUP),請詢問使用者是否要開始設定程序,然後開啟 VIA 的「設定」畫面。
  3. 否則 (例如使用者正在開車),請留下通知,讓使用者在安全無虞的情況下點選該選項。

建構語音互動設定畫面

設定和登入畫面應以一般活動的形式開發。請參閱預先載入的助理:使用者體驗指南,瞭解使用者介面開發作業的使用者體驗和視覺指南。

一般規範:

  • 使用者應可隨時中斷及恢復設定。
  • 如果 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。如需語音板導入作業的視覺和使用者體驗指南,請參閱「預先載入的 Google 助理:使用者體驗指南」。

顯示語音板

圖 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() 啟動語音板活動。這個方法會使用適當的視窗設定和活動旗標啟動 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() 時,工作階段必須能夠將這項要求傳遞至活動。

重要事項:在 Automotive 中,只有特別註解的活動或 UXR「許可清單」中列出的活動,才能在行車時顯示。這也適用於以 VoiceInteractionSession#startAssistantActivity() 啟動的活動。請記得使用 <meta-data android:name="distractionOptimized" android:value="true"/> 為活動加上註解,或是在 /packages/services/Car/service/res/values/config.xml 檔案的 systemActivityWhitelist 鍵中加入此活動。詳情請參閱「駕駛人分心行為指南」。

實作語音辨識

在本節中,您將瞭解如何透過熱字詞的偵測和辨識功能,實作語音辨識功能。熱字詞是用來透過語音啟動新查詢或動作的觸發字詞。例如「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,請參閱「MediaRecorder 總覽」。語音互動服務也應為 RecognitionService 類別的實作項目。系統中任何需要語音辨識功能的應用程式,都會使用這個 API 存取這項功能。如要進行語音辨識並存取麥克風,VIA 必須持有 android.permission.RECORD_AUDIO。存取 RecognitionService 實作項目的應用程式也應具備這項權限。

在 Android 10 之前,麥克風存取權一次只會授予一個應用程式 (除了熱字詞偵測,請參閱上文)。從 Android 10 開始,麥克風存取權可共用。詳情請參閱「共用音訊輸入」。

存取音訊輸出

當 VIA 準備好提供口頭回應時,請務必遵循下列指南: