speech: API council feedback from model download with a listener

A single listener corresponds to a single model download request
identified by the intent. Hence, instead of setting and clearing
the listener explicitly, the whole pipeline will be covered by
a triggerModelDownload overload.

Bug: 271016482
Test: CTS
Change-Id: I580359009316a325c77e432f74faa7e2431b813a
This commit is contained in:
Aleksandar Kiridzic
2023-03-13 16:44:40 +00:00
committed by Aleksandar Kiridžić
parent f7e5e1471c
commit 828eef124c
7 changed files with 164 additions and 275 deletions

View File

@@ -41555,7 +41555,6 @@ package android.speech {
public abstract class RecognitionService extends android.app.Service {
ctor public RecognitionService();
method public void clearModelDownloadListener(@NonNull android.content.Intent, @NonNull android.content.AttributionSource);
method public int getMaxConcurrentSessionsCount();
method public final android.os.IBinder onBind(android.content.Intent);
method protected abstract void onCancel(android.speech.RecognitionService.Callback);
@@ -41565,7 +41564,7 @@ package android.speech {
method protected abstract void onStopListening(android.speech.RecognitionService.Callback);
method public void onTriggerModelDownload(@NonNull android.content.Intent);
method public void onTriggerModelDownload(@NonNull android.content.Intent, @NonNull android.content.AttributionSource);
method public void setModelDownloadListener(@NonNull android.content.Intent, @NonNull android.content.AttributionSource, @NonNull android.speech.ModelDownloadListener);
method public void onTriggerModelDownload(@NonNull android.content.Intent, @NonNull android.content.AttributionSource, @NonNull android.speech.ModelDownloadListener);
field public static final String SERVICE_INTERFACE = "android.speech.RecognitionService";
field public static final String SERVICE_META_DATA = "android.speech";
}
@@ -41690,18 +41689,17 @@ package android.speech {
public class SpeechRecognizer {
method @MainThread public void cancel();
method public void checkRecognitionSupport(@NonNull android.content.Intent, @NonNull java.util.concurrent.Executor, @NonNull android.speech.RecognitionSupportCallback);
method public void clearModelDownloadListener(@NonNull android.content.Intent);
method @MainThread @NonNull public static android.speech.SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull android.content.Context);
method @MainThread public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context);
method @MainThread public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context, android.content.ComponentName);
method public void destroy();
method public static boolean isOnDeviceRecognitionAvailable(@NonNull android.content.Context);
method public static boolean isRecognitionAvailable(@NonNull android.content.Context);
method public void setModelDownloadListener(@NonNull android.content.Intent, @NonNull java.util.concurrent.Executor, @NonNull android.speech.ModelDownloadListener);
method @MainThread public void setRecognitionListener(android.speech.RecognitionListener);
method @MainThread public void startListening(android.content.Intent);
method @MainThread public void stopListening();
method public void triggerModelDownload(@NonNull android.content.Intent);
method public void triggerModelDownload(@NonNull android.content.Intent, @NonNull java.util.concurrent.Executor, @NonNull android.speech.ModelDownloadListener);
field public static final String CONFIDENCE_SCORES = "confidence_scores";
field public static final String DETECTED_LANGUAGE = "detected_language";
field public static final int ERROR_AUDIO = 3; // 0x3

View File

@@ -78,23 +78,10 @@ oneway interface IRecognitionService {
* information see {@link #checkRecognitionSupport}, {@link #startListening} and
* {@link RecognizerIntent}.
*
* Progress can be monitord by calling {@link #setModelDownloadListener} before a trigger.
* Progress updates can be received via {@link #IModelDownloadListener}.
*/
void triggerModelDownload(in Intent recognizerIntent, in AttributionSource attributionSource);
/**
* Sets listener to received download progress updates. Clients still have to call
* {@link #triggerModelDownload} to trigger a model download.
*/
void setModelDownloadListener(
void triggerModelDownload(
in Intent recognizerIntent,
in AttributionSource attributionSource,
in IModelDownloadListener listener);
/**
* Clears the listener for model download events attached to a recognitionIntent if any.
*/
void clearModelDownloadListener(
in Intent recognizerIntent,
in AttributionSource attributionSource);
}

View File

@@ -22,20 +22,27 @@ package android.speech;
*/
public interface ModelDownloadListener {
/**
* Called by {@link RecognitionService} when there's an update on the download progress.
* Called by {@link RecognitionService} only if the download has started after the request.
*
* <p>RecognitionService will call this zero or more times during the download.</p>
* <p> The number of calls to this method varies depending of the {@link RecognitionService}
* implementation. If the download finished quickly enough, {@link #onSuccess()} may be called
* directly. In other cases, this method may be called any number of times during the download.
*
* @param completedPercent the percentage of download that is completed
*/
void onProgress(int completedPercent);
/**
* Called when {@link RecognitionService} completed the download and it can now be used to
* satisfy recognition requests.
* This method is called:
* <li> if the model is already available;
* <li> if the {@link RecognitionService} has started and completed the download.
*
* <p> Once this method is called, the model can be safely used to satisfy recognition requests.
*/
void onSuccess();
/**
* Called when {@link RecognitionService} scheduled the download but won't satisfy it
* Called when {@link RecognitionService} scheduled the download, but won't satisfy it
* immediately. There will be no further updates on this listener.
*/
void onScheduled();

View File

@@ -36,9 +36,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -93,10 +91,6 @@ public abstract class RecognitionService extends Service {
private static final int MSG_TRIGGER_MODEL_DOWNLOAD = 6;
private static final int MSG_SET_MODEL_DOWNLOAD_LISTENER = 7;
private static final int MSG_CLEAR_MODEL_DOWNLOAD_LISTENER = 8;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -120,21 +114,11 @@ public abstract class RecognitionService extends Service {
checkArgs.mIntent, checkArgs.callback, checkArgs.mAttributionSource);
break;
case MSG_TRIGGER_MODEL_DOWNLOAD:
Pair<Intent, AttributionSource> params =
(Pair<Intent, AttributionSource>) msg.obj;
dispatchTriggerModelDownload(params.first, params.second);
break;
case MSG_SET_MODEL_DOWNLOAD_LISTENER:
ModelDownloadListenerArgs dListenerArgs = (ModelDownloadListenerArgs) msg.obj;
dispatchSetModelDownloadListener(
dListenerArgs.mIntent,
dListenerArgs.mListener,
dListenerArgs.mAttributionSource);
break;
case MSG_CLEAR_MODEL_DOWNLOAD_LISTENER:
Pair<Intent, AttributionSource> clearDlPair =
(Pair<Intent, AttributionSource>) msg.obj;
dispatchClearModelDownloadListener(clearDlPair.first, clearDlPair.second);
ModelDownloadArgs modelDownloadArgs = (ModelDownloadArgs) msg.obj;
dispatchTriggerModelDownload(
modelDownloadArgs.mIntent,
modelDownloadArgs.mAttributionSource,
modelDownloadArgs.mListener);
break;
}
}
@@ -239,59 +223,52 @@ public abstract class RecognitionService extends Service {
private void dispatchTriggerModelDownload(
Intent intent,
AttributionSource attributionSource) {
RecognitionService.this.onTriggerModelDownload(intent, attributionSource);
}
private void dispatchSetModelDownloadListener(
Intent intent,
IModelDownloadListener listener,
AttributionSource attributionSource) {
RecognitionService.this.setModelDownloadListener(
intent,
attributionSource,
new ModelDownloadListener() {
@Override
public void onProgress(int completedPercent) {
try {
listener.onProgress(completedPercent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
AttributionSource attributionSource,
IModelDownloadListener listener) {
if (listener == null) {
RecognitionService.this.onTriggerModelDownload(intent, attributionSource);
} else {
RecognitionService.this.onTriggerModelDownload(
intent,
attributionSource,
new ModelDownloadListener() {
@Override
public void onProgress(int completedPercent) {
try {
listener.onProgress(completedPercent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
@Override
public void onSuccess() {
try {
listener.onSuccess();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@Override
public void onSuccess() {
try {
listener.onSuccess();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
@Override
public void onScheduled() {
try {
listener.onScheduled();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@Override
public void onScheduled() {
try {
listener.onScheduled();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
@Override
public void onError(int error) {
try {
listener.onError(error);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@Override
public void onError(int error) {
try {
listener.onError(error);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
}
private void dispatchClearModelDownloadListener(
Intent intent, AttributionSource attributionSource) {
RecognitionService.this.clearModelDownloadListener(intent, attributionSource);
});
}
}
private static class StartListeningArgs {
@@ -323,17 +300,18 @@ public abstract class RecognitionService extends Service {
}
}
private static class ModelDownloadListenerArgs {
private static class ModelDownloadArgs {
final Intent mIntent;
final IModelDownloadListener mListener;
final AttributionSource mAttributionSource;
@Nullable final IModelDownloadListener mListener;
private ModelDownloadListenerArgs(Intent intent,
IModelDownloadListener listener,
AttributionSource attributionSource) {
mIntent = intent;
private ModelDownloadArgs(
Intent intent,
AttributionSource attributionSource,
@Nullable IModelDownloadListener listener) {
this.mIntent = intent;
this.mAttributionSource = attributionSource;
this.mListener = listener;
mAttributionSource = attributionSource;
}
}
@@ -443,38 +421,39 @@ public abstract class RecognitionService extends Service {
}
/**
* Sets a {@link ModelDownloadListener} to receive progress updates after
* {@link #onTriggerModelDownload} calls.
* Requests the download of the recognizer support for {@code recognizerIntent}.
*
* @param recognizerIntent the request to monitor model download progress for.
* @param modelDownloadListener the listener to keep updated.
* <p> Provides the calling {@link AttributionSource} to the service implementation so that
* permissions and bandwidth could be correctly blamed.
*
* <p> Client will receive the progress updates via the given {@link ModelDownloadListener}:
*
* <li> If the model is already available, {@link ModelDownloadListener#onSuccess()} will be
* called directly. The model can be safely used afterwards.
*
* <li> If the {@link RecognitionService} has started the download,
* {@link ModelDownloadListener#onProgress(int)} will be called an unspecified (zero or more)
* number of times until the download is complete.
* When the download finishes, {@link ModelDownloadListener#onSuccess()} will be called.
* The model can be safely used afterwards.
*
* <li> If the {@link RecognitionService} has only scheduled the download, but won't satisfy it
* immediately, {@link ModelDownloadListener#onScheduled()} will be called.
* There will be no further updates on this listener.
*
* <li> If the request fails at any time due to a network or scheduling error,
* {@link ModelDownloadListener#onError(int)} will be called.
*
* @param recognizerIntent contains parameters for the recognition to be performed. The intent
* may also contain optional extras, see {@link RecognizerIntent}.
* @param attributionSource the attribution source of the caller.
* @param listener on which to receive updates about the model download request.
*/
public void setModelDownloadListener(
public void onTriggerModelDownload(
@NonNull Intent recognizerIntent,
@NonNull AttributionSource attributionSource,
@NonNull ModelDownloadListener modelDownloadListener) {
if (DBG) {
Log.i(TAG, TextUtils.formatSimple(
"#setModelDownloadListener [%s] [%s]",
recognizerIntent,
modelDownloadListener));
}
modelDownloadListener.onError(SpeechRecognizer.ERROR_CANNOT_LISTEN_TO_DOWNLOAD_EVENTS);
}
/**
* Clears the {@link ModelDownloadListener} set to receive progress updates for the given
* {@code recognizerIntent}, if any.
*
* @param recognizerIntent the request to monitor model download progress for.
*/
public void clearModelDownloadListener(
@NonNull Intent recognizerIntent,
@NonNull AttributionSource attributionSource) {
if (DBG) {
Log.i(TAG, TextUtils.formatSimple(
"#clearModelDownloadListener [%s]", recognizerIntent));
}
@NonNull ModelDownloadListener listener) {
listener.onError(SpeechRecognizer.ERROR_CANNOT_LISTEN_TO_DOWNLOAD_EVENTS);
}
@Override
@@ -815,41 +794,18 @@ public abstract class RecognitionService extends Service {
@Override
public void triggerModelDownload(
Intent recognizerIntent, @NonNull AttributionSource attributionSource) {
Intent recognizerIntent,
@NonNull AttributionSource attributionSource,
IModelDownloadListener listener) {
final RecognitionService service = mServiceRef.get();
if (service != null) {
service.mHandler.sendMessage(
Message.obtain(
service.mHandler, MSG_TRIGGER_MODEL_DOWNLOAD,
Pair.create(recognizerIntent, attributionSource)));
}
}
@Override
public void setModelDownloadListener(
Intent recognizerIntent,
AttributionSource attributionSource,
IModelDownloadListener listener) throws RemoteException {
final RecognitionService service = mServiceRef.get();
if (service != null) {
service.mHandler.sendMessage(
Message.obtain(service.mHandler, MSG_SET_MODEL_DOWNLOAD_LISTENER,
new ModelDownloadListenerArgs(
new ModelDownloadArgs(
recognizerIntent,
listener,
attributionSource)));
}
}
@Override
public void clearModelDownloadListener(
Intent recognizerIntent,
AttributionSource attributionSource) throws RemoteException {
final RecognitionService service = mServiceRef.get();
if (service != null) {
service.mHandler.sendMessage(
Message.obtain(service.mHandler, MSG_CLEAR_MODEL_DOWNLOAD_LISTENER,
Pair.create(recognizerIntent, attributionSource)));
attributionSource,
listener)));
}
}

View File

@@ -297,8 +297,6 @@ public class SpeechRecognizer {
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_SET_MODEL_DOWNLOAD_LISTENER = 8;
private static final int MSG_CLEAR_MODEL_DOWNLOAD_LISTENER = 9;
/** The actual RecognitionService endpoint */
private IRecognitionService mService;
@@ -341,19 +339,13 @@ public class SpeechRecognizer {
args.mIntent, args.mCallbackExecutor, args.mCallback);
break;
case MSG_TRIGGER_MODEL_DOWNLOAD:
handleTriggerModelDownload((Intent) msg.obj);
break;
case MSG_SET_MODEL_DOWNLOAD_LISTENER:
ModelDownloadListenerArgs modelDownloadListenerArgs =
(ModelDownloadListenerArgs) msg.obj;
handleSetModelDownloadListener(
handleTriggerModelDownload(
modelDownloadListenerArgs.mIntent,
modelDownloadListenerArgs.mExecutor,
modelDownloadListenerArgs.mModelDownloadListener);
break;
case MSG_CLEAR_MODEL_DOWNLOAD_LISTENER:
handleClearModelDownloadListener((Intent) msg.obj);
break;
}
}
};
@@ -657,17 +649,13 @@ public class SpeechRecognizer {
* user interaction to approve the download. Callers can verify the status of the request via
* {@link #checkRecognitionSupport(Intent, Executor, RecognitionSupportCallback)}.
*
* <p>Listeners set via
* {@link #setModelDownloadListener(Intent, Executor, ModelDownloadListener)} will receive
* updates about this download request.</p>
*
* @param recognizerIntent contains parameters for the recognition to be performed. The intent
* may also contain optional extras, see {@link RecognizerIntent}.
*/
public void triggerModelDownload(@NonNull Intent recognizerIntent) {
Objects.requireNonNull(recognizerIntent, "intent must not be null");
if (DBG) {
Slog.i(TAG, "#triggerModelDownload called");
Slog.i(TAG, "#triggerModelDownload without a listener called");
if (mService == null) {
Slog.i(TAG, "Connection is not established yet");
}
@@ -676,23 +664,47 @@ public class SpeechRecognizer {
// First time connection: first establish a connection, then dispatch.
connectToSystemService();
}
putMessage(Message.obtain(mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, recognizerIntent));
putMessage(Message.obtain(
mHandler, MSG_TRIGGER_MODEL_DOWNLOAD,
new ModelDownloadListenerArgs(recognizerIntent, null, null)));
}
/**
* Sets a listener to model download updates. Clients will have to call this method before
* {@link #triggerModelDownload(Intent)}.
* Attempts to download the support for the given {@code recognizerIntent}. This might trigger
* user interaction to approve the download. Callers can verify the status of the request via
* {@link #checkRecognitionSupport(Intent, Executor, RecognitionSupportCallback)}.
*
* @param recognizerIntent the request to monitor support for.
* <p> The updates about the model download request are received via the given
* {@link ModelDownloadListener}:
*
* <li> If the model is already available, {@link ModelDownloadListener#onSuccess()} will be
* called directly. The model can be safely used afterwards.
*
* <li> If the {@link RecognitionService} has started the download,
* {@link ModelDownloadListener#onProgress(int)} will be called an unspecified (zero or more)
* number of times until the download is complete.
* When the download finishes, {@link ModelDownloadListener#onSuccess()} will be called.
* The model can be safely used afterwards.
*
* <li> If the {@link RecognitionService} has only scheduled the download, but won't satisfy it
* immediately, {@link ModelDownloadListener#onScheduled()} will be called.
* There will be no further updates on this listener.
*
* <li> If the request fails at any time due to a network or scheduling error,
* {@link ModelDownloadListener#onError(int)} will be called.
*
* @param recognizerIntent contains parameters for the recognition to be performed. The intent
* may also contain optional extras, see {@link RecognizerIntent}.
* @param executor for dispatching listener callbacks
* @param listener on which to receive updates about the model download request.
*/
public void setModelDownloadListener(
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, "#setModelDownloadListener called");
Slog.i(TAG, "#triggerModelDownload with a listener called");
if (mService == null) {
Slog.i(TAG, "Connection is not established yet");
}
@@ -702,31 +714,10 @@ public class SpeechRecognizer {
connectToSystemService();
}
putMessage(Message.obtain(
mHandler, MSG_SET_MODEL_DOWNLOAD_LISTENER,
mHandler, MSG_TRIGGER_MODEL_DOWNLOAD,
new ModelDownloadListenerArgs(recognizerIntent, executor, listener)));
}
/**
* Clears the listener for model download updates if any.
*
* @param recognizerIntent the request to monitor support for.
*/
public void clearModelDownloadListener(@NonNull Intent recognizerIntent) {
Objects.requireNonNull(recognizerIntent, "intent must not be null");
if (DBG) {
Slog.i(TAG, "#clearModelDownloadListener 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_CLEAR_MODEL_DOWNLOAD_LISTENER, recognizerIntent));
}
/**
* Sets a temporary component to power on-device speech recognizer.
*
@@ -836,51 +827,36 @@ public class SpeechRecognizer {
}
}
private void handleTriggerModelDownload(Intent recognizerIntent) {
if (!maybeInitializeManagerService()) {
return;
}
try {
mService.triggerModelDownload(recognizerIntent, mContext.getAttributionSource());
} catch (final RemoteException e) {
Log.e(TAG, "downloadModel() failed", e);
mListener.onError(ERROR_CLIENT);
}
}
private void handleSetModelDownloadListener(
private void handleTriggerModelDownload(
Intent recognizerIntent,
Executor callbackExecutor,
@Nullable Executor callbackExecutor,
@Nullable ModelDownloadListener modelDownloadListener) {
if (!maybeInitializeManagerService()) {
return;
}
try {
InternalModelDownloadListener listener =
modelDownloadListener == null
? null
: new InternalModelDownloadListener(
callbackExecutor,
modelDownloadListener);
mService.setModelDownloadListener(
recognizerIntent, mContext.getAttributionSource(), listener);
if (DBG) Log.d(TAG, "setModelDownloadListener()");
} catch (final RemoteException e) {
Log.e(TAG, "setModelDownloadListener() failed", e);
callbackExecutor.execute(() -> modelDownloadListener.onError(ERROR_CLIENT));
}
}
private void handleClearModelDownloadListener(Intent recognizerIntent) {
if (!maybeInitializeManagerService()) {
return;
// Trigger model download without a listener.
if (modelDownloadListener == null) {
try {
mService.triggerModelDownload(
recognizerIntent, mContext.getAttributionSource(), null);
if (DBG) Log.d(TAG, "triggerModelDownload() without a listener");
} catch (final RemoteException e) {
Log.e(TAG, "triggerModelDownload() without a listener failed", e);
mListener.onError(ERROR_CLIENT);
}
}
try {
mService.clearModelDownloadListener(
recognizerIntent, mContext.getAttributionSource());
if (DBG) Log.d(TAG, "clearModelDownloadListener()");
} catch (final RemoteException e) {
Log.e(TAG, "clearModelDownloadListener() failed", e);
// Trigger model download with a listener.
else {
try {
mService.triggerModelDownload(
recognizerIntent, mContext.getAttributionSource(),
new InternalModelDownloadListener(callbackExecutor, modelDownloadListener));
if (DBG) Log.d(TAG, "triggerModelDownload() with a listener");
} catch (final RemoteException e) {
Log.e(TAG, "triggerModelDownload() with a listener failed", e);
callbackExecutor.execute(() -> modelDownloadListener.onError(ERROR_CLIENT));
}
}
}

View File

@@ -250,15 +250,7 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn
service.checkRecognitionSupport(recognizerIntent, attributionSource, callback));
}
void triggerModelDownload(Intent recognizerIntent, AttributionSource attributionSource) {
if (!mConnected) {
Slog.e(TAG, "#downloadModel failed due to connection.");
return;
}
run(service -> service.triggerModelDownload(recognizerIntent, attributionSource));
}
void setModelDownloadListener(
void triggerModelDownload(
Intent recognizerIntent,
AttributionSource attributionSource,
IModelDownloadListener listener) {
@@ -266,25 +258,12 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn
try {
listener.onError(SpeechRecognizer.ERROR_SERVER_DISCONNECTED);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report the connection broke to the caller.", e);
Slog.w(TAG, "#downloadModel failed due to connection.", e);
e.printStackTrace();
}
return;
}
run(service ->
service.setModelDownloadListener(recognizerIntent, attributionSource, listener));
}
void clearModelDownloadListener(
Intent recognizerIntent,
AttributionSource attributionSource) {
if (!mConnected) {
return;
}
run(service ->
service.clearModelDownloadListener(recognizerIntent, attributionSource));
run(service -> service.triggerModelDownload(recognizerIntent, attributionSource, listener));
}
void shutdown(IBinder clientToken) {

View File

@@ -192,26 +192,12 @@ final class SpeechRecognitionManagerServiceImpl extends
@Override
public void triggerModelDownload(
Intent recognizerIntent,
AttributionSource attributionSource) {
service.triggerModelDownload(recognizerIntent, attributionSource);
}
@Override
public void setModelDownloadListener(
Intent recognizerIntent,
AttributionSource attributionSource,
IModelDownloadListener listener) throws RemoteException {
service.setModelDownloadListener(
IModelDownloadListener listener) {
service.triggerModelDownload(
recognizerIntent, attributionSource, listener);
}
@Override
public void clearModelDownloadListener(
Intent recognizerIntent,
AttributionSource attributionSource) throws RemoteException {
service.clearModelDownloadListener(recognizerIntent, attributionSource);
}
});
} catch (RemoteException e) {
Slog.e(TAG, "Error creating a speech recognition session", e);