語音輸入

語音輸入功能可讓你打造真正免持介面Glass 提供三種語音輸入功能。

主要語音指令會從首頁資訊卡啟動 Glassware,關聯語音指令可以在活動內執行動作,而系統的語音辨識活動則可讓您接收任意形式的語音輸入內容。

主要語音指令

這些語音指令可透過 Home 卡 (Clock 卡) 啟動 Glassware。當您宣告主要語音指令時,如果使用者決定輕觸主螢幕資訊卡來啟動 Glassware, Glass 就會自動建立觸控選單項目做為備用選項。

如何將語音指令新增到 ok Glass 語音主選單:

  1. 針對 res/xml/<my_voice_trigger>.xml 中的語音指令建立 XML 資源,以使用 VoiceTriggers.Command 中定義的其中一個語音指令。 例如,以下是如何使用「開始跑步」的步驟。

    <?xml version="1.0" encoding="utf-8"?>
    <trigger command="START_A_RUN" />
    

    如要建立語音指令,提示使用者在啟動活動或服務之前說出其他詞組,請一併加入 input 元素。舉例來說,如果您使用「發布更新」,就可以這麼做。

    <?xml version="1.0" encoding="utf-8"?>
    <trigger command="POST_AN_UPDATE">
        <input prompt="@string/glass_voice_prompt" />
    </trigger>
    
  2. 在 Android 資訊清單中使用 com.google.android.glass.action.VOICE_TRIGGER 動作註冊意圖篩選器。如果意圖篩選器偵測到使用者說出您的語音指令,就會啟動您的活動或服務。

    <?xml version="1.0" encoding="utf-8"?>
    <application ...>
        <activity | service ...>
            <intent-filter>
                <action android:name=
                        "com.google.android.glass.action.VOICE_TRIGGER" />
            </intent-filter>
            <meta-data android:name="com.google.android.glass.VoiceTrigger"
                android:resource="@xml/my_voice_trigger" />
        </activity | service>
        // ...
    </application>
    
  3. 為您的活動或服務宣告 android:icon 屬性。這可讓 Glass 在 ok, Glass 的觸控選單中顯示 Glassware 的圖示。

    <activity |service
        android:icon="@drawable/my_icon" ...>
      ...
    </activity | service>
    
  4. 如果您的語音指令使用語音提示並開始活動,請使用以下程式碼取得任何轉錄的文字 (例如 onResume()):

    ArrayList<String> voiceResults = getIntent().getExtras()
            .getStringArrayList(RecognizerIntent.EXTRA_RESULTS);
    

    語音指令啟動服務時,onStartCommand() 回呼中會提供意圖額外項目:

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        ArrayList<String> voiceResults = intent.getExtras()
                .getStringArrayList(RecognizerIntent.EXTRA_RESULTS);
        // ...
    }
    

設定限制

如果您需要下列一或多項功能來啟動 Glassware,請在 res/xml/<my_voice_trigger>.xml 資源中指定這些功能。 如果裝置無法使用這些功能,Gboard 會停用語音指令:

  • camera
  • network
  • microphone

    <trigger command="POST_AN_UPDATE">
        <constraints
            camera="true"
            network="true" />
    </trigger>
    

內容比對語音指令

內容比對語音指令可讓使用者從活動執行動作。您可以使用標準 Android 選單 API 建立關聯語音指令,但使用者可以透過語音指令 (而非觸控) 叫用選單項目。

如要為特定活動啟用相關內容語音指令:

  1. 呼叫所需活動中的 getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS),以啟用內容語音指令。啟用這項功能後,只要這個活動收到焦點,畫面的頁尾區域就會顯示 "ok Glass" 選單。

  2. 覆寫 onCreatePanelMenu() 並處理已啟用 WindowUtils.FEATURE_VOICE_COMMANDS 的情況。啟用後,您可以在這裡進行一次性選單設定,例如加載選單資源或呼叫 Menu.add() 方法來建立語音選單系統。

  3. 覆寫 onMenuItemSelected() 即可在使用者說話時處理語音指令。使用者選取選單項目後,只要活動仍處於焦點,系統會在螢幕頁尾區段自動再次顯示 "ok, Glass" 語音指令,以接受新的語音指令。

    下列程式碼會啟用內容語音指令、在適當情況下加載選單資源,並在說話時處理語音指令:

    public class ContextualMenuActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle bundle) {
            super.onCreate(bundle);
    
            // Requests a voice menu on this activity. As for any other
            // window feature, be sure to request this before
            // setContentView() is called
            getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS);
            setContentView(R.layout.activity_main);
        }
    
        @Override
        public boolean onCreatePanelMenu(int featureId, Menu menu) {
            if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS) {
                getMenuInflater().inflate(R.menu.main, menu);
                return true;
            }
            // Pass through to super to setup touch menu.
            return super.onCreatePanelMenu(featureId, menu);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        @Override
        public boolean onMenuItemSelected(int featureId, MenuItem item) {
            if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS) {
                switch (item.getItemId()) {
                    case R.id.dogs_menu_item:
                        // handle top-level dogs menu item
                        break;
                    case R.id.cats_menu_item:
                        // handle top-level cats menu item
                        break;
                    case R.id.lab_menu_item:
                        // handle second-level labrador menu item
                        break;
                    case R.id.golden_menu_item:
                        // handle second-level golden menu item
                        break;
                    case R.id.calico_menu_item:
                        // handle second-level calico menu item
                        break;
                    case R.id.cheshire_menu_item:
                        // handle second-level cheshire menu item
                        break;
                    default:
                        return true;
                }
                return true;
            }
            // Good practice to pass through to super if not handled
            return super.onMenuItemSelected(featureId, item);
        }
    }
    

    以下是先前活動使用的選單資源範例。請注意,您可以為階層式語音選單系統建立巢狀選單項目。在下列範例中,第一個選單項目可存取:ok Glass, Show me dogs, Labrador

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Use the constants defined in the ContextualMenus.Command enum-->
        <item
            android:id="@+id/dogs_menu_item"
            android:title="@string/show_me_dogs">
            <menu>
                <item
                    android:id="@+id/lab_menu_item"
                    android:title="@string/labrador" />
                <item
                    android:id="@+id/golden_menu_item"
                    android:title="@string/golden" />
            </menu>
        </item>
        <item
            android:id="@+id/cats_menu_item"
            android:title="@string/show_me_cats">
            <menu>
                <item
                    android:id="@+id/cheshire_menu_item"
                    android:title="@string/cheshire" />
                <item
                    android:id="@+id/calico_menu_item"
                    android:title="@string/calico" />
            </menu>
        </item>
    </menu>
    
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Use the constants defined in the ContextualMenus.Command enum-->
        <item
            android:id="@+id/play_menu_item"
            android:title="PLAY_MUSIC" />
        <item
            android:id="@+id/pause_menu_item"
            android:title="PAUSE_MUSIC" />
    </menu>
    
  4. (選用) 覆寫 onPreparePanel(),檢查 WindowUtils.FEATURE_VOICE_COMMANDS 是否已啟用。啟用之後,即可利用其他邏輯來設定選單系統,例如根據某些條件新增及移除特定選單項目。您也可以根據某些條件將內容語音選單切換為開啟 (傳回 true) 並關閉 (傳回 false)。例如:

        private boolean mVoiceMenuEnabled;
        ...
        @Override
        public boolean onPreparePanel(int featureId, View view, Menu menu) {
            if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS) {
            // toggle this boolean on and off based on some criteria
                return mVoiceMenuEnabled;
            }
            // Good practice to call through to super for other cases
            return super.onPreparePanel(featureId, view, menu);
        }
    

同時支援語音和觸控選單

由於內容比對語音指令使用現有的 Android 選單 API,因此您可以重複使用許多現有的選單和資源,運用觸控選單,同時支援這兩種選單。

您只需查看 Window.FEATURE_OPTIONS_PANEL 功能,除了您已在一些方法中查找的 WindowUtils.FEATURE_VOICE_COMMANDS 功能之外,

例如,您可以變更先前的活動範例,以支援以下觸控選單 (變更變更):

// 1. Check for Window.FEATURE_OPTIONS_PANEL
// to inflate the same menu resource for touch menus.
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
    if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS ||
            featureId == Window.FEATURE_OPTIONS_PANEL) {
    ...
}

// 2. Check for Window.FEATURE_OPTIONS_PANEL
// to handle touch menu item selections.
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    if (featureId == WindowUtils.FEATURE_VOICE_COMMANDS ||
            featureId == Window.FEATURE_OPTIONS_PANEL) {
    ...
}

進行這些變更後,您可以輕觸或說出確定玻璃來顯示選單。

使用不公開的語音指令進行開發

如要發布 Glassware,您必須使用 VoiceTriggers.Command 中核准的主要語音指令,以及 ContextualMenus.Command 中核准的內容比對語音指令。

如要使用 GDK 不支援的語音指令,您可以在 AndroidManifest.xml 檔案中要求 Android 權限:

<uses-permission
     android:name="com.google.android.glass.permission.DEVELOPMENT" />

使用不公開的主要語音指令

  1. res/values/strings.xml 中宣告定義語音觸發條件名稱的字串值。啟動 Glassware 前,可選擇宣告語音提示來顯示語音辨識軟體。

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="glass_voice_trigger">read me a story</string>
        <string name="glass_voice_prompt">what story?</string>
    </resources>
    
  2. res/xml/<my_voice_trigger>.xml 中為語音觸發條件建立 XML 資源。如果是不公開的語音指令,則應使用 keyword 屬性,而不是用於核准的語音指令的 command 屬性。keyword 屬性應為定義語音指令的字串資源參照。簡易的語音觸發條件能夠立即啟動活動或服務,只要指定 trigger 元素即可:

    <?xml version="1.0" encoding="utf-8"?>
    <trigger keyword="@string/glass_voice_trigger" />
    

    若要建立語音觸發條件,提示使用者在啟動活動或服務之前說出其他詞組,請一併加入輸入元素:

    <?xml version="1.0" encoding="utf-8"?>
    <trigger keyword="@string/glass_voice_trigger">
        <input prompt="@string/glass_voice_prompt" />
    </trigger>
    

使用不公開的語音指令

建立選單項目時,請依據選單項目的標題使用任何文字。 例如:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Use the constants defined in the ContextualMenus.Command enum-->
    <item
        android:id="@+id/pizza_menu_item"
        android:title="@string/find_pizza" />
</menu>

正在啟動語音辨識功能


語音辨識軟體會等候使用者說話,並在完成後傳回傳回的文字。如要開始活動:

  1. 使用 ACTION_RECOGNIZE_SPEECH 意圖呼叫 startActivityForResult()。啟動活動時,系統會支援以下意圖額外項目:
  2. 覆寫 onActivityResult() 回呼,以便從 EXTRA_RESULTS 的意圖額外接收轉錄的文字。使用者完成說話時,系統會呼叫這個回呼。

    private static final int SPEECH_REQUEST = 0;
    
    private void displaySpeechRecognizer() {
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        startActivityForResult(intent, SPEECH_REQUEST);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode,
            Intent data) {
        if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
            List<String> results = data.getStringArrayListExtra(
                    RecognizerIntent.EXTRA_RESULTS);
            String spokenText = results.get(0);
            // Do something with spokenText.
        }
        super.onActivityResult(requestCode, resultCode, data);
    }