語音輸入功能可讓你打造真正免持介面Glass 提供三種語音輸入功能。
主要語音指令會從首頁資訊卡啟動 Glassware,關聯語音指令可以在活動內執行動作,而系統的語音辨識活動則可讓您接收任意形式的語音輸入內容。
主要語音指令
這些語音指令可透過 Home 卡 (Clock 卡) 啟動 Glassware。當您宣告主要語音指令時,如果使用者決定輕觸主螢幕資訊卡來啟動 Glassware, Glass 就會自動建立觸控選單項目做為備用選項。
如何將語音指令新增到 ok Glass 語音主選單:
針對
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>
在 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>
為您的活動或服務宣告
android:icon
屬性。這可讓 Glass 在 ok, Glass 的觸控選單中顯示 Glassware 的圖示。<activity |service android:icon="@drawable/my_icon" ...> ... </activity | service>
如果您的語音指令使用語音提示並開始活動,請使用以下程式碼取得任何轉錄的文字 (例如
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 建立關聯語音指令,但使用者可以透過語音指令 (而非觸控) 叫用選單項目。
如要為特定活動啟用相關內容語音指令:
呼叫所需活動中的
getWindow().requestFeature(
WindowUtils.FEATURE_VOICE_COMMANDS
)
,以啟用內容語音指令。啟用這項功能後,只要這個活動收到焦點,畫面的頁尾區域就會顯示 "ok Glass" 選單。覆寫
onCreatePanelMenu()
並處理已啟用WindowUtils.FEATURE_VOICE_COMMANDS
的情況。啟用後,您可以在這裡進行一次性選單設定,例如加載選單資源或呼叫Menu.add()
方法來建立語音選單系統。覆寫
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>
(選用) 覆寫
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" />
使用不公開的主要語音指令
在
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>
在
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>
正在啟動語音辨識功能
語音辨識軟體會等候使用者說話,並在完成後傳回傳回的文字。如要開始活動:
- 使用
ACTION_RECOGNIZE_SPEECH
意圖呼叫startActivityForResult()
。啟動活動時,系統會支援以下意圖額外項目: 覆寫
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); }