743 lines
27 KiB
Java
743 lines
27 KiB
Java
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
*
|
|
* 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 android.speech;
|
|
|
|
import android.Manifest;
|
|
import android.annotation.CallbackExecutor;
|
|
import android.annotation.MainThread;
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.annotation.RequiresPermission;
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.os.Binder;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.os.Looper;
|
|
import android.os.Message;
|
|
import android.os.RemoteException;
|
|
import android.os.ServiceManager;
|
|
import android.provider.Settings;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
import android.util.Slog;
|
|
|
|
import java.util.Objects;
|
|
import java.util.Queue;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
class SpeechRecognizerImpl extends SpeechRecognizer {
|
|
/** DEBUG value to enable verbose debug prints */
|
|
private static final boolean DBG = false;
|
|
|
|
/** Log messages identifier */
|
|
private static final String TAG = "SpeechRecognizer";
|
|
|
|
/** action codes */
|
|
private static final int MSG_START = 1;
|
|
private static final int MSG_STOP = 2;
|
|
private static final int MSG_CANCEL = 3;
|
|
private static final int MSG_CHANGE_LISTENER = 4;
|
|
private static final int MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT = 5;
|
|
private static final int MSG_CHECK_RECOGNITION_SUPPORT = 6;
|
|
private static final int MSG_TRIGGER_MODEL_DOWNLOAD = 7;
|
|
private static final int MSG_DESTROY = 8;
|
|
|
|
/** The actual RecognitionService endpoint */
|
|
private IRecognitionService mService;
|
|
|
|
/** Context with which the manager was created */
|
|
private final Context mContext;
|
|
|
|
/** Component to direct service intent to */
|
|
private final ComponentName mServiceComponent;
|
|
|
|
/** Whether to use on-device speech recognizer. */
|
|
private final boolean mOnDevice;
|
|
|
|
private IRecognitionServiceManager mManagerService;
|
|
|
|
/** Handler that will execute the main tasks */
|
|
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
|
|
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
switch (msg.what) {
|
|
case MSG_START -> handleStartListening((Intent) msg.obj);
|
|
case MSG_STOP -> handleStopMessage();
|
|
case MSG_CANCEL -> handleCancelMessage();
|
|
case MSG_CHANGE_LISTENER -> handleChangeListener((RecognitionListener) msg.obj);
|
|
case MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT ->
|
|
handleSetTemporaryComponent((ComponentName) msg.obj);
|
|
case MSG_CHECK_RECOGNITION_SUPPORT -> {
|
|
CheckRecognitionSupportArgs args = (CheckRecognitionSupportArgs) msg.obj;
|
|
handleCheckRecognitionSupport(
|
|
args.mIntent, args.mCallbackExecutor, args.mCallback);
|
|
}
|
|
case MSG_TRIGGER_MODEL_DOWNLOAD -> {
|
|
ModelDownloadListenerArgs modelDownloadListenerArgs =
|
|
(ModelDownloadListenerArgs) msg.obj;
|
|
handleTriggerModelDownload(
|
|
modelDownloadListenerArgs.mIntent,
|
|
modelDownloadListenerArgs.mExecutor,
|
|
modelDownloadListenerArgs.mModelDownloadListener);
|
|
}
|
|
case MSG_DESTROY -> handleDestroy();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Temporary queue, saving the messages until the connection will be established, afterwards,
|
|
* only mHandler will receive the messages
|
|
*/
|
|
private final Queue<Message> mPendingTasks = new LinkedBlockingQueue<>();
|
|
|
|
/** The Listener that will receive all the callbacks */
|
|
private final InternalRecognitionListener mListener = new InternalRecognitionListener();
|
|
|
|
private final IBinder mClientToken = new Binder();
|
|
|
|
/**
|
|
* The right way to create a {@code SpeechRecognizer} is by using
|
|
* {@link #createSpeechRecognizer} static factory method
|
|
*/
|
|
/* package */ SpeechRecognizerImpl(
|
|
final Context context,
|
|
final ComponentName serviceComponent) {
|
|
this(context, serviceComponent, false);
|
|
}
|
|
|
|
/**
|
|
* The right way to create a {@code SpeechRecognizer} is by using
|
|
* {@link #createOnDeviceSpeechRecognizer} static factory method
|
|
*/
|
|
/* package */ SpeechRecognizerImpl(final Context context, boolean onDevice) {
|
|
this(context, null, onDevice);
|
|
}
|
|
|
|
private SpeechRecognizerImpl(
|
|
final Context context,
|
|
final ComponentName serviceComponent,
|
|
final boolean onDevice) {
|
|
mContext = context;
|
|
mServiceComponent = serviceComponent;
|
|
mOnDevice = onDevice;
|
|
}
|
|
|
|
@NonNull
|
|
@MainThread
|
|
/* package */ static SpeechRecognizerImpl lenientlyCreateOnDeviceSpeechRecognizer(
|
|
@NonNull final Context context) {
|
|
if (context == null) {
|
|
throw new IllegalArgumentException("Context cannot be null");
|
|
}
|
|
checkIsCalledFromMainThread();
|
|
return new SpeechRecognizerImpl(context, /* onDevice */ true);
|
|
}
|
|
|
|
@Override
|
|
@MainThread
|
|
public void setRecognitionListener(RecognitionListener listener) {
|
|
checkIsCalledFromMainThread();
|
|
if (mListener.mInternalListener == null) {
|
|
// This shortcut is needed because otherwise, if there's an error connecting, it never
|
|
// gets delivered. I.e., the onSuccess callback set up in connectToSystemService does
|
|
// not get called, MSG_CHANGE_LISTENER does not get executed, so the onError in the same
|
|
// place does not get forwarded anywhere.
|
|
// Thread-wise, this is safe as both this method and the handler are on the UI thread.
|
|
handleChangeListener(listener);
|
|
} else {
|
|
putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
@MainThread
|
|
public void startListening(final Intent recognizerIntent) {
|
|
if (recognizerIntent == null) {
|
|
throw new IllegalArgumentException("intent must not be null");
|
|
}
|
|
checkIsCalledFromMainThread();
|
|
|
|
if (DBG) {
|
|
Slog.i(TAG, "#startListening called");
|
|
if (mService == null) {
|
|
Slog.i(TAG, "Connection is not established yet");
|
|
}
|
|
}
|
|
|
|
if (mService == null) {
|
|
// First time connection: first establish a connection, then dispatch #startListening.
|
|
connectToSystemService();
|
|
}
|
|
putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent));
|
|
}
|
|
|
|
@Override
|
|
@MainThread
|
|
public void stopListening() {
|
|
checkIsCalledFromMainThread();
|
|
|
|
if (DBG) {
|
|
Slog.i(TAG, "#stopListening called");
|
|
if (mService == null) {
|
|
Slog.i(TAG, "Connection is not established yet");
|
|
}
|
|
}
|
|
|
|
putMessage(Message.obtain(mHandler, MSG_STOP));
|
|
}
|
|
|
|
@Override
|
|
@MainThread
|
|
public void cancel() {
|
|
checkIsCalledFromMainThread();
|
|
putMessage(Message.obtain(mHandler, MSG_CANCEL));
|
|
}
|
|
|
|
@Override
|
|
public void checkRecognitionSupport(
|
|
@NonNull Intent recognizerIntent,
|
|
@NonNull @CallbackExecutor Executor executor,
|
|
@NonNull RecognitionSupportCallback supportListener) {
|
|
Objects.requireNonNull(recognizerIntent, "intent must not be null");
|
|
Objects.requireNonNull(supportListener, "listener must not be null");
|
|
|
|
if (DBG) {
|
|
Slog.i(TAG, "#checkRecognitionSupport called");
|
|
if (mService == null) {
|
|
Slog.i(TAG, "Connection is not established yet");
|
|
}
|
|
}
|
|
|
|
if (mService == null) {
|
|
// First time connection: first establish a connection, then dispatch.
|
|
connectToSystemService();
|
|
}
|
|
putMessage(Message.obtain(mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
|
|
new CheckRecognitionSupportArgs(recognizerIntent, executor, supportListener)));
|
|
}
|
|
|
|
@Override
|
|
public void triggerModelDownload(@NonNull Intent recognizerIntent) {
|
|
Objects.requireNonNull(recognizerIntent, "intent must not be null");
|
|
if (DBG) {
|
|
Slog.i(TAG, "#triggerModelDownload without a listener called");
|
|
if (mService == null) {
|
|
Slog.i(TAG, "Connection is not established yet");
|
|
}
|
|
}
|
|
if (mService == null) {
|
|
// First time connection: first establish a connection, then dispatch.
|
|
connectToSystemService();
|
|
}
|
|
putMessage(Message.obtain(
|
|
mHandler, MSG_TRIGGER_MODEL_DOWNLOAD,
|
|
new ModelDownloadListenerArgs(recognizerIntent, null, null)));
|
|
}
|
|
|
|
@Override
|
|
public void triggerModelDownload(
|
|
@NonNull Intent recognizerIntent,
|
|
@NonNull @CallbackExecutor Executor executor,
|
|
@NonNull ModelDownloadListener listener) {
|
|
Objects.requireNonNull(recognizerIntent, "intent must not be null");
|
|
if (DBG) {
|
|
Slog.i(TAG, "#triggerModelDownload with a listener called");
|
|
if (mService == null) {
|
|
Slog.i(TAG, "Connection is not established yet");
|
|
}
|
|
}
|
|
if (mService == null) {
|
|
// First time connection: first establish a connection, then dispatch.
|
|
connectToSystemService();
|
|
}
|
|
putMessage(Message.obtain(
|
|
mHandler, MSG_TRIGGER_MODEL_DOWNLOAD,
|
|
new ModelDownloadListenerArgs(recognizerIntent, executor, listener)));
|
|
}
|
|
|
|
@Override
|
|
@RequiresPermission(Manifest.permission.MANAGE_SPEECH_RECOGNITION)
|
|
public void setTemporaryOnDeviceRecognizer(@Nullable ComponentName componentName) {
|
|
mHandler.sendMessage(
|
|
Message.obtain(mHandler, MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT, componentName));
|
|
}
|
|
|
|
/* package */ static void checkIsCalledFromMainThread() {
|
|
if (Looper.myLooper() != Looper.getMainLooper()) {
|
|
throw new RuntimeException(
|
|
"SpeechRecognizer should be used only from the application's main thread");
|
|
}
|
|
}
|
|
|
|
private void putMessage(Message msg) {
|
|
if (mService == null) {
|
|
mPendingTasks.offer(msg);
|
|
} else {
|
|
mHandler.sendMessage(msg);
|
|
}
|
|
}
|
|
|
|
/** sends the actual message to the service */
|
|
private void handleStartListening(Intent recognizerIntent) {
|
|
if (!checkOpenConnection()) {
|
|
return;
|
|
}
|
|
try {
|
|
mService.startListening(recognizerIntent, mListener, mContext.getAttributionSource());
|
|
if (DBG) Log.d(TAG, "service start listening command succeeded");
|
|
} catch (final Exception e) {
|
|
Log.e(TAG, "startListening() failed", e);
|
|
mListener.onError(ERROR_CLIENT);
|
|
}
|
|
}
|
|
|
|
/** sends the actual message to the service */
|
|
private void handleStopMessage() {
|
|
if (!checkOpenConnection()) {
|
|
return;
|
|
}
|
|
try {
|
|
mService.stopListening(mListener);
|
|
if (DBG) Log.d(TAG, "service stop listening command succeeded");
|
|
} catch (final Exception e) {
|
|
Log.e(TAG, "stopListening() failed", e);
|
|
mListener.onError(ERROR_CLIENT);
|
|
}
|
|
}
|
|
|
|
/** sends the actual message to the service */
|
|
private void handleCancelMessage() {
|
|
if (!checkOpenConnection()) {
|
|
return;
|
|
}
|
|
try {
|
|
mService.cancel(mListener, /*isShutdown*/ false);
|
|
if (DBG) Log.d(TAG, "service cancel command succeeded");
|
|
} catch (final Exception e) {
|
|
Log.e(TAG, "cancel() failed", e);
|
|
mListener.onError(ERROR_CLIENT);
|
|
}
|
|
}
|
|
|
|
private void handleSetTemporaryComponent(ComponentName componentName) {
|
|
if (DBG) {
|
|
Log.d(TAG, "handleSetTemporaryComponent, componentName=" + componentName);
|
|
}
|
|
|
|
if (!maybeInitializeManagerService()) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
mManagerService.setTemporaryComponent(componentName);
|
|
} catch (final RemoteException e) {
|
|
e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
private void handleCheckRecognitionSupport(
|
|
Intent recognizerIntent,
|
|
Executor callbackExecutor,
|
|
RecognitionSupportCallback recognitionSupportCallback) {
|
|
if (!maybeInitializeManagerService() || !checkOpenConnection()) {
|
|
return;
|
|
}
|
|
try {
|
|
mService.checkRecognitionSupport(
|
|
recognizerIntent,
|
|
mContext.getAttributionSource(),
|
|
new InternalSupportCallback(callbackExecutor, recognitionSupportCallback));
|
|
if (DBG) Log.d(TAG, "service support command succeeded");
|
|
} catch (final Exception e) {
|
|
Log.e(TAG, "checkRecognitionSupport() failed", e);
|
|
callbackExecutor.execute(() -> recognitionSupportCallback.onError(ERROR_CLIENT));
|
|
}
|
|
}
|
|
|
|
private void handleTriggerModelDownload(
|
|
Intent recognizerIntent,
|
|
@Nullable Executor callbackExecutor,
|
|
@Nullable ModelDownloadListener modelDownloadListener) {
|
|
if (!maybeInitializeManagerService() || !checkOpenConnection()) {
|
|
return;
|
|
}
|
|
|
|
if (modelDownloadListener == null) {
|
|
// Trigger model download without a listener.
|
|
try {
|
|
mService.triggerModelDownload(
|
|
recognizerIntent, mContext.getAttributionSource(), null);
|
|
if (DBG) Log.d(TAG, "triggerModelDownload() without a listener");
|
|
} catch (final Exception e) {
|
|
Log.e(TAG, "triggerModelDownload() without a listener failed", e);
|
|
mListener.onError(ERROR_CLIENT);
|
|
}
|
|
} else {
|
|
// Trigger model download with a listener.
|
|
try {
|
|
mService.triggerModelDownload(
|
|
recognizerIntent, mContext.getAttributionSource(),
|
|
new InternalModelDownloadListener(callbackExecutor, modelDownloadListener));
|
|
if (DBG) Log.d(TAG, "triggerModelDownload() with a listener");
|
|
} catch (final Exception e) {
|
|
Log.e(TAG, "triggerModelDownload() with a listener failed", e);
|
|
callbackExecutor.execute(() -> modelDownloadListener.onError(ERROR_CLIENT));
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean checkOpenConnection() {
|
|
if (mService != null && mService.asBinder().isBinderAlive()) {
|
|
return true;
|
|
}
|
|
mListener.onError(ERROR_CLIENT);
|
|
Log.e(TAG, "not connected to the recognition service");
|
|
return false;
|
|
}
|
|
|
|
/** changes the listener */
|
|
private void handleChangeListener(RecognitionListener listener) {
|
|
if (DBG) Log.d(TAG, "handleChangeListener, listener=" + listener);
|
|
mListener.mInternalListener = listener;
|
|
}
|
|
|
|
@Override
|
|
public void destroy() {
|
|
putMessage(mHandler.obtainMessage(MSG_DESTROY));
|
|
}
|
|
|
|
private void handleDestroy() {
|
|
if (mService != null) {
|
|
try {
|
|
mService.cancel(mListener, /*isShutdown*/ true);
|
|
} catch (final Exception e) {
|
|
// Not important
|
|
}
|
|
}
|
|
|
|
mService = null;
|
|
mPendingTasks.clear();
|
|
mListener.mInternalListener = null;
|
|
}
|
|
|
|
/** Establishes a connection to system server proxy and initializes the session. */
|
|
private void connectToSystemService() {
|
|
if (!maybeInitializeManagerService()) {
|
|
return;
|
|
}
|
|
|
|
ComponentName componentName = getSpeechRecognizerComponentName();
|
|
|
|
if (!mOnDevice && componentName == null) {
|
|
mListener.onError(ERROR_CLIENT);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
mManagerService.createSession(
|
|
componentName,
|
|
mClientToken,
|
|
mOnDevice,
|
|
new IRecognitionServiceManagerCallback.Stub(){
|
|
@Override
|
|
public void onSuccess(IRecognitionService service) throws RemoteException {
|
|
if (DBG) {
|
|
Log.i(TAG, "Connected to speech recognition service");
|
|
}
|
|
mService = service;
|
|
while (!mPendingTasks.isEmpty()) {
|
|
mHandler.sendMessage(mPendingTasks.poll());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onError(int errorCode) throws RemoteException {
|
|
Log.e(TAG, "Bind to system recognition service failed with error "
|
|
+ errorCode);
|
|
mListener.onError(errorCode);
|
|
}
|
|
});
|
|
} catch (RemoteException e) {
|
|
e.rethrowFromSystemServer();
|
|
}
|
|
}
|
|
|
|
private synchronized boolean maybeInitializeManagerService() {
|
|
if (DBG) {
|
|
Log.i(TAG, "#maybeInitializeManagerService found = " + mManagerService);
|
|
}
|
|
if (mManagerService != null) {
|
|
return true;
|
|
}
|
|
|
|
IBinder service = ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE);
|
|
if (service == null && mOnDevice) {
|
|
service = (IBinder) mContext.getSystemService(Context.SPEECH_RECOGNITION_SERVICE);
|
|
}
|
|
mManagerService = IRecognitionServiceManager.Stub.asInterface(service);
|
|
|
|
if (mManagerService == null) {
|
|
if (mListener != null) {
|
|
mListener.onError(ERROR_CLIENT);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns the component name to be used for establishing a connection, based on the parameters
|
|
* used during initialization.
|
|
*
|
|
* <p>Note the 3 different scenarios:
|
|
* <ol>
|
|
* <li>On-device speech recognizer which is determined by the manufacturer and not
|
|
* changeable by the user
|
|
* <li>Default user-selected speech recognizer as specified by
|
|
* {@code Settings.Secure.VOICE_RECOGNITION_SERVICE}
|
|
* <li>Custom speech recognizer supplied by the client.
|
|
* </ol>
|
|
*/
|
|
@SuppressWarnings("NonUserGetterCalled")
|
|
private ComponentName getSpeechRecognizerComponentName() {
|
|
if (mOnDevice) {
|
|
return null;
|
|
}
|
|
|
|
if (mServiceComponent != null) {
|
|
return mServiceComponent;
|
|
}
|
|
|
|
String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(),
|
|
Settings.Secure.VOICE_RECOGNITION_SERVICE);
|
|
|
|
if (TextUtils.isEmpty(serviceComponent)) {
|
|
Log.e(TAG, "no selected voice recognition service");
|
|
mListener.onError(ERROR_CLIENT);
|
|
return null;
|
|
}
|
|
|
|
return ComponentName.unflattenFromString(serviceComponent);
|
|
}
|
|
|
|
private static class CheckRecognitionSupportArgs {
|
|
final Intent mIntent;
|
|
final Executor mCallbackExecutor;
|
|
final RecognitionSupportCallback mCallback;
|
|
|
|
private CheckRecognitionSupportArgs(
|
|
Intent intent,
|
|
Executor callbackExecutor,
|
|
RecognitionSupportCallback callback) {
|
|
mIntent = intent;
|
|
mCallbackExecutor = callbackExecutor;
|
|
mCallback = callback;
|
|
}
|
|
}
|
|
|
|
private static class ModelDownloadListenerArgs {
|
|
final Intent mIntent;
|
|
final Executor mExecutor;
|
|
final ModelDownloadListener mModelDownloadListener;
|
|
|
|
private ModelDownloadListenerArgs(Intent intent, Executor executor,
|
|
ModelDownloadListener modelDownloadListener) {
|
|
mIntent = intent;
|
|
mExecutor = executor;
|
|
mModelDownloadListener = modelDownloadListener;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal wrapper of IRecognitionListener which will propagate the results to
|
|
* RecognitionListener
|
|
*/
|
|
private static class InternalRecognitionListener extends IRecognitionListener.Stub {
|
|
private RecognitionListener mInternalListener;
|
|
|
|
private static final int MSG_BEGINNING_OF_SPEECH = 1;
|
|
private static final int MSG_BUFFER_RECEIVED = 2;
|
|
private static final int MSG_END_OF_SPEECH = 3;
|
|
private static final int MSG_ERROR = 4;
|
|
private static final int MSG_READY_FOR_SPEECH = 5;
|
|
private static final int MSG_RESULTS = 6;
|
|
private static final int MSG_PARTIAL_RESULTS = 7;
|
|
private static final int MSG_RMS_CHANGED = 8;
|
|
private static final int MSG_ON_EVENT = 9;
|
|
private static final int MSG_SEGMENT_RESULTS = 10;
|
|
private static final int MSG_SEGMENT_END_SESSION = 11;
|
|
private static final int MSG_LANGUAGE_DETECTION = 12;
|
|
|
|
private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) {
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
if (mInternalListener == null) {
|
|
return;
|
|
}
|
|
switch (msg.what) {
|
|
case MSG_BEGINNING_OF_SPEECH:
|
|
mInternalListener.onBeginningOfSpeech();
|
|
break;
|
|
case MSG_BUFFER_RECEIVED:
|
|
mInternalListener.onBufferReceived((byte[]) msg.obj);
|
|
break;
|
|
case MSG_END_OF_SPEECH:
|
|
mInternalListener.onEndOfSpeech();
|
|
break;
|
|
case MSG_ERROR:
|
|
mInternalListener.onError((Integer) msg.obj);
|
|
break;
|
|
case MSG_READY_FOR_SPEECH:
|
|
mInternalListener.onReadyForSpeech((Bundle) msg.obj);
|
|
break;
|
|
case MSG_RESULTS:
|
|
mInternalListener.onResults((Bundle) msg.obj);
|
|
break;
|
|
case MSG_PARTIAL_RESULTS:
|
|
mInternalListener.onPartialResults((Bundle) msg.obj);
|
|
break;
|
|
case MSG_RMS_CHANGED:
|
|
mInternalListener.onRmsChanged((Float) msg.obj);
|
|
break;
|
|
case MSG_ON_EVENT:
|
|
mInternalListener.onEvent(msg.arg1, (Bundle) msg.obj);
|
|
break;
|
|
case MSG_SEGMENT_RESULTS:
|
|
mInternalListener.onSegmentResults((Bundle) msg.obj);
|
|
break;
|
|
case MSG_SEGMENT_END_SESSION:
|
|
mInternalListener.onEndOfSegmentedSession();
|
|
break;
|
|
case MSG_LANGUAGE_DETECTION:
|
|
mInternalListener.onLanguageDetection((Bundle) msg.obj);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
public void onBeginningOfSpeech() {
|
|
Message.obtain(mInternalHandler, MSG_BEGINNING_OF_SPEECH).sendToTarget();
|
|
}
|
|
|
|
public void onBufferReceived(final byte[] buffer) {
|
|
Message.obtain(mInternalHandler, MSG_BUFFER_RECEIVED, buffer).sendToTarget();
|
|
}
|
|
|
|
public void onEndOfSpeech() {
|
|
Message.obtain(mInternalHandler, MSG_END_OF_SPEECH).sendToTarget();
|
|
}
|
|
|
|
public void onError(final int error) {
|
|
Message.obtain(mInternalHandler, MSG_ERROR, error).sendToTarget();
|
|
}
|
|
|
|
public void onReadyForSpeech(final Bundle noiseParams) {
|
|
Message.obtain(mInternalHandler, MSG_READY_FOR_SPEECH, noiseParams).sendToTarget();
|
|
}
|
|
|
|
public void onResults(final Bundle results) {
|
|
Message.obtain(mInternalHandler, MSG_RESULTS, results).sendToTarget();
|
|
}
|
|
|
|
public void onPartialResults(final Bundle results) {
|
|
Message.obtain(mInternalHandler, MSG_PARTIAL_RESULTS, results).sendToTarget();
|
|
}
|
|
|
|
public void onRmsChanged(final float rmsdB) {
|
|
Message.obtain(mInternalHandler, MSG_RMS_CHANGED, rmsdB).sendToTarget();
|
|
}
|
|
|
|
public void onSegmentResults(final Bundle bundle) {
|
|
Message.obtain(mInternalHandler, MSG_SEGMENT_RESULTS, bundle).sendToTarget();
|
|
}
|
|
|
|
public void onEndOfSegmentedSession() {
|
|
Message.obtain(mInternalHandler, MSG_SEGMENT_END_SESSION).sendToTarget();
|
|
}
|
|
|
|
public void onLanguageDetection(final Bundle results) {
|
|
Message.obtain(mInternalHandler, MSG_LANGUAGE_DETECTION, results).sendToTarget();
|
|
}
|
|
|
|
public void onEvent(final int eventType, final Bundle params) {
|
|
Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params)
|
|
.sendToTarget();
|
|
}
|
|
}
|
|
|
|
private static class InternalSupportCallback extends IRecognitionSupportCallback.Stub {
|
|
private final Executor mExecutor;
|
|
private final RecognitionSupportCallback mCallback;
|
|
|
|
private InternalSupportCallback(Executor executor, RecognitionSupportCallback callback) {
|
|
this.mExecutor = executor;
|
|
this.mCallback = callback;
|
|
}
|
|
|
|
@Override
|
|
public void onSupportResult(RecognitionSupport recognitionSupport) throws RemoteException {
|
|
mExecutor.execute(() -> mCallback.onSupportResult(recognitionSupport));
|
|
}
|
|
|
|
@Override
|
|
public void onError(int errorCode) throws RemoteException {
|
|
mExecutor.execute(() -> mCallback.onError(errorCode));
|
|
}
|
|
}
|
|
|
|
private static class InternalModelDownloadListener extends IModelDownloadListener.Stub {
|
|
private final Executor mExecutor;
|
|
private final ModelDownloadListener mModelDownloadListener;
|
|
|
|
private InternalModelDownloadListener(
|
|
Executor executor,
|
|
@NonNull ModelDownloadListener modelDownloadListener) {
|
|
mExecutor = executor;
|
|
mModelDownloadListener = modelDownloadListener;
|
|
}
|
|
|
|
@Override
|
|
public void onProgress(int completedPercent) throws RemoteException {
|
|
mExecutor.execute(() -> mModelDownloadListener.onProgress(completedPercent));
|
|
}
|
|
|
|
@Override
|
|
public void onSuccess() throws RemoteException {
|
|
mExecutor.execute(() -> mModelDownloadListener.onSuccess());
|
|
}
|
|
|
|
@Override
|
|
public void onScheduled() throws RemoteException {
|
|
mExecutor.execute(() -> mModelDownloadListener.onScheduled());
|
|
}
|
|
|
|
@Override
|
|
public void onError(int error) throws RemoteException {
|
|
mExecutor.execute(() -> mModelDownloadListener.onError(error));
|
|
}
|
|
}
|
|
}
|