Entrada de texto por voz

A entrada de texto por voz permite criar uma interface verdadeiramente por viva-voz. O Google Glass oferece três maneiras de usar a entrada de texto por voz.

Os comandos de voz principais iniciam o Glassware do card inicial, os comandos de voz contextuais podem executar ações em uma atividade e a atividade de reconhecimento de fala do sistema permite que você receba entradas de voz em formato livre dos usuários.

Principais comandos de voz

Estes comandos de voz iniciam o Glassware no card da casa (cartão de relógio). Quando você declara um comando de voz principal, o Google Glass cria automaticamente um item de menu de toque como substituto caso os usuários decidam iniciar o Glassware tocando no card "Início".

Para adicionar um comando de voz ao menu principal de voz do ok Glass:

  1. Crie um recurso XML para o comando de voz em res/xml/<my_voice_trigger>.xml que usa um dos comandos de voz existentes definidos em VoiceTriggers.Command. Por exemplo, veja como usar o recurso "Iniciar uma corrida".

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

    Para criar um comando de voz que incentive o usuário a falar outra frase antes de iniciar a atividade ou o serviço, inclua também um elemento input. Por exemplo, se você estiver usando a opção "Postar uma atualização".

    <?xml version="1.0" encoding="utf-8"?>
    <trigger command="POST_AN_UPDATE">
        <input prompt="@string/glass_voice_prompt" />
    </trigger>
    
  2. Registre um filtro de intent usando a ação com.google.android.glass.action.VOICE_TRIGGER no manifesto do Android. O filtro de intent iniciará a atividade ou serviço se detectar usuários que falam seu comando de 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. Declare um atributo android:icon para sua atividade ou serviço. Isso permite que o Google Glass mostre um ícone do seu Glassware no menu de toque de ok, Glass.

    <activity |service
        android:icon="@drawable/my_icon" ...>
      ...
    </activity | service>
    
  4. Se o comando de voz usar uma solicitação de voz e iniciar uma atividade, receba qualquer texto transcrito com o seguinte código, como em onResume():

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

    Se o comando de voz iniciar um serviço, a intent extra estará disponível no callback onStartCommand():

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

Como definir restrições

Se você precisar de um ou de todos os recursos a seguir para iniciar o Glassware, especifique-os no recurso res/xml/<my_voice_trigger>.xml. Se os recursos não estiverem disponíveis, o Google Glass vai desativar o comando de voz:

  • camera
  • network
  • microphone

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

Comandos de voz contextuais

Os comandos de voz contextuais permitem que os usuários realizem ações em atividades. Você cria comandos de voz contextuais com as APIs de menu padrão do Android, mas os usuários podem invocar os itens de menu com comandos de voz em vez de toque.

Para ativar comandos de voz contextuais para uma atividade específica:

  1. Chame getWindow().requestFeature(WindowUtils.FEATURE_VOICE_COMMANDS) na atividade desejada para ativar os comandos de voz contextuais. Com esse recurso ativado, o menu "ok Glass" aparece na área do rodapé da tela sempre que essa atividade receber foco.

  2. Modifique onCreatePanelMenu() e processe o caso em que WindowUtils.FEATURE_VOICE_COMMANDS está ativado. Se ativado, é aqui que você fará uma configuração única do menu, como inflar um recurso de menu ou chamar os métodos Menu.add() para criar seu sistema de menu de voz.

  3. Modifique onMenuItemSelected() para processar os comandos de voz quando os usuários falarem. Quando os usuários concluírem a seleção de um item de menu, o comando de voz "ok, Glass" aparecerá automaticamente na seção de rodapé da tela, pronto para aceitar um novo comando de voz, desde que a atividade permaneça em foco.

    O código a seguir ativa comandos de voz contextuais, infla um recurso de menu quando apropriado e processa comandos de voz quando eles são falados:

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

    Veja um exemplo do recurso de menu usado pela atividade anterior. Observe como você pode criar itens de menu aninhados para um sistema hierárquico de menu de voz. No exemplo a seguir, o primeiro item de menu pode ser acessado como: 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. (Opcional) Substitua onPreparePanel(), verificando se WindowUtils.FEATURE_VOICE_COMMANDS está ativado. Se ativado, é aqui que você pode fazer outra lógica para configurar o sistema de menus, como adicionar e remover determinados itens de menu com base em alguns critérios. Também é possível ativar ou desativar os menus de voz contextuais (retornar true) (retornar false) com base em alguns critérios. Exemplo:

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

Suporte a menus de voz e toque simultaneamente

Como os comandos de voz contextuais usam as APIs de menu do Android, você pode reutilizar grande parte do código e dos recursos que já tem para menus de toque e oferecer suporte aos dois tipos de menus simultaneamente.

Tudo o que você precisa fazer é verificar o recurso Window.FEATURE_OPTIONS_PANEL, além do recurso WindowUtils.FEATURE_VOICE_COMMANDS que já está verificando em alguns métodos, e adicionar lógica para abrir o menu de toque em alguma ação do usuário, como um toque.

Por exemplo, você pode mudar o exemplo de atividade anterior para adicionar compatibilidade com menus de toque como este (alterações são comentadas):

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

Com essas mudanças, você pode tocar ou dizer ok Glass para mostrar o menu.

Usar comandos de voz não listados para desenvolvimento

Para distribuir seu Glassware, use os comandos de voz principais aprovados em VoiceTriggers.Command e os comandos de voz contextuais aprovados em ContextualMenus.Command.

Se você quiser usar comandos de voz que não estão disponíveis no GDK, solicite uma permissão Android no arquivo AndroidManifest.xml:

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

Usar comandos de voz principais não listados

  1. Declare um valor de string em res/values/strings.xml que defina o nome do seu gatilho de voz. Como opção, declare uma solicitação de voz para exibir o Glassware de reconhecimento de fala antes de começar.

    <?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. Crie um recurso XML para o gatilho de voz em res/xml/<my_voice_trigger>.xml. Para comandos de voz não listados, use o atributo keyword em vez do atributo command usado para comandos de voz aprovados. O atributo keyword precisa ser uma referência ao recurso de string que define o comando de voz. Para um gatilho de voz simples que inicia uma atividade ou serviço imediatamente, basta especificar o elemento trigger:

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

    Para criar um gatilho de voz que incentive o usuário a falar outra frase antes de iniciar a atividade ou o serviço, inclua também um elemento de entrada:

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

Usar comandos de voz contextuais não listados

Ao criar itens de menu, use qualquer texto para o título do item. Exemplo:

<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 reconhecimento de fala


O Glassware de reconhecimento de fala espera os usuários falarem e retorna o texto transcrito depois que eles são concluídos. Para iniciar a atividade:

  1. Chame startActivityForResult() com a intent ACTION_RECOGNIZE_SPEECH. Os extras de intent a seguir são compatíveis ao iniciar a atividade:
  2. Substitua o callback onActivityResult() para receber o texto transcrito do extra da intent EXTRA_RESULTS. Esse callback é chamado quando os usuários terminam de falar.

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