1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package android.voicerecognition.cts; 18 19 import android.app.Activity; 20 import android.content.ComponentName; 21 import android.content.Intent; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.speech.ModelDownloadListener; 25 import android.speech.RecognitionListener; 26 import android.speech.RecognitionSupportCallback; 27 import android.speech.RecognizerIntent; 28 import android.speech.SpeechRecognizer; 29 30 import androidx.annotation.NonNull; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.concurrent.CountDownLatch; 35 import java.util.concurrent.Executors; 36 37 /** 38 * An activity that uses SpeechRecognition APIs. SpeechRecognition will bind the RecognitionService 39 * to provide the voice recognition functions. 40 */ 41 public class SpeechRecognitionActivity extends Activity { 42 private final String TAG = "SpeechRecognitionActivity"; 43 44 private List<RecognizerInfo> mRecognizerInfos; 45 46 private Handler mHandler; 47 48 @Override onCreate(Bundle savedInstanceState)49 protected void onCreate(Bundle savedInstanceState) { 50 super.onCreate(savedInstanceState); 51 mHandler = new Handler(getMainLooper()); 52 setContentView(R.layout.main); 53 } 54 55 @Override onDestroy()56 protected void onDestroy() { 57 destroyAllRecognizers(); 58 super.onDestroy(); 59 } 60 startListeningDefault()61 public void startListeningDefault() { 62 startListening(/* index */ 0); 63 } 64 startListening(int index)65 public void startListening(int index) { 66 final Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 67 recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName()); 68 startListening(recognizerIntent, index); 69 } 70 startListening(Intent intent, int index)71 public void startListening(Intent intent, int index) { 72 mHandler.post(() -> mRecognizerInfos.get(index).mRecognizer.startListening(intent)); 73 } 74 stopListeningDefault()75 public void stopListeningDefault() { 76 stopListening(/* index */ 0); 77 } 78 stopListening(int index)79 public void stopListening(int index) { 80 mHandler.post(mRecognizerInfos.get(index).mRecognizer::stopListening); 81 } 82 cancelDefault()83 public void cancelDefault() { 84 cancel(/* index */ 0); 85 } 86 cancel(int index)87 public void cancel(int index) { 88 mHandler.post(mRecognizerInfos.get(index).mRecognizer::cancel); 89 } 90 destroyRecognizerDefault()91 public void destroyRecognizerDefault() { 92 destroyRecognizer(/* index */ 0); 93 } 94 destroyRecognizer(int index)95 public void destroyRecognizer(int index) { 96 mHandler.post(mRecognizerInfos.get(index).mRecognizer::destroy); 97 } 98 99 /** 100 * Destroy any / all recognizers used by this Activity. 101 */ destroyAllRecognizers()102 public void destroyAllRecognizers() { 103 mHandler.post(() -> { 104 if (mRecognizerInfos != null) { 105 for (RecognizerInfo recognizerInfo : mRecognizerInfos) { 106 if (recognizerInfo.mRecognizer != null) { 107 recognizerInfo.mRecognizer.destroy(); 108 } 109 } 110 mRecognizerInfos.clear(); 111 } 112 }); 113 } 114 checkRecognitionSupportDefault(Intent intent, RecognitionSupportCallback rsc)115 public void checkRecognitionSupportDefault(Intent intent, RecognitionSupportCallback rsc) { 116 checkRecognitionSupport(intent, rsc, /* index */ 0); 117 } 118 checkRecognitionSupport(Intent intent, RecognitionSupportCallback rsc, int index)119 public void checkRecognitionSupport(Intent intent, RecognitionSupportCallback rsc, int index) { 120 mHandler.post(() -> mRecognizerInfos.get(index).mRecognizer.checkRecognitionSupport( 121 intent, Executors.newSingleThreadExecutor(), rsc)); 122 } 123 triggerModelDownloadDefault(Intent intent)124 public void triggerModelDownloadDefault(Intent intent) { 125 triggerModelDownload(intent, /* index */ 0); 126 } 127 triggerModelDownload(Intent intent, int index)128 public void triggerModelDownload(Intent intent, int index) { 129 mHandler.post(() -> mRecognizerInfos.get(index).mRecognizer.triggerModelDownload(intent)); 130 } 131 triggerModelDownloadWithListenerDefault( Intent intent, ModelDownloadListener listener)132 public void triggerModelDownloadWithListenerDefault( 133 Intent intent, ModelDownloadListener listener) { 134 triggerModelDownloadWithListener(intent, listener, /* index */ 0); 135 } 136 triggerModelDownloadWithListener( Intent intent, ModelDownloadListener listener, int index)137 public void triggerModelDownloadWithListener( 138 Intent intent, ModelDownloadListener listener, int index) { 139 mHandler.post(() -> mRecognizerInfos.get(index) 140 .mRecognizer.triggerModelDownload( 141 intent, 142 Executors.newSingleThreadExecutor(), 143 listener)); 144 } 145 initDefault(boolean onDevice, String customRecognizerComponent)146 public void initDefault(boolean onDevice, String customRecognizerComponent) { 147 init(onDevice, customRecognizerComponent, /* recognizerCount */ 1); 148 } 149 init(boolean onDevice, String customRecognizerComponent, int recognizerCount)150 public void init(boolean onDevice, String customRecognizerComponent, int recognizerCount) { 151 mRecognizerInfos = new ArrayList<>(); 152 153 for (int i = 0; i < recognizerCount; i++) { 154 mHandler.post(() -> { 155 final SpeechRecognizer recognizer; 156 if (onDevice) { 157 recognizer = SpeechRecognizer.createOnDeviceTestingSpeechRecognizer(this); 158 } else if (customRecognizerComponent != null) { 159 recognizer = SpeechRecognizer.createSpeechRecognizer(this, 160 ComponentName.unflattenFromString(customRecognizerComponent)); 161 } else { 162 recognizer = SpeechRecognizer.createSpeechRecognizer(this); 163 } 164 mRecognizerInfos.add(new RecognizerInfo(recognizer)); 165 }); 166 } 167 } 168 getRecognizerInfoDefault()169 RecognizerInfo getRecognizerInfoDefault() { 170 return getRecognizerInfo(/* index */ 0); 171 } 172 getRecognizerInfo(int index)173 RecognizerInfo getRecognizerInfo(int index) { 174 return mRecognizerInfos.get(index); 175 } 176 getRecognizerCount()177 int getRecognizerCount() { 178 return mRecognizerInfos.size(); 179 } 180 181 /** 182 * Data class containing information about a recognizer object used in the activity: 183 * <ul> 184 * <li> {@link RecognizerInfo#mRecognizer} - the recognizer object; 185 * <li> {@link RecognizerInfo#mCallbackMethodsInvoked} - list of {@link CallbackMethod}s 186 * invoked on the recognizer's listener; 187 * <li> {@link RecognizerInfo#mStartListeningCalled} - flag denoting 188 * if the recognizer has been used; 189 * <li> {@link RecognizerInfo#mCountDownLatch} - synchronization object used 190 * to emulate waiting on the recognition result. 191 */ 192 static class RecognizerInfo { 193 final SpeechRecognizer mRecognizer; 194 final List<CallbackMethod> mCallbackMethodsInvoked; 195 final List<Integer> mErrorCodesReceived; 196 public boolean mStartListeningCalled; 197 public CountDownLatch mCountDownLatch; 198 RecognizerInfo(SpeechRecognizer recognizer)199 RecognizerInfo(SpeechRecognizer recognizer) { 200 mRecognizer = recognizer; 201 mCallbackMethodsInvoked = new ArrayList<>(); 202 mErrorCodesReceived = new ArrayList<>(); 203 mStartListeningCalled = false; 204 mCountDownLatch = new CountDownLatch(1); 205 206 mRecognizer.setRecognitionListener(new SpeechRecognizerListener()); 207 } 208 209 class SpeechRecognizerListener implements RecognitionListener { 210 @Override onReadyForSpeech(Bundle params)211 public void onReadyForSpeech(Bundle params) { 212 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_READY_FOR_SPEECH); 213 } 214 215 @Override onBeginningOfSpeech()216 public void onBeginningOfSpeech() { 217 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_BEGINNING_OF_SPEECH); 218 } 219 220 @Override onRmsChanged(float rmsdB)221 public void onRmsChanged(float rmsdB) { 222 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_RMS_CHANGED); 223 } 224 225 @Override onBufferReceived(byte[] buffer)226 public void onBufferReceived(byte[] buffer) { 227 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_BUFFER_RECEIVED); 228 } 229 230 @Override onEndOfSpeech()231 public void onEndOfSpeech() { 232 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_END_OF_SPEECH); 233 } 234 235 @Override onError(int error)236 public void onError(int error) { 237 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_ERROR); 238 mErrorCodesReceived.add(error); 239 } 240 241 @Override onResults(Bundle results)242 public void onResults(Bundle results) { 243 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_RESULTS); 244 mStartListeningCalled = true; 245 mCountDownLatch.countDown(); 246 } 247 248 @Override onPartialResults(Bundle partialResults)249 public void onPartialResults(Bundle partialResults) { 250 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_PARTIAL_RESULTS); 251 } 252 253 @Override onSegmentResults(@onNull Bundle segmentResults)254 public void onSegmentResults(@NonNull Bundle segmentResults) { 255 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_SEGMENTS_RESULTS); 256 } 257 258 @Override onEndOfSegmentedSession()259 public void onEndOfSegmentedSession() { 260 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_END_SEGMENTED_SESSION); 261 } 262 263 @Override onLanguageDetection(@onNull Bundle results)264 public void onLanguageDetection(@NonNull Bundle results) { 265 mCallbackMethodsInvoked.add(CallbackMethod.CALLBACK_METHOD_LANGUAGE_DETECTION); 266 } 267 268 @Override onEvent(int eventType, Bundle params)269 public void onEvent(int eventType, Bundle params) { 270 } 271 } 272 } 273 } 274