speech: Add api to check request is supported
Bug: 204189031 CTS-Coverage-Bug: 208776893 Test: atest, new tests TBD Change-Id: Id3d7df47f52efc31227edb577db44b9e4ca04265
This commit is contained in:
@@ -39859,8 +39859,10 @@ package android.speech {
|
||||
ctor public RecognitionService();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method protected abstract void onCancel(android.speech.RecognitionService.Callback);
|
||||
method public void onCheckRecognitionSupport(@NonNull android.content.Intent, @NonNull android.speech.RecognitionService.SupportCallback);
|
||||
method protected abstract void onStartListening(android.content.Intent, android.speech.RecognitionService.Callback);
|
||||
method protected abstract void onStopListening(android.speech.RecognitionService.Callback);
|
||||
method public void triggerModelDownload(@NonNull android.content.Intent);
|
||||
field public static final String SERVICE_INTERFACE = "android.speech.RecognitionService";
|
||||
field public static final String SERVICE_META_DATA = "android.speech";
|
||||
}
|
||||
@@ -39878,6 +39880,36 @@ package android.speech {
|
||||
method public void rmsChanged(float) throws android.os.RemoteException;
|
||||
}
|
||||
|
||||
public static class RecognitionService.SupportCallback {
|
||||
method public void onError(int);
|
||||
method public void onSupportResult(@NonNull android.speech.RecognitionSupport);
|
||||
}
|
||||
|
||||
public final class RecognitionSupport implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public java.util.List<java.lang.String> getInstalledLanguages();
|
||||
method @NonNull public java.util.List<java.lang.String> getPendingLanguages();
|
||||
method @NonNull public java.util.List<java.lang.String> getSupportedLanguages();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.speech.RecognitionSupport> CREATOR;
|
||||
}
|
||||
|
||||
public static final class RecognitionSupport.Builder {
|
||||
ctor public RecognitionSupport.Builder();
|
||||
method @NonNull public android.speech.RecognitionSupport.Builder addInstalledLanguages(@NonNull String);
|
||||
method @NonNull public android.speech.RecognitionSupport.Builder addPendingLanguages(@NonNull String);
|
||||
method @NonNull public android.speech.RecognitionSupport.Builder addSupportedLanguages(@NonNull String);
|
||||
method @NonNull public android.speech.RecognitionSupport build();
|
||||
method @NonNull public android.speech.RecognitionSupport.Builder setInstalledLanguages(@NonNull java.util.List<java.lang.String>);
|
||||
method @NonNull public android.speech.RecognitionSupport.Builder setPendingLanguages(@NonNull java.util.List<java.lang.String>);
|
||||
method @NonNull public android.speech.RecognitionSupport.Builder setSupportedLanguages(@NonNull java.util.List<java.lang.String>);
|
||||
}
|
||||
|
||||
public interface RecognitionSupportCallback {
|
||||
method public void onError(int);
|
||||
method public void onSupportResult(@NonNull android.speech.RecognitionSupport);
|
||||
}
|
||||
|
||||
public class RecognizerIntent {
|
||||
method public static final android.content.Intent getVoiceDetailsIntent(android.content.Context);
|
||||
field public static final String ACTION_GET_LANGUAGE_DETAILS = "android.speech.action.GET_LANGUAGE_DETAILS";
|
||||
@@ -39927,6 +39959,7 @@ package android.speech {
|
||||
|
||||
public class SpeechRecognizer {
|
||||
method @MainThread public void cancel();
|
||||
method public void checkRecognitionSupport(@NonNull android.content.Intent, @NonNull android.speech.RecognitionSupportCallback);
|
||||
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);
|
||||
@@ -39936,8 +39969,10 @@ package android.speech {
|
||||
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);
|
||||
field public static final String CONFIDENCE_SCORES = "confidence_scores";
|
||||
field public static final int ERROR_AUDIO = 3; // 0x3
|
||||
field public static final int ERROR_CANNOT_CHECK_SUPPORT = 14; // 0xe
|
||||
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
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.os.Bundle;
|
||||
import android.content.AttributionSource;
|
||||
import android.content.Intent;
|
||||
import android.speech.IRecognitionListener;
|
||||
import android.speech.IRecognitionSupportCallback;
|
||||
|
||||
/**
|
||||
* A Service interface to speech recognition. Call startListening when
|
||||
@@ -60,4 +61,18 @@ oneway interface IRecognitionService {
|
||||
* @param listener to receive callbacks, note that this must be non-null
|
||||
*/
|
||||
void cancel(in IRecognitionListener listener, boolean isShutdown);
|
||||
|
||||
/**
|
||||
* Checks whether this RecognitionService could {@link #startListening} successfully on the
|
||||
* given recognizerIntent. For more information see {@link #startListening} and
|
||||
* {@link RecognizerIntent}.
|
||||
*/
|
||||
void checkRecognitionSupport(in Intent recognizerIntent, in IRecognitionSupportCallback listener);
|
||||
|
||||
/**
|
||||
* Requests RecognitionService to download the support for the given recognizerIntent. For more
|
||||
* information see {@link #checkRecognitionSupport}, {@link #startListening} and
|
||||
* {@link RecognizerIntent}.
|
||||
*/
|
||||
void triggerModelDownload(in Intent recognizerIntent);
|
||||
}
|
||||
|
||||
37
core/java/android/speech/IRecognitionSupportCallback.aidl
Normal file
37
core/java/android/speech/IRecognitionSupportCallback.aidl
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.os.Bundle;
|
||||
import android.speech.RecognitionSupport;
|
||||
|
||||
/**
|
||||
* Callback for speech recognition support checks, used with RecognitionService.
|
||||
* This provides the {@link RecognitionSupport} for a given recognition request, callers can use
|
||||
* it to check whether RecognitionService can fulfill a given recognition request.
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface IRecognitionSupportCallback {
|
||||
void onSupportResult(in RecognitionSupport recognitionSupport);
|
||||
|
||||
/**
|
||||
* A network or recognition error occurred.
|
||||
*
|
||||
* @param error code is defined in {@link SpeechRecognizer}
|
||||
*/
|
||||
void onError(in int error);
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
|
||||
@@ -90,6 +91,10 @@ public abstract class RecognitionService extends Service {
|
||||
|
||||
private static final int MSG_RESET = 4;
|
||||
|
||||
private static final int MSG_CHECK_RECOGNITION_SUPPORT = 5;
|
||||
|
||||
private static final int MSG_TRIGGER_MODEL_DOWNLOAD = 6;
|
||||
|
||||
private final Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
@@ -107,6 +112,15 @@ public abstract class RecognitionService extends Service {
|
||||
case MSG_RESET:
|
||||
dispatchClearCallback();
|
||||
break;
|
||||
case MSG_CHECK_RECOGNITION_SUPPORT:
|
||||
Pair<Intent, IRecognitionSupportCallback> intentAndListener =
|
||||
(Pair<Intent, IRecognitionSupportCallback>) msg.obj;
|
||||
dispatchCheckRecognitionSupport(
|
||||
intentAndListener.first, intentAndListener.second);
|
||||
break;
|
||||
case MSG_TRIGGER_MODEL_DOWNLOAD:
|
||||
dispatchTriggerModelDownload((Intent) msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -179,6 +193,15 @@ public abstract class RecognitionService extends Service {
|
||||
mStartedDataDelivery = false;
|
||||
}
|
||||
|
||||
private void dispatchCheckRecognitionSupport(
|
||||
Intent intent, IRecognitionSupportCallback callback) {
|
||||
RecognitionService.this.onCheckRecognitionSupport(intent, new SupportCallback(callback));
|
||||
}
|
||||
|
||||
private void dispatchTriggerModelDownload(Intent intent) {
|
||||
RecognitionService.this.triggerModelDownload(intent);
|
||||
}
|
||||
|
||||
private class StartListeningArgs {
|
||||
public final Intent mIntent;
|
||||
|
||||
@@ -238,6 +261,34 @@ public abstract class RecognitionService extends Service {
|
||||
*/
|
||||
protected abstract void onStopListening(Callback listener);
|
||||
|
||||
/**
|
||||
* Queries the service on whether it would support a {@link #onStartListening(Intent, Callback)}
|
||||
* for the same {@code recognizerIntent}.
|
||||
*
|
||||
* <p>The service will notify the caller about the level of support or error via
|
||||
* {@link SupportCallback}.
|
||||
*
|
||||
* <p>If the service does not offer the support check it will notify the caller with
|
||||
* {@link SpeechRecognizer#ERROR_CANNOT_CHECK_SUPPORT}.
|
||||
*/
|
||||
public void onCheckRecognitionSupport(
|
||||
@NonNull Intent recognizerIntent,
|
||||
@NonNull SupportCallback supportCallback) {
|
||||
if (DBG) {
|
||||
Log.i(TAG, String.format("#onSupports [%s]", recognizerIntent));
|
||||
}
|
||||
supportCallback.onError(SpeechRecognizer.ERROR_CANNOT_CHECK_SUPPORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the download of the recognizer support for {@code recognizerIntent}.
|
||||
*/
|
||||
public void triggerModelDownload(@NonNull Intent recognizerIntent) {
|
||||
if (DBG) {
|
||||
Log.i(TAG, String.format("#downloadModel [%s]", recognizerIntent));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("MissingNullability")
|
||||
public Context createContext(@NonNull ContextParams contextParams) {
|
||||
@@ -410,7 +461,45 @@ public abstract class RecognitionService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
/** Binder of the recognition service */
|
||||
/**
|
||||
* This class receives callbacks from the speech recognition service and forwards them to the
|
||||
* user. An instance of this class is passed to the
|
||||
* {@link RecognitionService#onCheckRecognitionSupport(Intent, SupportCallback)} method. Recognizers may call
|
||||
* these methods on any thread.
|
||||
*/
|
||||
public static class SupportCallback {
|
||||
|
||||
private final IRecognitionSupportCallback mCallback;
|
||||
|
||||
private SupportCallback(IRecognitionSupportCallback callback) {
|
||||
this.mCallback = callback;
|
||||
}
|
||||
|
||||
/** The service should call this method to notify the caller about the level of support. */
|
||||
public void onSupportResult(@NonNull RecognitionSupport recognitionSupport) {
|
||||
try {
|
||||
mCallback.onSupportResult(recognitionSupport);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The service should call this method when an error occurred and can't satisfy the support
|
||||
* request.
|
||||
*
|
||||
* @param errorCode code is defined in {@link SpeechRecognizer}
|
||||
*/
|
||||
public void onError(@SpeechRecognizer.RecognitionError int errorCode) {
|
||||
try {
|
||||
mCallback.onError(errorCode);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Binder of the recognition service */
|
||||
private static final class RecognitionServiceBinder extends IRecognitionService.Stub {
|
||||
private final WeakReference<RecognitionService> mServiceRef;
|
||||
|
||||
@@ -452,6 +541,27 @@ public abstract class RecognitionService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkRecognitionSupport(
|
||||
Intent recognizerIntent, IRecognitionSupportCallback callback) {
|
||||
final RecognitionService service = mServiceRef.get();
|
||||
if (service != null) {
|
||||
service.mHandler.sendMessage(
|
||||
Message.obtain(service.mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
|
||||
Pair.create(recognizerIntent, callback)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerModelDownload(Intent recognizerIntent) {
|
||||
final RecognitionService service = mServiceRef.get();
|
||||
if (service != null) {
|
||||
service.mHandler.sendMessage(
|
||||
Message.obtain(
|
||||
service.mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, recognizerIntent));
|
||||
}
|
||||
}
|
||||
|
||||
public void clearReference() {
|
||||
mServiceRef.clear();
|
||||
}
|
||||
|
||||
19
core/java/android/speech/RecognitionSupport.aidl
Normal file
19
core/java/android/speech/RecognitionSupport.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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;
|
||||
|
||||
parcelable RecognitionSupport;
|
||||
328
core/java/android/speech/RecognitionSupport.java
Normal file
328
core/java/android/speech/RecognitionSupport.java
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.annotation.NonNull;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.DataClass;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Encodes the level of support for a given speech recognition request */
|
||||
@DataClass(
|
||||
genConstructor = false,
|
||||
genBuilder = true,
|
||||
genEqualsHashCode = true,
|
||||
genHiddenConstDefs = true,
|
||||
genParcelable = true,
|
||||
genToString = true
|
||||
)
|
||||
public final class RecognitionSupport implements Parcelable {
|
||||
|
||||
/** Support for this request is ready for use on this device for the returned languages. */
|
||||
@NonNull
|
||||
private List<String> mInstalledLanguages = null;
|
||||
|
||||
/** Support for this request is scheduled for download for the returned languages. */
|
||||
@NonNull private List<String> mPendingLanguages = null;
|
||||
|
||||
/** These languages are supported but need to be downloaded before use. */
|
||||
@NonNull
|
||||
private List<String> mSupportedLanguages = null;
|
||||
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.23.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
//
|
||||
// To regenerate run:
|
||||
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/speech/RecognitionSupport.java
|
||||
//
|
||||
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
|
||||
// Settings > Editor > Code Style > Formatter Control
|
||||
//@formatter:off
|
||||
|
||||
|
||||
@DataClass.Generated.Member
|
||||
/* package-private */ RecognitionSupport(
|
||||
@NonNull List<String> installedLanguages,
|
||||
@NonNull List<String> pendingLanguages,
|
||||
@NonNull List<String> supportedLanguages) {
|
||||
this.mInstalledLanguages = installedLanguages;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mInstalledLanguages);
|
||||
this.mPendingLanguages = pendingLanguages;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mPendingLanguages);
|
||||
this.mSupportedLanguages = supportedLanguages;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mSupportedLanguages);
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for this request is ready for use on this device for the returned languages.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull List<String> getInstalledLanguages() {
|
||||
return mInstalledLanguages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for this request is scheduled for download for the returned languages.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull List<String> getPendingLanguages() {
|
||||
return mPendingLanguages;
|
||||
}
|
||||
|
||||
/**
|
||||
* These languages are supported but need to be downloaded before use.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull List<String> getSupportedLanguages() {
|
||||
return mSupportedLanguages;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public String toString() {
|
||||
// You can override field toString logic by defining methods like:
|
||||
// String fieldNameToString() { ... }
|
||||
|
||||
return "RecognitionSupport { " +
|
||||
"installedLanguages = " + mInstalledLanguages + ", " +
|
||||
"pendingLanguages = " + mPendingLanguages + ", " +
|
||||
"supportedLanguages = " + mSupportedLanguages +
|
||||
" }";
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public boolean equals(@android.annotation.Nullable Object o) {
|
||||
// You can override field equality logic by defining either of the methods like:
|
||||
// boolean fieldNameEquals(RecognitionSupport other) { ... }
|
||||
// boolean fieldNameEquals(FieldType otherValue) { ... }
|
||||
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
@SuppressWarnings("unchecked")
|
||||
RecognitionSupport that = (RecognitionSupport) o;
|
||||
//noinspection PointlessBooleanExpression
|
||||
return true
|
||||
&& java.util.Objects.equals(mInstalledLanguages, that.mInstalledLanguages)
|
||||
&& java.util.Objects.equals(mPendingLanguages, that.mPendingLanguages)
|
||||
&& java.util.Objects.equals(mSupportedLanguages, that.mSupportedLanguages);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int hashCode() {
|
||||
// You can override field hashCode logic by defining methods like:
|
||||
// int fieldNameHashCode() { ... }
|
||||
|
||||
int _hash = 1;
|
||||
_hash = 31 * _hash + java.util.Objects.hashCode(mInstalledLanguages);
|
||||
_hash = 31 * _hash + java.util.Objects.hashCode(mPendingLanguages);
|
||||
_hash = 31 * _hash + java.util.Objects.hashCode(mSupportedLanguages);
|
||||
return _hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
|
||||
// You can override field parcelling by defining methods like:
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
dest.writeStringList(mInstalledLanguages);
|
||||
dest.writeStringList(mPendingLanguages);
|
||||
dest.writeStringList(mSupportedLanguages);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int describeContents() { return 0; }
|
||||
|
||||
/** @hide */
|
||||
@SuppressWarnings({"unchecked", "RedundantCast"})
|
||||
@DataClass.Generated.Member
|
||||
/* package-private */ RecognitionSupport(@NonNull android.os.Parcel in) {
|
||||
// You can override field unparcelling by defining methods like:
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
List<String> installedLanguages = new java.util.ArrayList<>();
|
||||
in.readStringList(installedLanguages);
|
||||
List<String> pendingLanguages = new java.util.ArrayList<>();
|
||||
in.readStringList(pendingLanguages);
|
||||
List<String> supportedLanguages = new java.util.ArrayList<>();
|
||||
in.readStringList(supportedLanguages);
|
||||
|
||||
this.mInstalledLanguages = installedLanguages;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mInstalledLanguages);
|
||||
this.mPendingLanguages = pendingLanguages;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mPendingLanguages);
|
||||
this.mSupportedLanguages = supportedLanguages;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mSupportedLanguages);
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public static final @NonNull Parcelable.Creator<RecognitionSupport> CREATOR
|
||||
= new Parcelable.Creator<RecognitionSupport>() {
|
||||
@Override
|
||||
public RecognitionSupport[] newArray(int size) {
|
||||
return new RecognitionSupport[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecognitionSupport createFromParcel(@NonNull android.os.Parcel in) {
|
||||
return new RecognitionSupport(in);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A builder for {@link RecognitionSupport}
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@DataClass.Generated.Member
|
||||
public static final class Builder {
|
||||
|
||||
private @NonNull List<String> mInstalledLanguages;
|
||||
private @NonNull List<String> mPendingLanguages;
|
||||
private @NonNull List<String> mSupportedLanguages;
|
||||
|
||||
private long mBuilderFieldsSet = 0L;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for this request is ready for use on this device for the returned languages.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setInstalledLanguages(@NonNull List<String> value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x1;
|
||||
mInstalledLanguages = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see #setInstalledLanguages */
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder addInstalledLanguages(@NonNull String value) {
|
||||
// You can refine this method's name by providing item's singular name, e.g.:
|
||||
// @DataClass.PluralOf("item")) mItems = ...
|
||||
|
||||
if (mInstalledLanguages == null) setInstalledLanguages(new java.util.ArrayList<>());
|
||||
mInstalledLanguages.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for this request is scheduled for download for the returned languages.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setPendingLanguages(@NonNull List<String> value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x2;
|
||||
mPendingLanguages = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see #setPendingLanguages */
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder addPendingLanguages(@NonNull String value) {
|
||||
// You can refine this method's name by providing item's singular name, e.g.:
|
||||
// @DataClass.PluralOf("item")) mItems = ...
|
||||
|
||||
if (mPendingLanguages == null) setPendingLanguages(new java.util.ArrayList<>());
|
||||
mPendingLanguages.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* These languages are supported but need to be downloaded before use.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setSupportedLanguages(@NonNull List<String> value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x4;
|
||||
mSupportedLanguages = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @see #setSupportedLanguages */
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder addSupportedLanguages(@NonNull String value) {
|
||||
// You can refine this method's name by providing item's singular name, e.g.:
|
||||
// @DataClass.PluralOf("item")) mItems = ...
|
||||
|
||||
if (mSupportedLanguages == null) setSupportedLanguages(new java.util.ArrayList<>());
|
||||
mSupportedLanguages.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds the instance. This builder should not be touched after calling this! */
|
||||
public @NonNull RecognitionSupport build() {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x8; // Mark builder used
|
||||
|
||||
if ((mBuilderFieldsSet & 0x1) == 0) {
|
||||
mInstalledLanguages = null;
|
||||
}
|
||||
if ((mBuilderFieldsSet & 0x2) == 0) {
|
||||
mPendingLanguages = null;
|
||||
}
|
||||
if ((mBuilderFieldsSet & 0x4) == 0) {
|
||||
mSupportedLanguages = null;
|
||||
}
|
||||
RecognitionSupport o = new RecognitionSupport(
|
||||
mInstalledLanguages,
|
||||
mPendingLanguages,
|
||||
mSupportedLanguages);
|
||||
return o;
|
||||
}
|
||||
|
||||
private void checkNotUsed() {
|
||||
if ((mBuilderFieldsSet & 0x8) != 0) {
|
||||
throw new IllegalStateException(
|
||||
"This Builder should not be reused. Use a new Builder instance instead");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1639158640137L,
|
||||
codegenVersion = "1.0.23",
|
||||
sourceFile = "frameworks/base/core/java/android/speech/RecognitionSupport.java",
|
||||
inputSignatures = "private @android.annotation.NonNull java.util.List<java.lang.String> mInstalledLanguages\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mPendingLanguages\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mSupportedLanguages\nclass RecognitionSupport extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
//@formatter:on
|
||||
// End of generated code
|
||||
|
||||
}
|
||||
32
core/java/android/speech/RecognitionSupportCallback.java
Normal file
32
core/java/android/speech/RecognitionSupportCallback.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Used for receiving notifications from the SpeechRecognizer about the device support status for
|
||||
* the given recognition request.
|
||||
*/
|
||||
public interface RecognitionSupportCallback {
|
||||
|
||||
/** Notifies the caller about the support for the given request. */
|
||||
void onSupportResult(@NonNull RecognitionSupport recognitionSupport);
|
||||
|
||||
/** Notifies the caller about an error during the recognition support request */
|
||||
void onError(@SpeechRecognizer.RecognitionError int error);
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import android.os.ServiceManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -46,6 +47,7 @@ import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
@@ -112,7 +114,8 @@ public class SpeechRecognizer {
|
||||
ERROR_TOO_MANY_REQUESTS,
|
||||
ERROR_SERVER_DISCONNECTED,
|
||||
ERROR_LANGUAGE_NOT_SUPPORTED,
|
||||
ERROR_LANGUAGE_UNAVAILABLE
|
||||
ERROR_LANGUAGE_UNAVAILABLE,
|
||||
ERROR_CANNOT_CHECK_SUPPORT,
|
||||
})
|
||||
public @interface RecognitionError {}
|
||||
|
||||
@@ -155,19 +158,24 @@ public class SpeechRecognizer {
|
||||
/** Requested language is supported, but not available currently (e.g. not downloaded yet). */
|
||||
public static final int ERROR_LANGUAGE_UNAVAILABLE = 13;
|
||||
|
||||
/** The service does not allow to check for support. */
|
||||
public static final int ERROR_CANNOT_CHECK_SUPPORT = 14;
|
||||
|
||||
/** 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;
|
||||
|
||||
/** 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;
|
||||
|
||||
@@ -197,6 +205,15 @@ public class SpeechRecognizer {
|
||||
case MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT:
|
||||
handleSetTemporaryComponent((ComponentName) msg.obj);
|
||||
break;
|
||||
case MSG_CHECK_RECOGNITION_SUPPORT:
|
||||
Pair<Intent, RecognitionSupportCallback> intentAndListener =
|
||||
(Pair<Intent, RecognitionSupportCallback>) msg.obj;
|
||||
handleCheckRecognitionSupport(
|
||||
intentAndListener.first, intentAndListener.second);
|
||||
break;
|
||||
case MSG_TRIGGER_MODEL_DOWNLOAD:
|
||||
handleTriggerModelDownload((Intent) msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -208,7 +225,7 @@ public class SpeechRecognizer {
|
||||
private final Queue<Message> mPendingTasks = new LinkedBlockingQueue<>();
|
||||
|
||||
/** The Listener that will receive all the callbacks */
|
||||
private final InternalListener mListener = new InternalListener();
|
||||
private final InternalRecognitionListener mListener = new InternalRecognitionListener();
|
||||
|
||||
private final IBinder mClientToken = new Binder();
|
||||
|
||||
@@ -464,6 +481,38 @@ public class SpeechRecognizer {
|
||||
putMessage(Message.obtain(mHandler, MSG_CANCEL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether {@code recognizerIntent} is supported by
|
||||
* {@link SpeechRecognizer#startListening(Intent)}.
|
||||
*
|
||||
* @param recognizerIntent contains parameters for the recognition to be performed. The intent
|
||||
* may also contain optional extras. See {@link RecognizerIntent} for the list of
|
||||
* supported extras, any unlisted extra might be ignored.
|
||||
* @param supportListener the listener on which to receive the support query results.
|
||||
*/
|
||||
public void checkRecognitionSupport(
|
||||
@NonNull Intent recognizerIntent,
|
||||
@NonNull RecognitionSupportCallback supportListener) {
|
||||
Objects.requireNonNull(recognizerIntent, "intent must not be null");
|
||||
Objects.requireNonNull(supportListener, "listener must not be null");
|
||||
|
||||
putMessage(Message.obtain(mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
|
||||
Pair.create(recognizerIntent, supportListener)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, RecognitionSupportCallback)}.
|
||||
*
|
||||
* @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");
|
||||
putMessage(Message.obtain(mHandler, MSG_TRIGGER_MODEL_DOWNLOAD));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a temporary component to power on-device speech recognizer.
|
||||
*
|
||||
@@ -503,7 +552,7 @@ public class SpeechRecognizer {
|
||||
}
|
||||
try {
|
||||
mService.startListening(recognizerIntent, mListener, mContext.getAttributionSource());
|
||||
if (DBG) Log.d(TAG, "service start listening command succeded");
|
||||
if (DBG) Log.d(TAG, "service start listening command succeeded");
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(TAG, "startListening() failed", e);
|
||||
mListener.onError(ERROR_CLIENT);
|
||||
@@ -517,7 +566,7 @@ public class SpeechRecognizer {
|
||||
}
|
||||
try {
|
||||
mService.stopListening(mListener);
|
||||
if (DBG) Log.d(TAG, "service stop listening command succeded");
|
||||
if (DBG) Log.d(TAG, "service stop listening command succeeded");
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(TAG, "stopListening() failed", e);
|
||||
mListener.onError(ERROR_CLIENT);
|
||||
@@ -531,7 +580,7 @@ public class SpeechRecognizer {
|
||||
}
|
||||
try {
|
||||
mService.cancel(mListener, /*isShutdown*/ false);
|
||||
if (DBG) Log.d(TAG, "service cancel command succeded");
|
||||
if (DBG) Log.d(TAG, "service cancel command succeeded");
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(TAG, "cancel() failed", e);
|
||||
mListener.onError(ERROR_CLIENT);
|
||||
@@ -554,6 +603,35 @@ public class SpeechRecognizer {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCheckRecognitionSupport(
|
||||
Intent recognizerIntent, RecognitionSupportCallback recognitionSupportCallback) {
|
||||
if (!maybeInitializeManagerService()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mService.checkRecognitionSupport(
|
||||
recognizerIntent,
|
||||
new InternalSupportCallback(recognitionSupportCallback));
|
||||
if (DBG) Log.d(TAG, "service support command succeeded");
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(TAG, "checkRecognitionSupport() failed", e);
|
||||
mListener.onError(ERROR_CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTriggerModelDownload(Intent recognizerIntent) {
|
||||
if (!maybeInitializeManagerService()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mService.triggerModelDownload(recognizerIntent);
|
||||
if (DBG) Log.d(TAG, "service download support command succeeded");
|
||||
} catch (final RemoteException e) {
|
||||
Log.e(TAG, "downloadModel() failed", e);
|
||||
mListener.onError(ERROR_CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkOpenConnection() {
|
||||
if (mService != null) {
|
||||
return true;
|
||||
@@ -626,7 +704,7 @@ public class SpeechRecognizer {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean maybeInitializeManagerService() {
|
||||
private synchronized boolean maybeInitializeManagerService() {
|
||||
if (mManagerService != null) {
|
||||
return true;
|
||||
}
|
||||
@@ -678,7 +756,7 @@ public class SpeechRecognizer {
|
||||
* Internal wrapper of IRecognitionListener which will propagate the results to
|
||||
* RecognitionListener
|
||||
*/
|
||||
private static class InternalListener extends IRecognitionListener.Stub {
|
||||
private static class InternalRecognitionListener extends IRecognitionListener.Stub {
|
||||
private RecognitionListener mInternalListener;
|
||||
|
||||
private static final int MSG_BEGINNING_OF_SPEECH = 1;
|
||||
@@ -766,4 +844,42 @@ public class SpeechRecognizer {
|
||||
.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private static class InternalSupportCallback extends IRecognitionSupportCallback.Stub {
|
||||
private final RecognitionSupportCallback mCallback;
|
||||
|
||||
private static final int MSG_SUPPORT_RESULT = 1;
|
||||
private static final int MSG_ERROR = 2;
|
||||
|
||||
private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (mCallback == null) {
|
||||
return;
|
||||
}
|
||||
switch (msg.what) {
|
||||
case MSG_SUPPORT_RESULT:
|
||||
mCallback.onSupportResult((RecognitionSupport) msg.obj);
|
||||
break;
|
||||
case MSG_ERROR:
|
||||
mCallback.onError((Integer) msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private InternalSupportCallback(RecognitionSupportCallback callback) {
|
||||
this.mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSupportResult(RecognitionSupport recognitionSupport) throws RemoteException {
|
||||
Message.obtain(mInternalHandler, MSG_SUPPORT_RESULT, recognitionSupport).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode) throws RemoteException {
|
||||
Message.obtain(mInternalHandler, MSG_ERROR, errorCode).sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.speech.IRecognitionListener;
|
||||
import android.speech.IRecognitionService;
|
||||
import android.speech.IRecognitionSupportCallback;
|
||||
import android.speech.RecognitionService;
|
||||
import android.speech.SpeechRecognizer;
|
||||
import android.util.Log;
|
||||
@@ -211,6 +212,30 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn
|
||||
}
|
||||
}
|
||||
|
||||
void checkRecognitionSupport(
|
||||
Intent recognizerIntent,
|
||||
IRecognitionSupportCallback callback) {
|
||||
|
||||
if (!mConnected) {
|
||||
try {
|
||||
callback.onError(SpeechRecognizer.ERROR_SERVER_DISCONNECTED);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Failed to report the connection broke to the caller.", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
run(service -> service.checkRecognitionSupport(recognizerIntent, callback));
|
||||
}
|
||||
|
||||
void triggerModelDownload(Intent recognizerIntent) {
|
||||
if (!mConnected) {
|
||||
Slog.e(TAG, "#downloadModel failed due to connection.");
|
||||
return;
|
||||
}
|
||||
run(service -> service.triggerModelDownload(recognizerIntent));
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
synchronized (mLock) {
|
||||
if (this.mListener == null) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.permission.PermissionManager;
|
||||
import android.speech.IRecognitionListener;
|
||||
import android.speech.IRecognitionService;
|
||||
import android.speech.IRecognitionServiceManagerCallback;
|
||||
import android.speech.IRecognitionSupportCallback;
|
||||
import android.speech.RecognitionService;
|
||||
import android.speech.SpeechRecognizer;
|
||||
import android.util.Slog;
|
||||
@@ -169,6 +170,18 @@ final class SpeechRecognitionManagerServiceImpl extends
|
||||
clientToken.unlinkToDeath(deathRecipient, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkRecognitionSupport(
|
||||
Intent recognizerIntent,
|
||||
IRecognitionSupportCallback callback) {
|
||||
service.checkRecognitionSupport(recognizerIntent, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerModelDownload(Intent recognizerIntent) {
|
||||
service.triggerModelDownload(recognizerIntent);
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error creating a speech recognition session", e);
|
||||
|
||||
Reference in New Issue
Block a user