Loading core/api/current.txt +2 −4 Original line number Diff line number Diff line Loading @@ -41558,7 +41558,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); Loading @@ -41568,7 +41567,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"; } Loading Loading @@ -41693,18 +41692,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 core/java/android/speech/IRecognitionService.aidl +2 −15 Original line number Diff line number Diff line Loading @@ -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); } core/java/android/speech/ModelDownloadListener.java +12 −5 Original line number Diff line number Diff line Loading @@ -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(); Loading core/java/android/speech/RecognitionService.java +87 −131 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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; } } Loading Loading @@ -239,15 +223,12 @@ public abstract class RecognitionService extends Service { private void dispatchTriggerModelDownload( Intent intent, AttributionSource attributionSource) { AttributionSource attributionSource, IModelDownloadListener listener) { if (listener == null) { RecognitionService.this.onTriggerModelDownload(intent, attributionSource); } private void dispatchSetModelDownloadListener( Intent intent, IModelDownloadListener listener, AttributionSource attributionSource) { RecognitionService.this.setModelDownloadListener( } else { RecognitionService.this.onTriggerModelDownload( intent, attributionSource, new ModelDownloadListener() { Loading Loading @@ -288,10 +269,6 @@ public abstract class RecognitionService extends Service { } }); } private void dispatchClearModelDownloadListener( Intent intent, AttributionSource attributionSource) { RecognitionService.this.clearModelDownloadListener(intent, attributionSource); } private static class StartListeningArgs { Loading Loading @@ -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; } } Loading Loading @@ -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. */ public void setModelDownloadListener( @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. * <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. * * @param recognizerIntent the request to monitor model download progress for. * <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 clearModelDownloadListener( public void onTriggerModelDownload( @NonNull Intent recognizerIntent, @NonNull AttributionSource attributionSource) { if (DBG) { Log.i(TAG, TextUtils.formatSimple( "#clearModelDownloadListener [%s]", recognizerIntent)); } @NonNull AttributionSource attributionSource, @NonNull ModelDownloadListener listener) { listener.onError(SpeechRecognizer.ERROR_CANNOT_LISTEN_TO_DOWNLOAD_EVENTS); } @Override Loading Loading @@ -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))); } } Loading core/java/android/speech/SpeechRecognizer.java +56 −80 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } } }; Loading Loading @@ -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"); } Loading @@ -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)}. * * <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 the request to monitor support for. * @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"); } Loading @@ -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. * Loading Loading @@ -836,52 +827,37 @@ public class SpeechRecognizer { } } private void handleTriggerModelDownload(Intent recognizerIntent) { private void handleTriggerModelDownload( Intent recognizerIntent, @Nullable Executor callbackExecutor, @Nullable ModelDownloadListener modelDownloadListener) { if (!maybeInitializeManagerService()) { return; } // Trigger model download without a listener. if (modelDownloadListener == null) { try { mService.triggerModelDownload(recognizerIntent, mContext.getAttributionSource()); mService.triggerModelDownload( recognizerIntent, mContext.getAttributionSource(), null); if (DBG) Log.d(TAG, "triggerModelDownload() without a listener"); } catch (final RemoteException e) { Log.e(TAG, "downloadModel() failed", e); Log.e(TAG, "triggerModelDownload() without a listener failed", e); mListener.onError(ERROR_CLIENT); } } private void handleSetModelDownloadListener( Intent recognizerIntent, Executor callbackExecutor, @Nullable ModelDownloadListener modelDownloadListener) { if (!maybeInitializeManagerService()) { return; } // Trigger model download with a listener. else { try { InternalModelDownloadListener listener = modelDownloadListener == null ? null : new InternalModelDownloadListener( callbackExecutor, modelDownloadListener); mService.setModelDownloadListener( recognizerIntent, mContext.getAttributionSource(), listener); if (DBG) Log.d(TAG, "setModelDownloadListener()"); 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, "setModelDownloadListener() failed", e); Log.e(TAG, "triggerModelDownload() with a listener failed", e); callbackExecutor.execute(() -> modelDownloadListener.onError(ERROR_CLIENT)); } } private void handleClearModelDownloadListener(Intent recognizerIntent) { if (!maybeInitializeManagerService()) { return; } try { mService.clearModelDownloadListener( recognizerIntent, mContext.getAttributionSource()); if (DBG) Log.d(TAG, "clearModelDownloadListener()"); } catch (final RemoteException e) { Log.e(TAG, "clearModelDownloadListener() failed", e); } } private boolean checkOpenConnection() { Loading Loading
core/api/current.txt +2 −4 Original line number Diff line number Diff line Loading @@ -41558,7 +41558,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); Loading @@ -41568,7 +41567,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"; } Loading Loading @@ -41693,18 +41692,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
core/java/android/speech/IRecognitionService.aidl +2 −15 Original line number Diff line number Diff line Loading @@ -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); }
core/java/android/speech/ModelDownloadListener.java +12 −5 Original line number Diff line number Diff line Loading @@ -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(); Loading
core/java/android/speech/RecognitionService.java +87 −131 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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; } } Loading Loading @@ -239,15 +223,12 @@ public abstract class RecognitionService extends Service { private void dispatchTriggerModelDownload( Intent intent, AttributionSource attributionSource) { AttributionSource attributionSource, IModelDownloadListener listener) { if (listener == null) { RecognitionService.this.onTriggerModelDownload(intent, attributionSource); } private void dispatchSetModelDownloadListener( Intent intent, IModelDownloadListener listener, AttributionSource attributionSource) { RecognitionService.this.setModelDownloadListener( } else { RecognitionService.this.onTriggerModelDownload( intent, attributionSource, new ModelDownloadListener() { Loading Loading @@ -288,10 +269,6 @@ public abstract class RecognitionService extends Service { } }); } private void dispatchClearModelDownloadListener( Intent intent, AttributionSource attributionSource) { RecognitionService.this.clearModelDownloadListener(intent, attributionSource); } private static class StartListeningArgs { Loading Loading @@ -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; } } Loading Loading @@ -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. */ public void setModelDownloadListener( @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. * <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. * * @param recognizerIntent the request to monitor model download progress for. * <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 clearModelDownloadListener( public void onTriggerModelDownload( @NonNull Intent recognizerIntent, @NonNull AttributionSource attributionSource) { if (DBG) { Log.i(TAG, TextUtils.formatSimple( "#clearModelDownloadListener [%s]", recognizerIntent)); } @NonNull AttributionSource attributionSource, @NonNull ModelDownloadListener listener) { listener.onError(SpeechRecognizer.ERROR_CANNOT_LISTEN_TO_DOWNLOAD_EVENTS); } @Override Loading Loading @@ -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))); } } Loading
core/java/android/speech/SpeechRecognizer.java +56 −80 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } } }; Loading Loading @@ -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"); } Loading @@ -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)}. * * <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 the request to monitor support for. * @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"); } Loading @@ -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. * Loading Loading @@ -836,52 +827,37 @@ public class SpeechRecognizer { } } private void handleTriggerModelDownload(Intent recognizerIntent) { private void handleTriggerModelDownload( Intent recognizerIntent, @Nullable Executor callbackExecutor, @Nullable ModelDownloadListener modelDownloadListener) { if (!maybeInitializeManagerService()) { return; } // Trigger model download without a listener. if (modelDownloadListener == null) { try { mService.triggerModelDownload(recognizerIntent, mContext.getAttributionSource()); mService.triggerModelDownload( recognizerIntent, mContext.getAttributionSource(), null); if (DBG) Log.d(TAG, "triggerModelDownload() without a listener"); } catch (final RemoteException e) { Log.e(TAG, "downloadModel() failed", e); Log.e(TAG, "triggerModelDownload() without a listener failed", e); mListener.onError(ERROR_CLIENT); } } private void handleSetModelDownloadListener( Intent recognizerIntent, Executor callbackExecutor, @Nullable ModelDownloadListener modelDownloadListener) { if (!maybeInitializeManagerService()) { return; } // Trigger model download with a listener. else { try { InternalModelDownloadListener listener = modelDownloadListener == null ? null : new InternalModelDownloadListener( callbackExecutor, modelDownloadListener); mService.setModelDownloadListener( recognizerIntent, mContext.getAttributionSource(), listener); if (DBG) Log.d(TAG, "setModelDownloadListener()"); 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, "setModelDownloadListener() failed", e); Log.e(TAG, "triggerModelDownload() with a listener failed", e); callbackExecutor.execute(() -> modelDownloadListener.onError(ERROR_CLIENT)); } } private void handleClearModelDownloadListener(Intent recognizerIntent) { if (!maybeInitializeManagerService()) { return; } try { mService.clearModelDownloadListener( recognizerIntent, mContext.getAttributionSource()); if (DBG) Log.d(TAG, "clearModelDownloadListener()"); } catch (final RemoteException e) { Log.e(TAG, "clearModelDownloadListener() failed", e); } } private boolean checkOpenConnection() { Loading