diff --git a/core/api/current.txt b/core/api/current.txt index 0af5918e444b3..ef1d9efa6cda2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39181,19 +39181,21 @@ package android.speech { } public class SpeechRecognizer { - method public void cancel(); - method @NonNull public static android.speech.SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull android.content.Context); - method public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context); - method public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context, android.content.ComponentName); + method @MainThread public void cancel(); + 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 isRecognitionAvailable(android.content.Context); - method public void setRecognitionListener(android.speech.RecognitionListener); - method public void startListening(android.content.Intent); - method public void stopListening(); + method @MainThread public void setRecognitionListener(android.speech.RecognitionListener); + method @MainThread public void startListening(android.content.Intent); + method @MainThread public void stopListening(); field public static final String CONFIDENCE_SCORES = "confidence_scores"; field public static final int ERROR_AUDIO = 3; // 0x3 field public static final int ERROR_CLIENT = 5; // 0x5 field public static final int ERROR_INSUFFICIENT_PERMISSIONS = 9; // 0x9 + field public static final int ERROR_LANGUAGE_NOT_SUPPORTED = 12; // 0xc + field public static final int ERROR_LANGUAGE_UNAVAILABLE = 13; // 0xd field public static final int ERROR_NETWORK = 2; // 0x2 field public static final int ERROR_NETWORK_TIMEOUT = 1; // 0x1 field public static final int ERROR_NO_MATCH = 7; // 0x7 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 69f923c8447e5..51657ef9c7664 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2313,7 +2313,7 @@ package android.service.watchdog { package android.speech { public class SpeechRecognizer { - method public void setTemporaryOnDeviceRecognizer(@Nullable android.content.ComponentName); + method @RequiresPermission(android.Manifest.permission.MANAGE_SPEECH_RECOGNITION) public void setTemporaryOnDeviceRecognizer(@Nullable android.content.ComponentName); } } diff --git a/core/java/android/speech/RecognitionListener.java b/core/java/android/speech/RecognitionListener.java index 1ffdf0823f5f7..07bd9eae864b0 100644 --- a/core/java/android/speech/RecognitionListener.java +++ b/core/java/android/speech/RecognitionListener.java @@ -24,6 +24,7 @@ import android.os.Bundle; * Application main thread. */ public interface RecognitionListener { + /** * Called when the endpointer is ready for the user to start speaking. * @@ -63,7 +64,7 @@ public interface RecognitionListener { * * @param error code is defined in {@link SpeechRecognizer} */ - void onError(int error); + void onError(@SpeechRecognizer.RecognitionError int error); /** * Called when recognition results are ready. diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index 4afa94735d62b..ad670c8182b91 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -24,6 +24,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.app.AppOpsManager; import android.app.Service; +import android.content.AttributionSource; import android.content.Context; import android.content.ContextParams; import android.content.Intent; @@ -33,7 +34,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; -import android.content.AttributionSource; import android.os.Process; import android.os.RemoteException; import android.util.Log; @@ -297,7 +297,7 @@ public abstract class RecognitionService extends Service { * * @param error code is defined in {@link SpeechRecognizer} */ - public void error(int error) throws RemoteException { + public void error(@SpeechRecognizer.RecognitionError int error) throws RemoteException { Message.obtain(mHandler, MSG_RESET).sendToTarget(); mListener.onError(error); } diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java index 9a855f30a3732..b9920072271f5 100644 --- a/core/java/android/speech/SpeechRecognizer.java +++ b/core/java/android/speech/SpeechRecognizer.java @@ -16,8 +16,12 @@ package android.speech; +import android.Manifest; +import android.annotation.IntDef; +import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.content.ComponentName; import android.content.Context; @@ -36,6 +40,9 @@ import android.text.TextUtils; import android.util.Log; import android.util.Slog; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; @@ -83,6 +90,30 @@ public class SpeechRecognizer { */ public static final String CONFIDENCE_SCORES = "confidence_scores"; + /** + * The reason speech recognition failed. + * + * @hide + */ + @Documented + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"ERROR_"}, value = { + ERROR_NETWORK_TIMEOUT, + ERROR_NETWORK, + ERROR_AUDIO, + ERROR_SERVER, + ERROR_CLIENT, + ERROR_SPEECH_TIMEOUT, + ERROR_NO_MATCH, + ERROR_RECOGNIZER_BUSY, + ERROR_INSUFFICIENT_PERMISSIONS, + ERROR_TOO_MANY_REQUESTS, + ERROR_SERVER_DISCONNECTED, + ERROR_LANGUAGE_NOT_SUPPORTED, + ERROR_LANGUAGE_UNAVAILABLE + }) + public @interface RecognitionError {} + /** Network operation timed out. */ public static final int ERROR_NETWORK_TIMEOUT = 1; @@ -116,6 +147,12 @@ public class SpeechRecognizer { /** Server has been disconnected, e.g. because the app has crashed. */ public static final int ERROR_SERVER_DISCONNECTED = 11; + /** Requested language is not available to be used with the current recognizer. */ + public static final int ERROR_LANGUAGE_NOT_SUPPORTED = 12; + + /** Requested language is supported, but not available currently (e.g. not downloaded yet). */ + public static final int ERROR_LANGUAGE_UNAVAILABLE = 13; + /** action codes */ private static final int MSG_START = 1; private static final int MSG_STOP = 2; @@ -228,6 +265,7 @@ public class SpeechRecognizer { * @param context in which to create {@code SpeechRecognizer} * @return a new {@code SpeechRecognizer} */ + @MainThread public static SpeechRecognizer createSpeechRecognizer(final Context context) { return createSpeechRecognizer(context, null); } @@ -259,6 +297,7 @@ public class SpeechRecognizer { * {@code SpeechRecognizer} to * @return a new {@code SpeechRecognizer} */ + @MainThread public static SpeechRecognizer createSpeechRecognizer(final Context context, final ComponentName serviceComponent) { if (context == null) { @@ -279,6 +318,7 @@ public class SpeechRecognizer { * @return a new on-device {@code SpeechRecognizer}. */ @NonNull + @MainThread public static SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull final Context context) { if (context == null) { throw new IllegalArgumentException("Context cannot be null"); @@ -295,6 +335,7 @@ public class SpeechRecognizer { * @param listener listener that will receive all the callbacks from the created * {@link SpeechRecognizer}, this must not be null. */ + @MainThread public void setRecognitionListener(RecognitionListener listener) { checkIsCalledFromMainThread(); putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener)); @@ -309,6 +350,7 @@ public class SpeechRecognizer { * may also contain optional extras, see {@link RecognizerIntent}. If these values are * not set explicitly, default values will be used by the recognizer. */ + @MainThread public void startListening(final Intent recognizerIntent) { if (recognizerIntent == null) { throw new IllegalArgumentException("intent must not be null"); @@ -348,6 +390,7 @@ public class SpeechRecognizer { * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise * no notifications will be received. */ + @MainThread public void stopListening() { checkIsCalledFromMainThread(); @@ -366,6 +409,7 @@ public class SpeechRecognizer { * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise * no notifications will be received. */ + @MainThread public void cancel() { checkIsCalledFromMainThread(); putMessage(Message.obtain(mHandler, MSG_CANCEL)); @@ -382,6 +426,7 @@ public class SpeechRecognizer { * @hide */ @TestApi + @RequiresPermission(Manifest.permission.MANAGE_SPEECH_RECOGNITION) public void setTemporaryOnDeviceRecognizer(@Nullable ComponentName componentName) { mHandler.sendMessage( Message.obtain(mHandler, MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT, componentName));