| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
| 6 | 6 |
| 7 import android.content.ComponentName; | 7 import android.content.ComponentName; |
| 8 import android.content.Context; | 8 import android.content.Context; |
| 9 import android.content.Intent; | 9 import android.content.Intent; |
| 10 import android.content.pm.PackageManager; | 10 import android.content.pm.PackageManager; |
| 11 import android.content.pm.PackageManager.NameNotFoundException; | 11 import android.content.pm.PackageManager.NameNotFoundException; |
| 12 import android.content.pm.ResolveInfo; | 12 import android.content.pm.ResolveInfo; |
| 13 import android.content.pm.ServiceInfo; | 13 import android.content.pm.ServiceInfo; |
| 14 import android.os.Bundle; | 14 import android.os.Bundle; |
| 15 import android.speech.RecognitionListener; | 15 import android.speech.RecognitionListener; |
| 16 import android.speech.RecognitionService; | 16 import android.speech.RecognitionService; |
| 17 import android.speech.RecognizerIntent; | 17 import android.speech.RecognizerIntent; |
| 18 import android.speech.SpeechRecognizer; | 18 import android.speech.SpeechRecognizer; |
| 19 | 19 |
| 20 import org.chromium.base.CalledByNative; | 20 import org.chromium.base.CalledByNative; |
| 21 import org.chromium.base.JNINamespace; | 21 import org.chromium.base.JNINamespace; |
| 22 import org.chromium.content_public.common.SpeechRecognitionErrorCode; |
| 22 | 23 |
| 23 import java.util.ArrayList; | 24 import java.util.ArrayList; |
| 24 import java.util.List; | 25 import java.util.List; |
| 25 | 26 |
| 26 /** | 27 /** |
| 27 * This class uses Android's SpeechRecognizer to perform speech recognition for
the Web Speech API | 28 * This class uses Android's SpeechRecognizer to perform speech recognition for
the Web Speech API |
| 28 * on Android. Using Android's platform recognizer offers several benefits, like
good quality and | 29 * on Android. Using Android's platform recognizer offers several benefits, like
good quality and |
| 29 * good local fallback when no data connection is available. | 30 * good local fallback when no data connection is available. |
| 30 */ | 31 */ |
| 31 @JNINamespace("content") | 32 @JNINamespace("content") |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 nativeOnSoundEnd(mNativeSpeechRecognizerImplAndroid); | 83 nativeOnSoundEnd(mNativeSpeechRecognizerImplAndroid); |
| 83 // Since Android doesn't have a dedicated event for when audio c
apture is finished, | 84 // Since Android doesn't have a dedicated event for when audio c
apture is finished, |
| 84 // we fire it after speech has ended. | 85 // we fire it after speech has ended. |
| 85 nativeOnAudioEnd(mNativeSpeechRecognizerImplAndroid); | 86 nativeOnAudioEnd(mNativeSpeechRecognizerImplAndroid); |
| 86 mState = STATE_IDLE; | 87 mState = STATE_IDLE; |
| 87 } | 88 } |
| 88 } | 89 } |
| 89 | 90 |
| 90 @Override | 91 @Override |
| 91 public void onError(int error) { | 92 public void onError(int error) { |
| 92 int code = SpeechRecognitionError.NONE; | 93 int code = SpeechRecognitionErrorCode.NONE; |
| 93 | 94 |
| 94 // Translate Android SpeechRecognizer errors to Web Speech API error
s. | 95 // Translate Android SpeechRecognizer errors to Web Speech API error
s. |
| 95 switch(error) { | 96 switch(error) { |
| 96 case SpeechRecognizer.ERROR_AUDIO: | 97 case SpeechRecognizer.ERROR_AUDIO: |
| 97 code = SpeechRecognitionError.AUDIO; | 98 code = SpeechRecognitionErrorCode.AUDIO; |
| 98 break; | 99 break; |
| 99 case SpeechRecognizer.ERROR_CLIENT: | 100 case SpeechRecognizer.ERROR_CLIENT: |
| 100 code = SpeechRecognitionError.ABORTED; | 101 code = SpeechRecognitionErrorCode.ABORTED; |
| 101 break; | 102 break; |
| 102 case SpeechRecognizer.ERROR_RECOGNIZER_BUSY: | 103 case SpeechRecognizer.ERROR_RECOGNIZER_BUSY: |
| 103 case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: | 104 case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: |
| 104 code = SpeechRecognitionError.NOT_ALLOWED; | 105 code = SpeechRecognitionErrorCode.NOT_ALLOWED; |
| 105 break; | 106 break; |
| 106 case SpeechRecognizer.ERROR_NETWORK_TIMEOUT: | 107 case SpeechRecognizer.ERROR_NETWORK_TIMEOUT: |
| 107 case SpeechRecognizer.ERROR_NETWORK: | 108 case SpeechRecognizer.ERROR_NETWORK: |
| 108 case SpeechRecognizer.ERROR_SERVER: | 109 case SpeechRecognizer.ERROR_SERVER: |
| 109 code = SpeechRecognitionError.NETWORK; | 110 code = SpeechRecognitionErrorCode.NETWORK; |
| 110 break; | 111 break; |
| 111 case SpeechRecognizer.ERROR_NO_MATCH: | 112 case SpeechRecognizer.ERROR_NO_MATCH: |
| 112 code = SpeechRecognitionError.NO_MATCH; | 113 code = SpeechRecognitionErrorCode.NO_MATCH; |
| 113 break; | 114 break; |
| 114 case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: | 115 case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: |
| 115 code = SpeechRecognitionError.NO_SPEECH; | 116 code = SpeechRecognitionErrorCode.NO_SPEECH; |
| 116 break; | 117 break; |
| 117 default: | 118 default: |
| 118 assert false; | 119 assert false; |
| 119 return; | 120 return; |
| 120 } | 121 } |
| 121 | 122 |
| 122 terminate(code); | 123 terminate(code); |
| 123 } | 124 } |
| 124 | 125 |
| 125 @Override | 126 @Override |
| 126 public void onEvent(int event, Bundle bundle) { } | 127 public void onEvent(int event, Bundle bundle) { } |
| 127 | 128 |
| 128 @Override | 129 @Override |
| 129 public void onPartialResults(Bundle bundle) { | 130 public void onPartialResults(Bundle bundle) { |
| 130 handleResults(bundle, true); | 131 handleResults(bundle, true); |
| 131 } | 132 } |
| 132 | 133 |
| 133 @Override | 134 @Override |
| 134 public void onReadyForSpeech(Bundle bundle) { | 135 public void onReadyForSpeech(Bundle bundle) { |
| 135 mState = STATE_AWAITING_SPEECH; | 136 mState = STATE_AWAITING_SPEECH; |
| 136 nativeOnAudioStart(mNativeSpeechRecognizerImplAndroid); | 137 nativeOnAudioStart(mNativeSpeechRecognizerImplAndroid); |
| 137 } | 138 } |
| 138 | 139 |
| 139 @Override | 140 @Override |
| 140 public void onResults(Bundle bundle) { | 141 public void onResults(Bundle bundle) { |
| 141 handleResults(bundle, false); | 142 handleResults(bundle, false); |
| 142 // We assume that onResults is called only once, at the end of a ses
sion, thus we | 143 // We assume that onResults is called only once, at the end of a ses
sion, thus we |
| 143 // terminate. If one day the recognition provider changes dictation
mode behavior to | 144 // terminate. If one day the recognition provider changes dictation
mode behavior to |
| 144 // call onResults several times, we should terminate only if (!mCont
inuous). | 145 // call onResults several times, we should terminate only if (!mCont
inuous). |
| 145 terminate(SpeechRecognitionError.NONE); | 146 terminate(SpeechRecognitionErrorCode.NONE); |
| 146 } | 147 } |
| 147 | 148 |
| 148 @Override | 149 @Override |
| 149 public void onRmsChanged(float rms) { } | 150 public void onRmsChanged(float rms) { } |
| 150 | 151 |
| 151 private void handleResults(Bundle bundle, boolean provisional) { | 152 private void handleResults(Bundle bundle, boolean provisional) { |
| 152 if (mContinuous && provisional) { | 153 if (mContinuous && provisional) { |
| 153 // In continuous mode, Android's recognizer sends final results
as provisional. | 154 // In continuous mode, Android's recognizer sends final results
as provisional. |
| 154 provisional = false; | 155 provisional = false; |
| 155 } | 156 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 private void terminate(int error) { | 231 private void terminate(int error) { |
| 231 | 232 |
| 232 if (mState != STATE_IDLE) { | 233 if (mState != STATE_IDLE) { |
| 233 if (mState == STATE_CAPTURING_SPEECH) { | 234 if (mState == STATE_CAPTURING_SPEECH) { |
| 234 nativeOnSoundEnd(mNativeSpeechRecognizerImplAndroid); | 235 nativeOnSoundEnd(mNativeSpeechRecognizerImplAndroid); |
| 235 } | 236 } |
| 236 nativeOnAudioEnd(mNativeSpeechRecognizerImplAndroid); | 237 nativeOnAudioEnd(mNativeSpeechRecognizerImplAndroid); |
| 237 mState = STATE_IDLE; | 238 mState = STATE_IDLE; |
| 238 } | 239 } |
| 239 | 240 |
| 240 if (error != SpeechRecognitionError.NONE) | 241 if (error != SpeechRecognitionErrorCode.NONE) |
| 241 nativeOnRecognitionError(mNativeSpeechRecognizerImplAndroid, error); | 242 nativeOnRecognitionError(mNativeSpeechRecognizerImplAndroid, error); |
| 242 | 243 |
| 243 mRecognizer.destroy(); | 244 mRecognizer.destroy(); |
| 244 mRecognizer = null; | 245 mRecognizer = null; |
| 245 nativeOnRecognitionEnd(mNativeSpeechRecognizerImplAndroid); | 246 nativeOnRecognitionEnd(mNativeSpeechRecognizerImplAndroid); |
| 246 mNativeSpeechRecognizerImplAndroid = 0; | 247 mNativeSpeechRecognizerImplAndroid = 0; |
| 247 } | 248 } |
| 248 | 249 |
| 249 @CalledByNative | 250 @CalledByNative |
| 250 private static SpeechRecognition createSpeechRecognition( | 251 private static SpeechRecognition createSpeechRecognition( |
| (...skipping 12 matching lines...) Expand all Loading... |
| 263 mIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, interimResults)
; | 264 mIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, interimResults)
; |
| 264 mRecognizer.startListening(mIntent); | 265 mRecognizer.startListening(mIntent); |
| 265 } | 266 } |
| 266 | 267 |
| 267 @CalledByNative | 268 @CalledByNative |
| 268 private void abortRecognition() { | 269 private void abortRecognition() { |
| 269 if (mRecognizer == null) | 270 if (mRecognizer == null) |
| 270 return; | 271 return; |
| 271 | 272 |
| 272 mRecognizer.cancel(); | 273 mRecognizer.cancel(); |
| 273 terminate(SpeechRecognitionError.ABORTED); | 274 terminate(SpeechRecognitionErrorCode.ABORTED); |
| 274 } | 275 } |
| 275 | 276 |
| 276 @CalledByNative | 277 @CalledByNative |
| 277 private void stopRecognition() { | 278 private void stopRecognition() { |
| 278 if (mRecognizer == null) | 279 if (mRecognizer == null) |
| 279 return; | 280 return; |
| 280 | 281 |
| 281 mContinuous = false; | 282 mContinuous = false; |
| 282 mRecognizer.stopListening(); | 283 mRecognizer.stopListening(); |
| 283 } | 284 } |
| 284 | 285 |
| 285 // Native JNI calls to content/browser/speech/speech_recognizer_impl_android
.cc | 286 // Native JNI calls to content/browser/speech/speech_recognizer_impl_android
.cc |
| 286 private native void nativeOnAudioStart(long nativeSpeechRecognizerImplAndroi
d); | 287 private native void nativeOnAudioStart(long nativeSpeechRecognizerImplAndroi
d); |
| 287 private native void nativeOnSoundStart(long nativeSpeechRecognizerImplAndroi
d); | 288 private native void nativeOnSoundStart(long nativeSpeechRecognizerImplAndroi
d); |
| 288 private native void nativeOnSoundEnd(long nativeSpeechRecognizerImplAndroid)
; | 289 private native void nativeOnSoundEnd(long nativeSpeechRecognizerImplAndroid)
; |
| 289 private native void nativeOnAudioEnd(long nativeSpeechRecognizerImplAndroid)
; | 290 private native void nativeOnAudioEnd(long nativeSpeechRecognizerImplAndroid)
; |
| 290 private native void nativeOnRecognitionResults(long nativeSpeechRecognizerIm
plAndroid, | 291 private native void nativeOnRecognitionResults(long nativeSpeechRecognizerIm
plAndroid, |
| 291 String[] results, | 292 String[] results, |
| 292 float[] scores, | 293 float[] scores, |
| 293 boolean provisional); | 294 boolean provisional); |
| 294 private native void nativeOnRecognitionError(long nativeSpeechRecognizerImpl
Android, int error); | 295 private native void nativeOnRecognitionError(long nativeSpeechRecognizerImpl
Android, int error); |
| 295 private native void nativeOnRecognitionEnd(long nativeSpeechRecognizerImplAn
droid); | 296 private native void nativeOnRecognitionEnd(long nativeSpeechRecognizerImplAn
droid); |
| 296 } | 297 } |
| OLD | NEW |