應用程式開發

如要實作語音互動應用程式 (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 處於啟用狀態即可。例如啟動字詞偵測。
  • 回報支援的語音動作 (請參閱「語音助理輕觸朗讀」)。
  • 從螢幕鎖定畫面 (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() 是處理語音助理輕觸朗讀的必要條件。系統會使用 VoiceInteractionSessionService 建立 VoiceInteractionSession 並與之互動。它只有一項職責,就是應要求啟動新的工作階段。

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

最後,大部分工作都會在 VoiceInteractionSession 中完成。單一工作階段例項可能會重複使用,以完成多項使用者互動。在 Android Automotive OS 中,有一個 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 的說明文件。

實作設定/登入流程

設定和登入方式如下:

  • 在裝置開機期間 (設定精靈)。
  • 在語音互動服務切換期間 (「設定」)。
  • 首次啟動應用程式時。

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

更換語音服務時的設定

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

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

無論如何,VoiceInteractionService 可以透過多種方式鼓勵使用者完成設定:

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

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

通知提醒

通知提醒不會干擾使用者,可指出需要設定,並提供使用者前往助理設定流程的途徑。

通知提醒

圖 2. 通知提醒

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

通知提醒流程

圖 3. 通知提醒流程

語音回覆

這是最簡單的實作流程,在 VoiceInteractionSession#onShow() 回呼中啟動語音指令,向使用者說明需要執行的動作,然後詢問使用者 (如果 UX 限制狀態允許設定),是否要啟動設定流程。如果當時無法設定,也請說明情況。

首次使用時設定

使用者隨時可能觸發未正確設定的 VIA。在這種情況下:

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

建構語音互動設定畫面

設定和登入畫面應開發為一般活動。如需預先載入的 Assistant 使用者介面開發 UX 和視覺設計指南,請參閱這篇文章

一般指南:

  • VIA 應允許使用者隨時中斷及繼續設定。
  • 如果 UX_RESTRICTIONS_NO_SETUP 限制生效,則不應允許設定。詳情請參閱「駕駛人分心指南」。
  • 設定畫面應符合各車輛的設計系統。一般畫面版面配置、圖示、顏色和其他方面應與其餘 UI 一致。詳情請參閱「自訂」一節。

實作設定畫面

設定整合

圖 4. 設定整合

設定畫面是一般的 Android 活動。如果實作,必須在 VIA 資訊清單中,將進入點宣告為 res/xml/interaction_service.xml 的一部分 (請參閱「資訊清單」)。如果使用者尚未完成設定和登入程序,您可以在「設定」部分繼續進行,或視需要提供「登出」或「切換使用者」選項。與上述「設定」畫面類似,這些畫面應具備下列特點:

  • 提供返回螢幕堆疊中上一個畫面的選項 (例如返回車輛設定)。
  • 開車時不得使用。詳情請參閱「駕駛人分心指南」。
  • 請將各個車輛設計系統與相應的描述配對。詳情請參閱「自訂」。

在資訊清單檔案中宣告必要權限

VIA 要求的權限可分為三類:

  • 系統簽章權限。這些權限只會授予預先安裝的系統簽署 APK。使用者無法授予這些權限,只有原始設備製造商 (OEM) 可以在建構系統映像檔時授予這些權限。如要進一步瞭解如何取得簽章權限,請參閱「授予系統專屬權限」。
  • 危險權限。使用者必須透過 PermissionsController 對話方塊授予這些權限。原始設備製造商可以預先將部分權限授予預設的 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() 啟動 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 的處理作業委派給一般活動。使用這個選項時,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」。

偵測啟動字詞

Android 提供 DSP 層級的全時啟動字詞偵測器存取權,方法是透過 AlwaysOnHotwordDetector。以低 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 類別實作項目。系統中需要語音辨識的應用程式會使用 存取這項功能。如要進行語音辨識及存取麥克風,VIA 必須持有 android.permission.RECORD_AUDIO。存取 RecognitionService 實作項目的應用程式也應持有這項權限。

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

存取音訊輸出

當 VIA 準備好提供口頭回覆時,請務必遵守下列規範: