/* * Copyright 2011 Greg Milette and Adam Stroud * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package root.gast.speech; import java.util.Arrays; import java.util.List; import java.util.Locale; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Intent; import android.os.Bundle; import android.speech.RecognitionListener; import android.speech.RecognizerIntent; import android.speech.SpeechRecognizer; import android.util.Log; /** * abstract class for getting speech, handles some boiler plate code. Any * Activity that uses speech should extend this, or utilize the methods in * {@link SpeechRecognitionUtil} * * @author gmilette */ public abstract class SpeechRecognizingActivity extends Activity implements RecognitionListener { private static final String TAG = "SpeechRecognizingActivity"; /** * code to identify return recognition results */ public static final int VOICE_RECOGNITION_REQUEST_CODE = 1234; public static final int UNKNOWN_ERROR = -1; private SpeechRecognizer recognizer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); boolean recognizerIntent = SpeechRecognitionUtil.isSpeechAvailable(this); if (!recognizerIntent) { speechNotAvailable(); } boolean direct = SpeechRecognizer.isRecognitionAvailable(this); if (!direct) { directSpeechNotAvailable(); } } protected void checkForLanguage(final Locale language) { OnLanguageDetailsListener andThen = new OnLanguageDetailsListener() { @Override public void onLanguageDetailsReceived(LanguageDetailsChecker data) { // do a best match String languageToUse = data.matchLanguage(language); languageCheckResult(languageToUse); } }; SpeechRecognitionUtil.getLanguageDetails(this, andThen); } /** * execute the RecognizerIntent, then call * {@link #receiveWhatWasHeard(List, List)} when done * might throw a {@link ActivityNotFoundException} if the * device cannot respond to the Intent */ public void recognize(Intent recognizerIntent) { startActivityForResult(recognizerIntent, VOICE_RECOGNITION_REQUEST_CODE); } /** * Handle the results from the RecognizerIntent. */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == VOICE_RECOGNITION_REQUEST_CODE) { if (resultCode == RESULT_OK) { List<String> heard = data. getStringArrayListExtra (RecognizerIntent.EXTRA_RESULTS); float[] scores = data. getFloatArrayExtra (RecognizerIntent.EXTRA_CONFIDENCE_SCORES); if (scores == null) { for (int i = 0; i < heard.size(); i++) { Log.d(TAG, i + ": " + heard.get(i)); } } else { for (int i = 0; i < heard.size(); i++) { Log.d(TAG, i + ": " + heard.get(i) + " score: " + scores[i]); } } receiveWhatWasHeard(heard, scores); } else { Log.d(TAG, "error code: " + resultCode); recognitionFailure(UNKNOWN_ERROR); } } super.onActivityResult(requestCode, resultCode, data); } /** * called when speech is not available on this device, and when * {@link #recognize(Intent)} will not work */ abstract protected void speechNotAvailable(); /** * called when {@link SpeechRecognizer} cannot be used on this device and * {@link #recognizeDirectly(Intent)} will not work */ abstract protected void directSpeechNotAvailable(); /** * call back the result from {@link #checkForLanguage(Locale)} * * @param languageToUse * the language string to use or null if failure */ abstract protected void languageCheckResult(String languageToUse); /** * result of speech recognition * * @param heard * possible speech to text conversions * @param confidenceScores * the confidence for the strings in heard */ abstract protected void receiveWhatWasHeard(List<String> heard, float[] confidenceScores); /** * @param code * If using {@link #recognizeDirectly(Intent) it will be * the error code from {@link SpeechRecognizer} * if using {@link #recognize(Intent)} * it will be {@link #UNKNOWN_ERROR}. */ abstract protected void recognitionFailure(int errorCode); //direct speech recognition methods follow /** * Uses {@link SpeechRecognizer} to perform recognition and then calls * {@link #receiveWhatWasHeard(List, float[])} with the results <br> * check {@link SpeechRecognizer.isRecognitionAvailable(context)} before * calling this method otherwise if it isn't available the code will report * an error */ public void recognizeDirectly(Intent recognizerIntent) { // SpeechRecognizer requires EXTRA_CALLING_PACKAGE, so add if it's not // here if (!recognizerIntent.hasExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE)) { recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, "com.dummy"); } SpeechRecognizer recognizer = getSpeechRecognizer(); recognizer.startListening(recognizerIntent); } @Override public void onResults(Bundle results) { Log.d(TAG, "full results"); receiveResults(results); } @Override public void onPartialResults(Bundle partialResults) { Log.d(TAG, "partial results"); receiveResults(partialResults); } /** * common method to process any results bundle from {@link SpeechRecognizer} */ private void receiveResults(Bundle results) { if ((results != null) && results.containsKey(SpeechRecognizer.RESULTS_RECOGNITION)) { List<String> heard = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); float[] scores = results.getFloatArray(SpeechRecognizer.CONFIDENCE_SCORES); receiveWhatWasHeard(heard, scores); } } @Override public void onError(int errorCode) { recognitionFailure(errorCode); } /** * stop the speech recognizer */ @Override protected void onPause() { if (getSpeechRecognizer() != null) { getSpeechRecognizer().stopListening(); getSpeechRecognizer().cancel(); getSpeechRecognizer().destroy(); } super.onPause(); } /** * lazy initialize the speech recognizer */ private SpeechRecognizer getSpeechRecognizer() { if (recognizer == null) { recognizer = SpeechRecognizer.createSpeechRecognizer(this); recognizer.setRecognitionListener(this); } return recognizer; } // other unused methods from RecognitionListener... @Override public void onReadyForSpeech(Bundle params) { Log.d(TAG, "ready for speech " + params); } @Override public void onEndOfSpeech() { } /** * @see android.speech.RecognitionListener#onBeginningOfSpeech() */ @Override public void onBeginningOfSpeech() { } @Override public void onBufferReceived(byte[] buffer) { } @Override public void onRmsChanged(float rmsdB) { } @Override public void onEvent(int eventType, Bundle params) { } public void onPartialResultsUnsupported(Bundle partialResults) { Log.d(TAG, "partial results"); if (partialResults .containsKey(SpeechRecognitionUtil.UNSUPPORTED_GOOGLE_RESULTS)) { String[] heard = partialResults .getStringArray(SpeechRecognitionUtil.UNSUPPORTED_GOOGLE_RESULTS); float[] scores = partialResults .getFloatArray(SpeechRecognitionUtil.UNSUPPORTED_GOOGLE_RESULTS_CONFIDENCE); receiveWhatWasHeard(Arrays.asList(heard), scores); } else { receiveResults(partialResults); } } }