Tutorial Android – Speech-To-Text Sem O Pop-Up

On 4 de agosto de 2017 by Carlos Mion

Neste post iremos mostrar como adicionar a função de Speech-To-Text do Google no seu aplicativo sem que aquele Pop-Up característico apareça. O desenvolvimento usará o Android Studio 2.3.3 e a versão 6.0 do Android(API 23) – A funcionalidade faz parte do Android desde a API 8.

Android Manifest para o Speech-To-Text

No AndroidManifest.xml, adicione a linha:

[code language=”java”]
<uses-permission android:name="android.permission.RECORD_AUDIO" />
[/code]

Esta linha serve para que seu celular libere o acesso ao microfone.

Implementando a nova classe Speech-To-Text

Este tutorial utilizará de um novo projeto Android para seu desenvolvimento, mas caso seu interesse seja apenas adicionar esta função ao seu aplicativo, basta acompanhar a partir da parte da criação da nova classe em diante.

Criação do projeto:

Com o projeto ja criado, crie uma nova classe chamada SpeechToText:

Nova classe criada:

Logo após a criação da classe, faça com que ela implemente “RecognitionListener”:

[code language=”java”]
public class SpeechToText implements RecognitionListener {
[/code]

A IDE irá acusar erro:

Para corrigi-lo basta clicar na linha sublinhada de vermelho e digitar “Alt+Enter” e selecionar a primeira opção “Implement methods”(Implementar métodos). A classe ficará assim:

Agora declare as variáveis que serão utilizadas nesta classe:

[code language=”java”]
private SpeechRecognizer speech = null;
private Intent recognizerIntent;
private MainActivity mainActivity;
private String text = "";
private boolean isListening = false;
private int MINIMUM_LENGTH_FOR_EXTRA_SPEECH_IN_MILLIS = 3000;
private final backgroundListener backgroundListener; // o erro lançado por esta linha será corrigido mais tarde com o desenvolvimento da classe.
[/code]

Agora faça o construtor da classe Speech-To-Text:

 

[code language=”java”]
public SpeechToText(){
mainActivity = new MainActivity();
backgroundListener = new backgroundListener();
speech = SpeechRecognizer.createSpeechRecognizer(MainActivity.getContext()); // este erro também será resolvido no decorrer do tutorial.
speech.setRecognitionListener(this);
recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE,
Locale.getDefault()); // leia logo abaixo a explicação desta linha.
recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, mainActivity.getPackageName());
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, MINIMUM_LENGTH_FOR_EXTRA_SPEECH_IN_MILLIS);
}
[/code]

Observação, na linha:

[code language=”java”]
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE,
Locale.getDefault());
[/code]

“Locale.getDefault()” significa que a linguagem/idioma que o App tentará reconhecer é a padrão do sistema. Caso queira uma linguagem/idioma diferente da padrão de seu celular, basta trocá-lo por:

[code language=”java”]
Locale.ENGLISH
[/code]

Caso não tenha encontrado a linguagem desejada, como por exemplo, português, substitua “Locale.getDefault()” por “new Locale(“pt”, “BR”)”, a linha fica assim:

[code language=”java”]
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, new Locale("pt", "BR"));
[/code]

Agora voltando ao desenvolvimento da classe, adicione as funções get e set da variável “isListening” digitando os códigos:

[code language=”java”]
public boolean isListening() {
return isListening;
}

public void setListening(boolean listening) {
isListening = listening;
}
[/code]

Então preencha os métodos adicionados automaticamente pela IDE de cima para baixo, com a exceção das que ficarão sem alteração. Começando por “onReadyForSpeech(Bundle bundle)”:

Adicione a linha:

[code language=”java”]
setListening(false);
[/code]

Em “onBeginningOfSpeech()”, adicione:

[code language=”java”]
setListening(true);
[/code]

Em “onEndOfSpeech()”, adicione:

[code language=”java”]
setListening(false);
[/code]

Em “onError()”, adicione:

[code language=”java”]
MainActivity.setsubtitle(text);
[/code]

Em “onPartialResults(Bundle bundle)”, primeiro troque o nome do parâmetro, para que o código fique mais claro, substitua “Bundle bundle” por “Bundle partialResults”, logo após, adicione as linhas:

[code language=”java”]
ArrayList matches = partialResults
.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
text = "";
if(matches!=null)
for (String result : matches)
text += result + "\n";
MainActivity.setsubtitle(text);
setListening(false);
[/code]

Criando a Thread que controlará o SpeechToText

Ainda dentro da classe SpeechToText, crie uma nova classe, com o código:

[code language=”java”]
public class backgroundVoiceListener extends Thread{
public void run(){
try {
this.sleep(2000);
if(!isListening()){
setListening(true);
speech.startListening(recognizerIntent);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
[/code]

Esta thread, “backgroundVoiceListener”, irá fornecer o método “run()” que utilizaremos na MainActivity para ativar o reconhecimento de voz.

No final, a classe SpeechToText ficará assim:

[code language=”java”]
package com.example.mion.tutorial_speech_to_text;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.util.Log;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Locale;

public class SpeechToText implements RecognitionListener {

private SpeechRecognizer speech = null;
private Intent recognizerIntent;
private MainActivity mainActivity;
private String text = "";
private boolean isListening = false;
private int MINIMUM_LENGTH_FOR_EXTRA_SPEECH_IN_MILLIS = 3000;
final BackgroundVoiceListener backgroundVoiceListener;
public TextView subtitle;

public boolean isListening() {
return isListening;
}

public void setListening(boolean listening) {
isListening = listening;
}

public SpeechToText(){
mainActivity = new MainActivity();
subtitle = mainActivity.getSubtitle();
backgroundVoiceListener = new BackgroundVoiceListener();
speech = SpeechRecognizer.createSpeechRecognizer(MainActivity.getContext());
speech.setRecognitionListener(this);
recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, Locale.getDefault());
recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, mainActivity.getPackageName());
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, MINIMUM_LENGTH_FOR_EXTRA_SPEECH_IN_MILLIS);

}

@Override
public void onReadyForSpeech(Bundle bundle) {
setListening(false);
}

@Override
public void onBeginningOfSpeech() {
setListening(true);
}

@Override
public void onRmsChanged(float v) {
Log.i("Text", "onRmsChanged: " + v);

}

@Override
public void onBufferReceived(byte[] bytes) {

}

@Override
public void onEndOfSpeech() {
setListening(false);
}

@Override
public void onError(int i) {
MainActivity.setsubtitle(text);
Log.i("Text","text: " + text);

}

@Override
public void onResults(Bundle bundle) {

}

@Override
public void onPartialResults(Bundle partialResults) {
ArrayList matches = partialResults
.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
text = "";
Log.i("Text","text: " + text);
if(matches!=null)
for (String result : matches)
text += result + "\n";
Log.i("Text","text: " + text);
MainActivity.setsubtitle(text);
setListening(false);

}

@Override
public void onEvent(int i, Bundle bundle) {

}

public class BackgroundVoiceListener extends Thread{
public void run(){
try {
this.sleep(2000);
Log.i("Text","islistening: " + isListening());
if(!isListening()){
setListening(true);
speech.startListening(recognizerIntent);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}
[/code]

Utilizando a SpeechToText

[code language=”java”]
private SpeechToText stt;
public static Context context;
private boolean primeiraVez = true;
private static TextView subtitle;
[/code]

“stt” será utilizada para que possamos acessar a classe “SpeechToText” pela “MainActivity”, “context” será utilizado para corrigir o erro remanescente na classe SpeechToText, “primeiraVez” é uma variável de controle para que o “SpeechToText” seja inicializado apenas uma vez e “subtitle” é a variável que irá mostrar na tela o resultado do reconhecimento.

Crie o getter de “context” adicionando o código:

[code language=”java”]
public static Context getContext() {
return context;
}
[/code]

Este contexto é necessário para que o speechRecognizer seja inicializado.

Crie o getter e o setter de “firstTime” adicionando o código:

[code language=”java”]
public boolean isFirstTime() {
return firstTime;
}

public void setFirstTime(boolean firstTime) {
this.firstTime = firstTime;
}
[/code]

Também adicione o método “setSST()”, ele inicializará sst.

[code language=”java”]
public void setSST(){
stt = new SpeechToText();
setPrimeiraVez(false);
}
[/code]

Agora, para começar o reconhecimento de voz, basta adicionar as linhas abaixo no onCreate da “MainActivity”:

[code language=”java”]
context = getApplicationContext();
if(isFirstTime())
setSST();
[/code]

Assim, quando quiser que o reconhecimento seja feito, basta chamar o método:

[code language=”java”]
stt.backgroundVoiceListener.run();
[/code]

Exemplificando o Speech-To-Text

No menu de navegação da IDE, vá em “res” > “layout” > “activity_main.xml” e selecione a aba “Text”:

Abaixo do bloco de declaração do TextView que já vem de padrão, adicione um botão:

[code language=”java”]
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClickEscutar"
android:text="Escutar"
tools:layout_editor_absoluteX="148dp"
tools:layout_editor_absoluteY="302dp" />
[/code]

De volta na “MainActivity”, adicione o método “onClick” do botão:

[code language=”java”]
public void onClickEscutar(View view) {
stt.backgroundVoiceListener.run();

}
[/code]

Agora inicialize o TextView no onCreate():

[code language=”java”]
subtitle = (TextView) findViewById(R.id.text);
[/code]

Logo após isso, adicione o método “setSubtitle()”:

[code language=”java”]
public static void setsubtitle(String txt){

subtitle.setText(txt);

}
[/code]

Este método serve para acessar a referência ao texto.

A MainActivity ficou assim:

[code language=”java”]
package com.example.mion.tutorial_speech_to_text;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

private SpeechToText stt;
public static Context context;
private boolean firstTime = true;
public static TextView subtitle;

public TextView getSubtitle() {
return subtitle;
}

public boolean isFirstTime() {
return firstTime;
}

public void setFirstTime(boolean firstTime) {
this.firstTime = firstTime;
}

public static Context getContext() {
return context;
}

public void setSST() {
stt = new SpeechToText();
setFirstTime(false);
}

public static void setsubtitle(String txt){

subtitle.setText(txt);

}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
subtitle = (TextView) findViewById(R.id.text);

subtitle.setText("sdasd");
context = getApplicationContext();
if (isFirstTime())
setSST();
}

public void onClickEscutar(View view) {
Log.i("Text","clicou");
stt.backgroundVoiceListener.run();
}
}
[/code]

Agora basta ir nas configurações para permitir o acesso ao microfone, ou caso já faça o pedido de permissões na sua aplicação, basta adicioná-la.

Duvidas? Entre em contato comigo no E-mail: moc.liamtohnull@32noimsolrac

8 Responses to “Tutorial Android – Speech-To-Text Sem O Pop-Up”

  • Bem legal o seu tutorial, estou começando a programar em Android agora e estou gostando bastante!

  • Como faria para mandar o resultado do reconhecimento sem receber uma NullPointer ? tentei usar o metodo onResults mas continua dando o erro

  • Muito bom! Ajudou muito aqui, porém ainda preciso fazer com que ele fique escutando diretamente sem finalizar

  • Excelente tutorial para quem assim como eu está aprendendo a programar para dispositivos Android. Muito bem escrito!

  • A intenção do seu tutorial é ótima.
    Mas, tem erros demais.

    Seguem:
    – Na classe SpeechToText, o objeto backgroundListener além de iniciar com letra minúscula, não existe no projeto. Porém, subtende-se que seja a classe interna backgroundVoiceListener. Que também inicia com letra minúscula.

    – O objeto backgroundListener não é utilizado em nenhum momento.

    – O método stt.backgroundVoiceListener().run() não pode ser chamado dentro da classe MainActivity, porque backgroundVoiceListener é uma classe e não um objeto. Acho que você quis executar o objeto backgroundListener, mas também não pode, porque é uma variável privada.
    Uma forma correta, por exemplo, é criar um método público em SpeechToText que execute backgroundListener.run() e executar este método dentro de MainActivity, chamando stt..

    – Você declarou na MainActivity, a variável primeiraVez, mas não é usado em nenhum local.

    – Depois você cria os métodos isFirstTime e setFirstTime alterando o estado da variável firstTime, que não existe.

    Porém, subtende-se que primeiraVez seja firstTime.

    No método onPartialResults, você está querendo varrer uma lista de String, mas não referencia o objeto genérico na declaração de matches, devendo ficar assim -> ArrayList matches

    – Na classe SpeechToText, em seu construtor, não tem sentido instanciar a classe MainActivity. Inclusive dá erro ao obter o nome do pacote da classe, em recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, activity.getPackageName());

    O correto é passar a referência da MainActivity, no construtor da classe SpeechToText, ficando public SpeechToText(Activity activity) e utiliza-lo em toda a classe.

    Segue as correções do seu tutorial:

    MainActivity.java -> https://pastebin.com/y1ZFdrqx
    SpeechToText.java -> https://pastebin.com/siLU67ZF
    activity_main.java -> https://pastebin.com/0DxUfCcv
    AndroidManifest.xml -> https://pastebin.com/zPyyFqiP

    Abstraia o ícone ic_recorder_microphone_svgrepo_com no ImageView. Converti um arquivo .svg qualquer que encontrei.

  • Obrigado, estava pensando a mesma coisa.

  • Apesar de publicado há algum tempo atrás, esse conteúdo ainda é extremamente útil e me ajudou bastante com o desenvolvimento de um aplicativo mobile. Postem mais conteúdos assim. Abraços.

Deixe um comentário

O seu endereço de e-mail não será publicado.