Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@brandall76
Last active January 26, 2024 10:11
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save brandall76/b911eb732f309dec68af351d74013851 to your computer and use it in GitHub Desktop.
Save brandall76/b911eb732f309dec68af351d74013851 to your computer and use it in GitHub Desktop.
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import java.util.ArrayList;
import java.util.Locale;
/**
* Create the basic Android Studio floating action button activity project and paste the below in. I
* haven't included the record audio permission flow for 23+
* <p>
* BUG replicated on Google Now V5.11.34.19.arm
* <p>
* Test 1 - The standard time given to speak before ERROR_NO_MATCH is thrown seems to have reduced
* since V5.10.32.16.arm.
* <p>
* Test 2 - Setting TEST_ERROR to true will not cancel/destroy the recognizer between each use. The
* result of this shows that ERROR_NO_MATCH is called immediately after recognizer.startListening(intent),
* but the recognizer continues to function.
* <p>
* Test 3 - Setting TEST_ERROR to false the (unfiltered) log shows error messages regarding the leaking
* of the ServiceConnection
* Test 4 - The partial results often contain just an empty string. Not a massive issue, other than
* checking !partialArray.isEmpty() technically returns a false positive, as there's nothing to see...
*
** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW **
** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW **
*
* Since the release of V5.14.32.16.arm the behaviour of test 3 has changed. Replicated on multiple
* devices running various API levels. V5.14.32.21.arm appears to be more troublesome.
*
* With TEST_ERROR set to false, there are no longer log messages regarding the leaking of the
* service connection, instead the behaviour is now the same as Test 2 aside from a new log error message
* showing 'E/SpeechRecognizer: not connected to the recognition service'. In both cases, whether
* destroying the recognizer or not, ERROR_NO_MATCH is immediately thrown.
*
* Test 5 - onRmsChanged() is now only sporadically being called. With TEST_ERROR set to false, press
* the FAB to start the voice recognition, then immediately press it again. onRmsChanged() will
* begin to be called again.
*
* Test 6 - Repeat Test 5 until the recognizer makes the double beep 'error' noise (unique to Google).
* Next time the recognition is started onEndOfSpeech() will be called immediately. This does not
* happen every time and may take a few attempts to replicate.
*
* Handling the bug - Subclass the RecognitionListener and ensure that onReadyForSpeech() has been
* called prior to reacting to ERROR_NO_MATCH or onEndOfSpeech()
* <a href="https://gist.github.com/brandall76/bbf908d886c9a3469e6957812555f1f7">BugRecognitionListener/a>
*
* Test 7 - Whilst the recognition is listening, call recognizer.stopListening() and then immediately destroy the
* recognition service. The next time the recognizer starts listening, onBeginningOfSpeech() will be called twice.
*
* NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW **
* NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW ** NEW **
*
* Since the release of V6.0.23.*** the recognizer is now completely broken. If you don't speak initially, the
* recognition will continue indefinitely. Otherwise end of speech has around a 10 second delay.
*
* stopListening() no longer works
*/
public class MainActivity extends AppCompatActivity implements RecognitionListener {
private SpeechRecognizer recognizer;
private Intent intent = null;
// Toggle to test errors
private boolean TEST_ERROR = false;
// Reset each time startListening is called.
private long then;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
assert fab != null;
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (TEST_ERROR || recognizer == null) {
Log.i("SPEECH_TEST", "onClick: setting recognizer");
intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getPackageName());
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "blar");
intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault().toString());
recognizer = SpeechRecognizer.createSpeechRecognizer(MainActivity.this);
recognizer.setRecognitionListener(MainActivity.this);
}
then = System.currentTimeMillis();
recognizer.startListening(intent);
}
});
}
@Override
public void onReadyForSpeech(final Bundle params) {
}
@Override
public void onBeginningOfSpeech() {
}
@Override
public void onRmsChanged(final float rmsdB) {
}
@Override
public void onBufferReceived(final byte[] buffer) {
}
@Override
public void onEndOfSpeech() {
}
@Override
public void onError(final int error) {
Log.w("SPEECH_TEST", "onError");
switch (error) {
case SpeechRecognizer.ERROR_NO_MATCH:
Log.e("SPEECH_TEST", "onError: ERROR_NO_MATCH");
// Will also output a time when the bug occurs
Log.d("SPEECH_TEST", "time given to speak: " + (System.currentTimeMillis() - then));
break;
}
}
@Override
public void onResults(final Bundle results) {
Log.i("SPEECH_TEST", "onResults");
if (!TEST_ERROR) {
Log.i("SPEECH_TEST", "onResults: destroying recognizer");
if (recognizer != null) {
recognizer.cancel();
recognizer.destroy();
recognizer = null;
}
}
}
@Override
public void onPartialResults(final Bundle partialResults) {
final ArrayList<String> partialData = partialResults.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
if (partialData != null) {
for (String partial : partialData) {
if (partial.replaceAll("\\s", "").isEmpty()) {
Log.i("SPEECH_TEST", "onPartialResults: I'm an empty String?");
}
}
}
}
@Override
public void onEvent(final int eventType, final Bundle params) {
}
}
@brandall76
Copy link
Author

Updated Test 7 - changed do not destroy the recognizer, to do destroy the recognizer. Can't replicate otherwise.

@nisd93
Copy link

nisd93 commented May 25, 2017

Can't get rid of with "onError "? Any help!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment