Голосовой ввод

Голосовой ввод позволяет создать по-настоящему громкий интерфейс. Glass предлагает три способа использования голосового ввода.

Основные голосовые команды запускают Glassware с домашней карты, контекстные голосовые команды могут выполнять действия в рамках действия, а действие системы распознавания речи позволяет получать голосовой ввод в произвольной форме от пользователей.

Основные голосовые команды

Эти голосовые команды запускают Glassware с домашней карты (карты часов). Когда вы объявляете основную голосовую команду, Glass автоматически создает элемент сенсорного меню в качестве запасного варианта, если пользователи решат запустить ваш Glassware, нажав на карточку «Домой».

Чтобы добавить голосовую команду в главное меню ok glass voice:

  1. Создайте ресурс XML для голосовой команды в res/xml/<my_voice_trigger>.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. Зарегистрируйте фильтр намерений с помощью действия com.google.android.glass.action.VOICE_TRIGGER в манифесте Android. Фильтр намерений запускает вашу деятельность или службу, если обнаруживает, что пользователи произносят вашу голосовую команду.

    <?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 Touch.

    <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 . Если функции недоступны, Glass отключает голосовую команду:

  • camera
  • network
  • microphone

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

Контекстные голосовые команды

Контекстные голосовые команды позволяют пользователям выполнять действия из действий. Вы создаете контекстные голосовые команды с помощью стандартных API меню Android, но пользователи могут вызывать пункты меню с помощью голосовых команд, а не касания.

Чтобы включить контекстные голосовые команды для определенного действия:

  1. Вызовите getWindow().requestFeature( WindowUtils.FEATURE_VOICE_COMMANDS ) в нужном действии, чтобы включить контекстные голосовые команды. Если эта функция включена, меню «ok glass» появляется в нижней части экрана всякий раз, когда это действие получает фокус.

  2. Переопределите onCreatePanelMenu() и обработайте случай, когда WindowUtils.FEATURE_VOICE_COMMANDS включен. Если включено, здесь вы выполняете однократную настройку меню, например, наполняете ресурс меню или вызываете методы Menu.add() для создания вашей системы голосового меню.

  3. Переопределите onMenuItemSelected() для обработки голосовых команд, когда их произносят пользователи. Когда пользователи завершают выбор пункта меню, голосовая команда «ОК, стекло» автоматически появляется в нижней части экрана, готовая принять новую голосовую команду, пока действие остается в фокусе.

    Следующий код включает контекстные голосовые команды, увеличивает ресурс меню, когда это необходимо, и обрабатывает голосовые команды, когда они произносятся:

    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);
        }
    }
    

    Вот пример ресурса меню, используемого предыдущим действием. Обратите внимание, как вы можете создавать вложенные пункты меню для иерархической системы голосового меню. В следующем примере к первому пункту меню можно получить доступ как: ок, стекло, Покажи мне собак, Лабрадор .

    <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);
        }
    

Поддержка голосового и сенсорного меню одновременно

Поскольку контекстные голосовые команды используют существующие API-интерфейсы меню Android, вы можете повторно использовать большую часть кода и ресурсов, которые у вас уже есть для сенсорных меню, и одновременно поддерживать оба типа меню.

Все, что вам нужно сделать, это проверить наличие функции 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, вы можете запросить разрешение Android в файле AndroidManifest.xml :

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

Использование неуказанных основных голосовых команд

  1. Объявите строковое значение в res/values/strings.xml , которое определяет имя вашего голосового триггера. При желании объявите голосовую подсказку для отображения Glassware распознавания речи перед запуском 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. Создайте ресурс XML для голосового триггера в res/xml/<my_voice_trigger>.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>

Запуск распознавания речи


Glassware для распознавания речи ожидает, пока пользователи заговорят, и возвращает транскрибированный текст после того, как они закончат. Чтобы начать действие:

  1. Вызовите startActivityForResult() с намерением ACTION_RECOGNIZE_SPEECH . Следующие дополнительные намерения поддерживаются при запуске действия:
  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);
    }