Entrada de voz

La entrada de voz te permite crear una interfaz verdaderamente manos libres. Glass te ofrece tres formas de usar la entrada de voz.

Los comandos de voz principales inician Glassware desde la tarjeta de inicio, los comandos de voz contextuales pueden ejecutar acciones dentro de una actividad, y la actividad de reconocimiento de voz del sistema te permite recibir entradas de voz de formato libre de los usuarios.

Comandos por voz principales

Estos comandos por voz inician Glassware desde la tarjeta de inicio (tarjeta de reloj). Cuando declaras un comando por voz principal, Glass crea automáticamente un elemento de menú táctil como resguardo en caso de que los usuarios decidan iniciar tu dispositivo Glassware presionando la tarjeta de inicio.

Para agregar un comando por voz al menú principal de voz ok Glass, haz lo siguiente:

  1. Crea un recurso XML para el comando por voz en res/xml/<my_voice_trigger>.xml que use uno de los comandos de voz existentes definidos en VoiceTriggers.Command. Por ejemplo, a continuación se indica cómo usar "Iniciar una ejecución".

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

    Para crear un comando por voz que le pida al usuario que diga una frase adicional antes de iniciar tu actividad o servicio, incluye también un elemento input. Por ejemplo, es posible que quieras hacerlo si usas la opción "Publicar una actualización".

    <?xml version="1.0" encoding="utf-8"?>
    <trigger command="POST_AN_UPDATE">
        <input prompt="@string/glass_voice_prompt" />
    </trigger>
    
  2. Registra un filtro de intents con la acción com.google.android.glass.action.VOICE_TRIGGER en tu manifiesto de Android. El filtro de intents inicia tu actividad o servicio si detecta que los usuarios dicen tu comando por voz.

    <?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. Declara un atributo android:icon para tu actividad o servicio. Esto permite que Glass muestre un ícono para tu Glassware en el menú táctil ok, Glass.

    <activity |service
        android:icon="@drawable/my_icon" ...>
      ...
    </activity | service>
    
  4. Si tu comando por voz usa un mensaje de voz y, luego, inicia una actividad, obtén cualquier texto transcrito con el siguiente código (como en onResume()):

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

    Si el comando por voz inicia un servicio, el intent adicional está disponible en la devolución de llamada onStartCommand():

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

Establece restricciones

Si necesitas una o todas de las siguientes funciones para iniciar tu Glassware, especifícalas en el recurso res/xml/<my_voice_trigger>.xml. Si las funciones no están disponibles, Glass inhabilita el comando por voz:

  • camera
  • network
  • microphone

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

Comandos por voz contextuales

Los comandos por voz contextuales permiten a los usuarios realizar acciones desde actividades. Puedes compilar comandos contextuales de voz con las API de menú estándar de Android, pero los usuarios pueden invocar los elementos de menú con comandos por voz en lugar de controles táctiles.

Para habilitar los comandos contextuales de voz para una actividad en particular:

  1. Llama a getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS) en la actividad deseada para habilitar los comandos por voz contextuales. Cuando esta función está habilitada, el menú "ok Glass" aparece en el área del pie de página de la pantalla cada vez que esta actividad recibe el foco.

  2. Anula onCreatePanelMenu() y controla el caso en el que WindowUtils.FEATURE_VOICE_COMMANDS esté habilitado. Si la opción está habilitada, aquí es donde realizas la configuración de menú única, como aumentar un recurso de menú o llamar a los métodos Menu.add() para crear tu sistema de menú de voz.

  3. Anula onMenuItemSelected() para controlar los comandos por voz cuando los usuarios los digan. Cuando los usuarios terminan de seleccionar un elemento de menú, el comando por voz "ok, Glass" vuelve a aparecer automáticamente en la sección de pie de página de la pantalla, listo para aceptar un nuevo comando por voz, siempre que la actividad permanezca enfocada.

    El siguiente código habilita los comandos por voz contextuales, aumenta un recurso de menú cuando corresponde y controla los comandos por voz cuando se pronuncian:

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

    A continuación, se muestra un ejemplo del recurso de menú que se usó en la actividad anterior. Observa cómo puedes crear elementos de menú anidados para un sistema de menú de voz jerárquico. En el siguiente ejemplo, se puede acceder al primer elemento del menú de la siguiente manera: 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. Anula onPreparePanel() (opcional) y verifica si WindowUtils.FEATURE_VOICE_COMMANDS está habilitado o no. Si está habilitado, aquí puedes hacer otra lógica para configurar el sistema del menú, como agregar y quitar ciertos elementos del menú en función de algunos criterios. También puedes activar o desactivar los menús contextuales de voz contextual (mostrar true) y mostrar (mostrar false) según algunos criterios. Por ejemplo:

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

Cómo agregar compatibilidad con menús táctiles y de voz de forma simultánea

Debido a que los comandos de voz contextuales usan las API del menú de Android existentes, puedes reutilizar gran parte del código y los recursos que ya tienes para los menús táctiles y admitir simultáneamente ambos tipos de menús.

Lo único que debes hacer es comprobar la función Window.FEATURE_OPTIONS_PANEL además de la función WindowUtils.FEATURE_VOICE_COMMANDS que ya verificaste en algunos métodos y, luego, agregar lógica para abrir el menú táctil en alguna acción del usuario, como presionar una opción.

Por ejemplo, puedes cambiar el ejemplo de actividad anterior para agregar compatibilidad con menús táctiles como este (los cambios se comentan):

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

Con estos cambios, puedes presionar o decir ok Glass para mostrar el menú.

Usa comandos por voz no listados para el desarrollo

Cuando desees distribuir tu cristalería, debes usar los comandos por voz principales aprobados en VoiceTriggers.Command y los comandos por voz contextuales aprobados en ContextualMenus.Command.

Si deseas usar comandos por voz que no están disponibles en GDK, puedes solicitar un permiso de Android en tu archivo AndroidManifest.xml:

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

Usa comandos por voz principales no listados

  1. Declara un valor de string en res/values/strings.xml que defina el nombre de tu activador de voz. De manera opcional, puedes declarar un mensaje de voz para mostrar la pantalla de reconocimiento de voz antes de iniciarla.

    <?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. Crea un recurso XML para el activador de voz en res/xml/<my_voice_trigger>.xml. Para los comandos de voz no listados, debes usar el atributo keyword en lugar del atributo command que se usa en los comandos de voz aprobados. El atributo keyword debe ser una referencia al recurso de strings que define el comando por voz. Para un activador de voz simple que inicie una actividad o un servicio de inmediato, simplemente especifica el elemento trigger:

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

    Para crear un activador de voz que le pida al usuario que diga una frase adicional antes de iniciar tu actividad o servicio, incluye también un elemento de entrada:

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

Usa comandos por voz contextuales no listados

Cuando crees elementos de menú, usa cualquier texto para el título del elemento. Por ejemplo:

<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>

Iniciando reconocimiento de voz


El reconocimiento de voz de Glassware espera a que los usuarios hablen y muestra el texto transcrito una vez que terminan. Para iniciar la actividad, haz lo siguiente:

  1. Llama a startActivityForResult() con el intent ACTION_RECOGNIZE_SPEECH. Cuando inicias la actividad, se admiten los siguientes extras de intents:
  2. Anula la devolución de llamada onActivityResult() para recibir el texto transcrito del intent adicional EXTRA_RESULTS. Se llama a esta devolución de llamada cuando los usuarios terminan de hablar.

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