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

Голосовой ввод позволяет создать по-настоящему интерфейс без помощи рук. 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 отображать значок вашей посуды в сенсорном меню «ОК, стекло» .

    <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 ) в нужном действии, чтобы включить контекстные голосовые команды. Если эта функция включена, меню «ОК» появляется в нижней части экрана всякий раз, когда это действие получает фокус.

  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) {
    ...
}

Благодаря этим изменениям вы можете нажать или сказать «ОК» , чтобы отобразить меню.

Использование скрытых голосовых команд для разработки

Если вы хотите распространять свою стеклянную посуду, вы должны использовать утвержденные основные голосовые команды в 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);
    }