diff options
| author | 2023-03-10 09:24:58 +0800 | |
|---|---|---|
| committer | 2023-03-19 16:26:48 +0000 | |
| commit | 78c84e15d284b8e0461f2392c9b800e84d9dc4e9 (patch) | |
| tree | 43dc0f7c27de6cba17337ae811cbdf0c1d273871 | |
| parent | 52cef828f16ea9193b0f2999e0ab00701e19ee52 (diff) | |
Follow HotwordDetector / DetectorFailure API feedback
By API Council feedback, there are two suggestions instead of
using instanceof.
(1) Use multiple methods in the callback.
(2) Use one big failure class which has a field for the failure type.
For suggestion 1, the assistant application can easy know the failure
comes from which module and take its next action in the different
callback method. Currently there are three kinds of detectors, I list
what callbacks will be used by different detectors.
(1)AlwaysOnHotwordDetector:
onFailure(HotwordDetectionServiceFailure)
onFailure(SoundTriggerFailure)
onUnknownFailure(String)
(2)SoftwareHotwordDetector
onFailure(HotwordDetectionServiceFailure)
onUnknownFailure(String)
(3)VisualQueryDetector
onFailure(VisualQueryDetectionServiceFailure)
onUnknownFailure(String)
For suggestion 2, it seems that the assistant application still needs
to take the action first to know the failure comes from which module
in this one callback method.
We think that the suggestion 1 is better than suggestion 2.
Bug: 271107031
Test: atest CtsVoiceInteractionTestCases
Change-Id: I57fa93d5a0c2919ce762688f1d97766e531ccfb3
Merged-In: I57fa93d5a0c2919ce762688f1d97766e531ccfb3
23 files changed, 527 insertions, 506 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 50e58f57dfc2..6177a9f0500f 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -13033,6 +13033,7 @@ package android.service.voice { public abstract static class AlwaysOnHotwordDetector.Callback implements android.service.voice.HotwordDetector.Callback { ctor public AlwaysOnHotwordDetector.Callback(); method public abstract void onAvailabilityChanged(int); + method public void onFailure(@NonNull android.service.voice.SoundTriggerFailure); method public void onHotwordDetectionServiceInitialized(int); method public void onHotwordDetectionServiceRestarted(); method public void onRejected(@NonNull android.service.voice.HotwordRejectedResult); @@ -13056,17 +13057,12 @@ package android.service.voice { method public int getStart(); } - public abstract class DetectorFailure implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public String getErrorMessage(); - method public abstract int getSuggestedAction(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.DetectorFailure> CREATOR; - field public static final int SUGGESTED_ACTION_DISABLE_DETECTION = 2; // 0x2 - field public static final int SUGGESTED_ACTION_NONE = 1; // 0x1 - field public static final int SUGGESTED_ACTION_RECREATE_DETECTOR = 3; // 0x3 - field public static final int SUGGESTED_ACTION_RESTART_RECOGNITION = 4; // 0x4 - field public static final int SUGGESTED_ACTION_UNKNOWN = 0; // 0x0 + public final class FailureSuggestedAction { + field public static final int DISABLE_DETECTION = 2; // 0x2 + field public static final int NONE = 1; // 0x1 + field public static final int RECREATE_DETECTOR = 3; // 0x3 + field public static final int RESTART_RECOGNITION = 4; // 0x4 + field public static final int UNKNOWN = 0; // 0x0 } public final class HotwordAudioStream implements android.os.Parcelable { @@ -13163,9 +13159,12 @@ package android.service.voice { method public void onRejected(@NonNull android.service.voice.HotwordRejectedResult); } - public final class HotwordDetectionServiceFailure extends android.service.voice.DetectorFailure { + public final class HotwordDetectionServiceFailure implements android.os.Parcelable { + method public int describeContents(); method public int getErrorCode(); + method @NonNull public String getErrorMessage(); method public int getSuggestedAction(); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordDetectionServiceFailure> CREATOR; field public static final int ERROR_CODE_BINDING_DIED = 2; // 0x2 field public static final int ERROR_CODE_BIND_FAILURE = 1; // 0x1 @@ -13188,12 +13187,13 @@ package android.service.voice { public static interface HotwordDetector.Callback { method public void onDetected(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload); method @Deprecated public void onError(); - method public default void onFailure(@NonNull android.service.voice.DetectorFailure); + method public default void onFailure(@NonNull android.service.voice.HotwordDetectionServiceFailure); method public void onHotwordDetectionServiceInitialized(int); method public void onHotwordDetectionServiceRestarted(); method public void onRecognitionPaused(); method public void onRecognitionResumed(); method public void onRejected(@NonNull android.service.voice.HotwordRejectedResult); + method public default void onUnknownFailure(@NonNull String); } public final class HotwordRejectedResult implements android.os.Parcelable { @@ -13220,9 +13220,12 @@ package android.service.voice { field public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64 } - public final class SoundTriggerFailure extends android.service.voice.DetectorFailure { + public final class SoundTriggerFailure implements android.os.Parcelable { + method public int describeContents(); method public int getErrorCode(); + method @NonNull public String getErrorMessage(); method public int getSuggestedAction(); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.SoundTriggerFailure> CREATOR; field public static final int ERROR_CODE_MODULE_DIED = 1; // 0x1 field public static final int ERROR_CODE_RECOGNITION_RESUME_FAILED = 2; // 0x2 @@ -13230,11 +13233,6 @@ package android.service.voice { field public static final int ERROR_CODE_UNKNOWN = 0; // 0x0 } - public final class UnknownFailure extends android.service.voice.DetectorFailure { - method public int getSuggestedAction(); - field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.UnknownFailure> CREATOR; - } - public abstract class VisualQueryDetectionService extends android.app.Service implements android.service.voice.SandboxedDetectionInitializer { ctor public VisualQueryDetectionService(); method public final void finishQuery() throws java.lang.IllegalStateException; @@ -13249,9 +13247,12 @@ package android.service.voice { field public static final String SERVICE_INTERFACE = "android.service.voice.VisualQueryDetectionService"; } - public final class VisualQueryDetectionServiceFailure extends android.service.voice.DetectorFailure { + public final class VisualQueryDetectionServiceFailure implements android.os.Parcelable { + method public int describeContents(); method public int getErrorCode(); + method @NonNull public String getErrorMessage(); method public int getSuggestedAction(); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.VisualQueryDetectionServiceFailure> CREATOR; field public static final int ERROR_CODE_BINDING_DIED = 2; // 0x2 field public static final int ERROR_CODE_BIND_FAILURE = 1; // 0x1 @@ -13269,10 +13270,11 @@ package android.service.voice { } public static interface VisualQueryDetector.Callback { - method public void onFailure(@NonNull android.service.voice.DetectorFailure); + method public void onFailure(@NonNull android.service.voice.VisualQueryDetectionServiceFailure); method public void onQueryDetected(@NonNull String); method public void onQueryFinished(); method public void onQueryRejected(); + method public void onUnknownFailure(@NonNull String); method public void onVisualQueryDetectionServiceInitialized(int); method public void onVisualQueryDetectionServiceRestarted(); } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index b856bc2ce853..b7d97eae56aa 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2897,23 +2897,19 @@ package android.service.voice { field public static final boolean ENABLE_PROXIMITY_RESULT = true; } - public final class HotwordDetectionServiceFailure extends android.service.voice.DetectorFailure { + public final class HotwordDetectionServiceFailure implements android.os.Parcelable { ctor public HotwordDetectionServiceFailure(int, @NonNull String); } - public final class SoundTriggerFailure extends android.service.voice.DetectorFailure { + public final class SoundTriggerFailure implements android.os.Parcelable { ctor public SoundTriggerFailure(int, @NonNull String); } - public final class UnknownFailure extends android.service.voice.DetectorFailure { - ctor public UnknownFailure(@NonNull String); - } - public final class VisibleActivityInfo implements android.os.Parcelable { ctor public VisibleActivityInfo(int, @NonNull android.os.IBinder); } - public final class VisualQueryDetectionServiceFailure extends android.service.voice.DetectorFailure { + public final class VisualQueryDetectionServiceFailure implements android.os.Parcelable { ctor public VisualQueryDetectionServiceFailure(int, @NonNull String); } diff --git a/core/java/android/service/voice/AbstractDetector.java b/core/java/android/service/voice/AbstractDetector.java index 0f3e8d1f4bde..8648e386fbbb 100644 --- a/core/java/android/service/voice/AbstractDetector.java +++ b/core/java/android/service/voice/AbstractDetector.java @@ -228,11 +228,16 @@ abstract class AbstractDetector implements HotwordDetector { /** Called when the detection fails due to an error. */ @Override - public void onError(DetectorFailure detectorFailure) { - Slog.v(TAG, "BinderCallback#onError detectorFailure: " + detectorFailure); + public void onHotwordDetectionServiceFailure( + HotwordDetectionServiceFailure hotwordDetectionServiceFailure) { + Slog.v(TAG, "BinderCallback#onHotwordDetectionServiceFailure: " + + hotwordDetectionServiceFailure); Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { - mCallback.onFailure(detectorFailure != null ? detectorFailure - : new UnknownFailure("Error data is null")); + if (hotwordDetectionServiceFailure != null) { + mCallback.onFailure(hotwordDetectionServiceFailure); + } else { + mCallback.onUnknownFailure("Error data is null"); + } })); } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index e69e03e1fac3..8688a18880b7 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -280,6 +280,9 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { private static final int MSG_HOTWORD_REJECTED = 6; private static final int MSG_HOTWORD_STATUS_REPORTED = 7; private static final int MSG_PROCESS_RESTARTED = 8; + private static final int MSG_DETECTION_HOTWORD_DETECTION_SERVICE_FAILURE = 9; + private static final int MSG_DETECTION_SOUND_TRIGGER_FAILURE = 10; + private static final int MSG_DETECTION_UNKNOWN_FAILURE = 11; private final String mText; private final Locale mLocale; @@ -774,12 +777,28 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { /** * {@inheritDoc} * - * @deprecated Use {@link HotwordDetector.Callback#onError(DetectorFailure)} instead. + * @deprecated On {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, + * implement {@link HotwordDetector.Callback#onFailure(HotwordDetectionServiceFailure)}, + * {@link AlwaysOnHotwordDetector.Callback#onFailure(SoundTriggerFailure)}, + * {@link HotwordDetector.Callback#onUnknownFailure(String)} instead. */ @Deprecated @Override public abstract void onError(); + /** + * Called when the detection fails due to an error occurs in the + * {@link com.android.server.soundtrigger.SoundTriggerService} and + * {@link com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareService}, + * {@link SoundTriggerFailure} will be reported to the detector. + * + * @param soundTriggerFailure It provides the error code, error message and suggested + * action. + */ + public void onFailure(@NonNull SoundTriggerFailure soundTriggerFailure) { + onError(); + } + /** {@inheritDoc} */ public abstract void onRecognitionPaused(); @@ -1556,18 +1575,43 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { @Override public void onError(int status) { Slog.i(TAG, "onError: " + status); - // This is a workaround before the sound trigger uses the onDetectionFailure method. - Message.obtain(mHandler, MSG_DETECTION_ERROR, - new SoundTriggerFailure(status, "Sound trigger error")).sendToTarget(); + // TODO(b/271534248): This is a workaround before the sound trigger uses the new error + // method. + Message.obtain(mHandler, MSG_DETECTION_SOUND_TRIGGER_FAILURE, + new SoundTriggerFailure(SoundTriggerFailure.ERROR_CODE_UNKNOWN, + "Sound trigger error")).sendToTarget(); } @Override - public void onDetectionFailure(DetectorFailure detectorFailure) { - Slog.v(TAG, "onDetectionFailure detectorFailure: " + detectorFailure); - Message.obtain(mHandler, MSG_DETECTION_ERROR, - detectorFailure != null ? detectorFailure - : new UnknownFailure("Error data is null")).sendToTarget(); + public void onHotwordDetectionServiceFailure( + HotwordDetectionServiceFailure hotwordDetectionServiceFailure) { + Slog.v(TAG, "onHotwordDetectionServiceFailure: " + hotwordDetectionServiceFailure); + if (hotwordDetectionServiceFailure != null) { + Message.obtain(mHandler, MSG_DETECTION_HOTWORD_DETECTION_SERVICE_FAILURE, + hotwordDetectionServiceFailure).sendToTarget(); + } else { + Message.obtain(mHandler, MSG_DETECTION_UNKNOWN_FAILURE, + "Error data is null").sendToTarget(); + } } + + @Override + public void onVisualQueryDetectionServiceFailure( + VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure) + throws RemoteException { + // It should never be called here. + Slog.w(TAG, + "onVisualQueryDetectionServiceFailure: " + visualQueryDetectionServiceFailure); + } + + @Override + public void onUnknownFailure(String errorMessage) throws RemoteException { + Slog.v(TAG, "onUnknownFailure: " + errorMessage); + Message.obtain(mHandler, MSG_DETECTION_UNKNOWN_FAILURE, + !TextUtils.isEmpty(errorMessage) ? errorMessage + : "Error data is null").sendToTarget(); + } + @Override public void onRecognitionPaused() { Slog.i(TAG, "onRecognitionPaused"); @@ -1600,7 +1644,7 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { } void onDetectorRemoteException() { - Message.obtain(mHandler, MSG_DETECTION_ERROR, + Message.obtain(mHandler, MSG_DETECTION_HOTWORD_DETECTION_SERVICE_FAILURE, new HotwordDetectionServiceFailure( HotwordDetectionServiceFailure.ERROR_CODE_REMOTE_EXCEPTION, "Detector remote exception occurs")).sendToTarget(); @@ -1630,7 +1674,9 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { mExternalCallback.onDetected((EventPayload) message.obj); break; case MSG_DETECTION_ERROR: - mExternalCallback.onFailure((DetectorFailure) message.obj); + // TODO(b/271534248): After reverting the workaround, this logic is still + // necessary. + mExternalCallback.onError(); break; case MSG_DETECTION_PAUSE: mExternalCallback.onRecognitionPaused(); @@ -1647,6 +1693,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { case MSG_PROCESS_RESTARTED: mExternalCallback.onHotwordDetectionServiceRestarted(); break; + case MSG_DETECTION_HOTWORD_DETECTION_SERVICE_FAILURE: + mExternalCallback.onFailure((HotwordDetectionServiceFailure) message.obj); + break; + case MSG_DETECTION_SOUND_TRIGGER_FAILURE: + mExternalCallback.onFailure((SoundTriggerFailure) message.obj); + break; + case MSG_DETECTION_UNKNOWN_FAILURE: + mExternalCallback.onUnknownFailure((String) message.obj); + break; default: super.handleMessage(message); } diff --git a/core/java/android/service/voice/DetectorFailure.aidl b/core/java/android/service/voice/DetectorFailure.aidl deleted file mode 100644 index 3591329ac111..000000000000 --- a/core/java/android/service/voice/DetectorFailure.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2023 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.service.voice; - -parcelable DetectorFailure; diff --git a/core/java/android/service/voice/DetectorFailure.java b/core/java/android/service/voice/DetectorFailure.java deleted file mode 100644 index c6efdc3063e3..000000000000 --- a/core/java/android/service/voice/DetectorFailure.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2023 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.service.voice; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import com.android.internal.util.Preconditions; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This is used by the assistant application to know what went wrong during using the detector - * and which action the application should take. The detector can be a HotwordDector or a visual - * query detector. - * - * <p>Any class that derives this class must only add an integer value of error source type, an - * integer value of error code and a string of error message passed into the constructor. Any other - * field will not be parceled through. If the derived class has custom parceling implementation, - * this class will not be able to unpack the parcel without having access to that implementation. - * - * @hide - */ -@SuppressLint("ParcelNotFinal") // Safe because the constructor is package-private -@SystemApi -public abstract class DetectorFailure implements Parcelable { - - /** - * A suggested action due to an unknown error occurs. - */ - public static final int SUGGESTED_ACTION_UNKNOWN = 0; - - /** - * Indicates that an error occurs, but no action is needed for the client. The error will be - * recovered from within the framework. - */ - public static final int SUGGESTED_ACTION_NONE = 1; - - /** - * Indicates that an error occurs, but no action is needed for the client due to the error can - * not be recovered. It means that the detection will not work even though the assistant - * application creates the detector again. - * - * Example: The detection service always crashes after assistant application creates the - * detector. The assistant application can stop re-creating the detector and show a suitable - * error dialog to notify the user. - */ - public static final int SUGGESTED_ACTION_DISABLE_DETECTION = 2; - - /** - * Indicates that the detection service is invalid, the client needs to destroy its detector - * first and recreate its detector later. - */ - public static final int SUGGESTED_ACTION_RECREATE_DETECTOR = 3; - - /** - * Indicates that the detection has stopped. The client needs to start recognition again. - * - * Example: The system server receives a Dsp trigger event. - */ - public static final int SUGGESTED_ACTION_RESTART_RECOGNITION = 4; - - /** - * @hide - */ - @IntDef(prefix = {"SUGGESTED_ACTION_"}, value = { - SUGGESTED_ACTION_UNKNOWN, - SUGGESTED_ACTION_NONE, - SUGGESTED_ACTION_DISABLE_DETECTION, - SUGGESTED_ACTION_RECREATE_DETECTOR, - SUGGESTED_ACTION_RESTART_RECOGNITION - }) - @Retention(RetentionPolicy.SOURCE) - public @interface SuggestedAction {} - - /** - * Indicates that an error occurs from the unknown error source. - * - * @hide - */ - public static final int ERROR_SOURCE_TYPE_UNKNOWN = -1; - - /** - * Indicates that an error occurs from the hotword detection. - * - * @see HotwordDetectionServiceFailure#ERROR_CODE_BIND_FAILURE - * @see HotwordDetectionServiceFailure#ERROR_CODE_BINDING_DIED - * @see HotwordDetectionServiceFailure#ERROR_CODE_COPY_AUDIO_DATA_FAILURE - * @see HotwordDetectionServiceFailure#ERROR_CODE_DETECT_TIMEOUT - * @see HotwordDetectionServiceFailure#ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION - * @see HotwordDetectionServiceFailure#ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE - * @see HotwordDetectionServiceFailure#ERROR_CODE_REMOTE_EXCEPTION - * - * @hide - */ - public static final int ERROR_SOURCE_TYPE_HOTWORD_DETECTION = 0; - - /** - * Indicates that an error occurs from the sound trigger system service - * {@link com.android.server.soundtrigger.SoundTriggerService} and - * {@link com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareService}. - * - * @see SoundTriggerFailure#ERROR_CODE_MODULE_DIED - * @see SoundTriggerFailure#ERROR_CODE_RECOGNITION_RESUME_FAILED - * @see SoundTriggerFailure#ERROR_CODE_UNEXPECTED_PREEMPTION - * - * @hide - */ - public static final int ERROR_SOURCE_TYPE_SOUND_TRIGGER = 1; - - /** - * Indicates that an error occurs from {@link VisualQueryDetectionService}. - * - * @see VisualQueryDetectionServiceFailure#ERROR_CODE_BIND_FAILURE - * @see VisualQueryDetectionServiceFailure#ERROR_CODE_BINDING_DIED - * @see VisualQueryDetectionServiceFailure#ERROR_CODE_ILLEGAL_ATTENTION_STATE - * @see VisualQueryDetectionServiceFailure#ERROR_CODE_ILLEGAL_STREAMING_STATE - * @see VisualQueryDetectionServiceFailure#ERROR_CODE_REMOTE_EXCEPTION - * - * @hide - */ - public static final int ERROR_SOURCE_TYPE_VISUAL_QUERY_DETECTION = 2; - - private int mErrorSourceType = ERROR_SOURCE_TYPE_UNKNOWN; - private int mErrorCode = UnknownFailure.ERROR_CODE_UNKNOWN; - private String mErrorMessage = "Unknown"; - - DetectorFailure(int errorSourceType, int errorCode, @NonNull String errorMessage) { - Preconditions.checkArgumentInRange(errorSourceType, ERROR_SOURCE_TYPE_UNKNOWN, - ERROR_SOURCE_TYPE_VISUAL_QUERY_DETECTION, "errorSourceType"); - if (TextUtils.isEmpty(errorMessage)) { - throw new IllegalArgumentException("errorMessage is empty or null."); - } - mErrorSourceType = errorSourceType; - mErrorCode = errorCode; - mErrorMessage = errorMessage; - } - - /** - * Returns the suggested action. - */ - @SuggestedAction - public abstract int getSuggestedAction(); - - /** - * Returns the error code. - * - * @hide - */ - public int getErrorCode() { - return mErrorCode; - } - - /** - * Returns the error message. - */ - @NonNull - public String getErrorMessage() { - return mErrorMessage; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mErrorSourceType); - dest.writeInt(mErrorCode); - dest.writeString8(mErrorMessage); - } - - public static final @NonNull Parcelable.Creator<DetectorFailure> CREATOR = - new Parcelable.Creator<DetectorFailure>() { - @Override - public DetectorFailure[] newArray(int size) { - return new DetectorFailure[size]; - } - - @Override - public DetectorFailure createFromParcel(@NonNull Parcel in) { - final int errorSourceType = in.readInt(); - final int errorCode = in.readInt(); - final String errorMessage = in.readString8(); - switch (errorSourceType) { - case ERROR_SOURCE_TYPE_HOTWORD_DETECTION: - return new HotwordDetectionServiceFailure(errorCode, errorMessage); - case ERROR_SOURCE_TYPE_SOUND_TRIGGER: - return new SoundTriggerFailure(errorCode, errorMessage); - case ERROR_SOURCE_TYPE_VISUAL_QUERY_DETECTION: - return new VisualQueryDetectionServiceFailure(errorCode, errorMessage); - default: - return new UnknownFailure(errorMessage); - } - } - }; -} diff --git a/core/java/android/service/voice/FailureSuggestedAction.java b/core/java/android/service/voice/FailureSuggestedAction.java new file mode 100644 index 000000000000..8408c3ba953a --- /dev/null +++ b/core/java/android/service/voice/FailureSuggestedAction.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 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.service.voice; + +import android.annotation.IntDef; +import android.annotation.SystemApi; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This is used by the assistant application to know which action the application should take on a + * failure callback. The detector can be a HotwordDector or a visual query detector. + * + * @hide + */ +@SystemApi +public final class FailureSuggestedAction { + + /** + * A suggested action due to an unknown error occurs. + */ + public static final int UNKNOWN = 0; + + /** + * Indicates that an error occurs, but no action is needed for the client. The error will be + * recovered from within the framework. + */ + public static final int NONE = 1; + + /** + * Indicates that an error occurs, but no action is needed for the client due to the error can + * not be recovered. It means that the detection will not work even though the assistant + * application creates the detector again. + */ + public static final int DISABLE_DETECTION = 2; + + /** + * Indicates that the detection service is invalid, the client needs to destroy its detector + * first and recreate its detector later. + */ + public static final int RECREATE_DETECTOR = 3; + + /** + * Indicates that the detection has stopped. The client needs to start recognition again. + * + * Example: The system server receives a Dsp trigger event. + */ + public static final int RESTART_RECOGNITION = 4; + + /** + * @hide + */ + @IntDef({UNKNOWN, NONE, DISABLE_DETECTION, RECREATE_DETECTOR, RESTART_RECOGNITION}) + @Retention(RetentionPolicy.SOURCE) + public @interface FailureSuggestedActionDef {} + + private FailureSuggestedAction() {} +} diff --git a/core/java/android/service/voice/HotwordDetectionServiceFailure.java b/core/java/android/service/voice/HotwordDetectionServiceFailure.java index 3d9f66b173d4..5cf245d8624b 100644 --- a/core/java/android/service/voice/HotwordDetectionServiceFailure.java +++ b/core/java/android/service/voice/HotwordDetectionServiceFailure.java @@ -22,6 +22,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -36,7 +37,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -public final class HotwordDetectionServiceFailure extends DetectorFailure { +public final class HotwordDetectionServiceFailure implements Parcelable { /** * An error code which means an unknown error occurs. @@ -94,12 +95,19 @@ public final class HotwordDetectionServiceFailure extends DetectorFailure { @Retention(RetentionPolicy.SOURCE) public @interface HotwordDetectionServiceErrorCode {} + private int mErrorCode = ERROR_CODE_UNKNOWN; + private String mErrorMessage = "Unknown"; + /** * @hide */ @TestApi public HotwordDetectionServiceFailure(int errorCode, @NonNull String errorMessage) { - super(ERROR_SOURCE_TYPE_HOTWORD_DETECTION, errorCode, errorMessage); + if (TextUtils.isEmpty(errorMessage)) { + throw new IllegalArgumentException("errorMessage is empty or null."); + } + mErrorCode = errorCode; + mErrorMessage = errorMessage; } /** @@ -107,22 +115,33 @@ public final class HotwordDetectionServiceFailure extends DetectorFailure { */ @HotwordDetectionServiceErrorCode public int getErrorCode() { - return super.getErrorCode(); + return mErrorCode; } - @Override + /** + * Returns the error message. + */ + @NonNull + public String getErrorMessage() { + return mErrorMessage; + } + + /** + * Returns the suggested action. + */ + @FailureSuggestedAction.FailureSuggestedActionDef public int getSuggestedAction() { - switch (getErrorCode()) { + switch (mErrorCode) { case ERROR_CODE_BIND_FAILURE: case ERROR_CODE_BINDING_DIED: case ERROR_CODE_REMOTE_EXCEPTION: - return SUGGESTED_ACTION_RECREATE_DETECTOR; + return FailureSuggestedAction.RECREATE_DETECTOR; case ERROR_CODE_DETECT_TIMEOUT: case ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION: case ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE: - return SUGGESTED_ACTION_RESTART_RECOGNITION; + return FailureSuggestedAction.RESTART_RECOGNITION; default: - return SUGGESTED_ACTION_NONE; + return FailureSuggestedAction.NONE; } } @@ -133,7 +152,14 @@ public final class HotwordDetectionServiceFailure extends DetectorFailure { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - super.writeToParcel(dest, flags); + dest.writeInt(mErrorCode); + dest.writeString8(mErrorMessage); + } + + @Override + public String toString() { + return "HotwordDetectionServiceFailure { errorCode = " + mErrorCode + ", errorMessage = " + + mErrorMessage + " }"; } public static final @NonNull Parcelable.Creator<HotwordDetectionServiceFailure> CREATOR = @@ -145,8 +171,7 @@ public final class HotwordDetectionServiceFailure extends DetectorFailure { @Override public HotwordDetectionServiceFailure createFromParcel(@NonNull Parcel in) { - DetectorFailure detectorFailure = DetectorFailure.CREATOR.createFromParcel(in); - return (HotwordDetectionServiceFailure) detectorFailure; + return new HotwordDetectionServiceFailure(in.readInt(), in.readString8()); } }; } diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java index 0c8fd48a39d2..32a93eef7fda 100644 --- a/core/java/android/service/voice/HotwordDetector.java +++ b/core/java/android/service/voice/HotwordDetector.java @@ -189,24 +189,34 @@ public interface HotwordDetector { /** * Called when the detection fails due to an error. * - * @deprecated On Android 14 and above, implement {@link #onFailure(DetectorFailure)} - * instead. + * @deprecated On {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, + * implement {@link HotwordDetector.Callback#onFailure(HotwordDetectionServiceFailure)}, + * {@link AlwaysOnHotwordDetector.Callback#onFailure(SoundTriggerFailure)}, + * {@link HotwordDetector.Callback#onUnknownFailure(String)} instead. */ @Deprecated void onError(); /** - * Called when the detection fails due to an error, the subclasses of - * {@link DetectorFailure} will be reported to the detector. + * Called when the detection fails due to an error occurs in the + * {@link HotwordDetectionService}, {@link HotwordDetectionServiceFailure} will be reported + * to the detector. * - * @see android.service.voice.HotwordDetectionServiceFailure - * @see android.service.voice.SoundTriggerFailure - * @see android.service.voice.UnknownFailure - * @see android.service.voice.VisualQueryDetectionServiceFailure + * @param hotwordDetectionServiceFailure It provides the error code, error message and + * suggested action. + */ + default void onFailure( + @NonNull HotwordDetectionServiceFailure hotwordDetectionServiceFailure) { + onError(); + } + + /** + * Called when the detection fails due to an unknown error occurs, an error message + * will be reported to the detector. * - * @param detectorFailure It provides the error code, error message and suggested action. + * @param errorMessage It provides the error message. */ - default void onFailure(@NonNull DetectorFailure detectorFailure) { + default void onUnknownFailure(@NonNull String errorMessage) { onError(); } diff --git a/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl b/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl index f800c1ee22d6..fab830af9d48 100644 --- a/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl +++ b/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl @@ -17,8 +17,8 @@ package android.service.voice; import android.media.AudioFormat; -import android.service.voice.DetectorFailure; import android.service.voice.HotwordDetectedResult; +import android.service.voice.HotwordDetectionServiceFailure; import android.service.voice.HotwordRejectedResult; /** @@ -39,7 +39,8 @@ oneway interface IMicrophoneHotwordDetectionVoiceInteractionCallback { /** * Called when the detection fails due to an error. */ - void onError(in DetectorFailure detectorFailure); + void onHotwordDetectionServiceFailure( + in HotwordDetectionServiceFailure hotwordDetectionServiceFailure); /** * Called when the detected result was not detected. diff --git a/core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl b/core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl index 1a935c0acbf6..cedb7ff62497 100644 --- a/core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl +++ b/core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl @@ -16,7 +16,7 @@ package android.service.voice; -import android.service.voice.DetectorFailure; +import android.service.voice.VisualQueryDetectionServiceFailure; /** * Callback for returning the detected result from the VisualQueryDetectionService. @@ -43,5 +43,6 @@ oneway interface IVisualQueryDetectionVoiceInteractionCallback { /** * Called when the detection fails due to an error. */ - void onDetectionFailure(in DetectorFailure detectorFailure); + void onVisualQueryDetectionServiceFailure( + in VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure); } diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java index 77900d7bcb5a..eac7aee43859 100644 --- a/core/java/android/service/voice/SoftwareHotwordDetector.java +++ b/core/java/android/service/voice/SoftwareHotwordDetector.java @@ -30,6 +30,7 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SharedMemory; +import android.text.TextUtils; import android.util.Log; import android.util.Slog; @@ -176,11 +177,16 @@ class SoftwareHotwordDetector extends AbstractDetector { /** Called when the detection fails due to an error. */ @Override - public void onError(DetectorFailure detectorFailure) { - Slog.v(TAG, "BinderCallback#onError detectorFailure: " + detectorFailure); + public void onHotwordDetectionServiceFailure( + HotwordDetectionServiceFailure hotwordDetectionServiceFailure) { + Slog.v(TAG, "BinderCallback#onHotwordDetectionServiceFailure:" + + hotwordDetectionServiceFailure); Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { - mCallback.onFailure(detectorFailure != null ? detectorFailure - : new UnknownFailure("Error data is null")); + if (hotwordDetectionServiceFailure != null) { + mCallback.onFailure(hotwordDetectionServiceFailure); + } else { + mCallback.onUnknownFailure("Error data is null"); + } })); } @@ -236,11 +242,34 @@ class SoftwareHotwordDetector extends AbstractDetector { } @Override - public void onDetectionFailure(DetectorFailure detectorFailure) throws RemoteException { - Slog.v(TAG, "onDetectionFailure detectorFailure: " + detectorFailure); + public void onHotwordDetectionServiceFailure( + HotwordDetectionServiceFailure hotwordDetectionServiceFailure) + throws RemoteException { + Slog.v(TAG, "onHotwordDetectionServiceFailure: " + hotwordDetectionServiceFailure); Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { - mCallback.onFailure(detectorFailure != null ? detectorFailure - : new UnknownFailure("Error data is null")); + if (hotwordDetectionServiceFailure != null) { + mCallback.onFailure(hotwordDetectionServiceFailure); + } else { + mCallback.onUnknownFailure("Error data is null"); + } + })); + } + + @Override + public void onVisualQueryDetectionServiceFailure( + VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure) + throws RemoteException { + // It should never be called here. + Slog.w(TAG, "onVisualQueryDetectionServiceFailure: " + + visualQueryDetectionServiceFailure); + } + + @Override + public void onUnknownFailure(String errorMessage) throws RemoteException { + Slog.v(TAG, "onUnknownFailure: " + errorMessage); + Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { + mCallback.onUnknownFailure( + !TextUtils.isEmpty(errorMessage) ? errorMessage : "Error data is null"); })); } diff --git a/core/java/android/service/voice/SoundTriggerFailure.java b/core/java/android/service/voice/SoundTriggerFailure.java index a431fbc0fe1d..5560800a373f 100644 --- a/core/java/android/service/voice/SoundTriggerFailure.java +++ b/core/java/android/service/voice/SoundTriggerFailure.java @@ -22,6 +22,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -35,7 +36,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -public final class SoundTriggerFailure extends DetectorFailure { +public final class SoundTriggerFailure implements Parcelable { /** * An error code which means an unknown error occurs. @@ -72,12 +73,19 @@ public final class SoundTriggerFailure extends DetectorFailure { @Retention(RetentionPolicy.SOURCE) public @interface SoundTriggerErrorCode {} + private int mErrorCode = ERROR_CODE_UNKNOWN; + private String mErrorMessage = "Unknown"; + /** * @hide */ @TestApi public SoundTriggerFailure(int errorCode, @NonNull String errorMessage) { - super(ERROR_SOURCE_TYPE_SOUND_TRIGGER, errorCode, errorMessage); + if (TextUtils.isEmpty(errorMessage)) { + throw new IllegalArgumentException("errorMessage is empty or null."); + } + mErrorCode = errorCode; + mErrorMessage = errorMessage; } /** @@ -85,19 +93,30 @@ public final class SoundTriggerFailure extends DetectorFailure { */ @SoundTriggerErrorCode public int getErrorCode() { - return super.getErrorCode(); + return mErrorCode; } - @Override + /** + * Returns the error message. + */ + @NonNull + public String getErrorMessage() { + return mErrorMessage; + } + + /** + * Returns the suggested action. + */ + @FailureSuggestedAction.FailureSuggestedActionDef public int getSuggestedAction() { - switch (getErrorCode()) { + switch (mErrorCode) { case ERROR_CODE_MODULE_DIED: case ERROR_CODE_UNEXPECTED_PREEMPTION: - return SUGGESTED_ACTION_RECREATE_DETECTOR; + return FailureSuggestedAction.RECREATE_DETECTOR; case ERROR_CODE_RECOGNITION_RESUME_FAILED: - return SUGGESTED_ACTION_RESTART_RECOGNITION; + return FailureSuggestedAction.RESTART_RECOGNITION; default: - return SUGGESTED_ACTION_NONE; + return FailureSuggestedAction.NONE; } } @@ -108,7 +127,14 @@ public final class SoundTriggerFailure extends DetectorFailure { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - super.writeToParcel(dest, flags); + dest.writeInt(mErrorCode); + dest.writeString8(mErrorMessage); + } + + @Override + public String toString() { + return "SoundTriggerFailure { errorCode = " + mErrorCode + ", errorMessage = " + + mErrorMessage + " }"; } public static final @NonNull Parcelable.Creator<SoundTriggerFailure> CREATOR = @@ -120,7 +146,7 @@ public final class SoundTriggerFailure extends DetectorFailure { @Override public SoundTriggerFailure createFromParcel(@NonNull Parcel in) { - return (SoundTriggerFailure) DetectorFailure.CREATOR.createFromParcel(in); + return new SoundTriggerFailure(in.readInt(), in.readString8()); } }; } diff --git a/core/java/android/service/voice/UnknownFailure.aidl b/core/java/android/service/voice/UnknownFailure.aidl deleted file mode 100644 index cf43cc2fad46..000000000000 --- a/core/java/android/service/voice/UnknownFailure.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2023 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.service.voice; - -parcelable UnknownFailure; diff --git a/core/java/android/service/voice/UnknownFailure.java b/core/java/android/service/voice/UnknownFailure.java deleted file mode 100644 index 2ef2d5f880fd..000000000000 --- a/core/java/android/service/voice/UnknownFailure.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2023 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.service.voice; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.annotation.TestApi; -import android.os.Parcel; -import android.os.Parcelable; - -/** - * A class which indicates an unknown error occurs during the detector doing detection. The class - * is mainly used by the assistant application, the application still can get the suggested action - * for the unknown error. - * - * @hide - */ -@SystemApi -public final class UnknownFailure extends DetectorFailure { - - /** - * An error code which means an unknown error occurs. - * - * @hide - */ - public static final int ERROR_CODE_UNKNOWN = 0; - - /** - * @hide - */ - @TestApi - public UnknownFailure(@NonNull String errorMessage) { - super(ERROR_SOURCE_TYPE_UNKNOWN, ERROR_CODE_UNKNOWN, errorMessage); - } - - @Override - public int getSuggestedAction() { - return SUGGESTED_ACTION_UNKNOWN; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - super.writeToParcel(dest, flags); - } - - public static final @NonNull Parcelable.Creator<UnknownFailure> CREATOR = - new Parcelable.Creator<UnknownFailure>() { - @Override - public UnknownFailure[] newArray(int size) { - return new UnknownFailure[size]; - } - - @Override - public UnknownFailure createFromParcel(@NonNull Parcel in) { - return (UnknownFailure) DetectorFailure.CREATOR.createFromParcel(in); - } - }; -} diff --git a/core/java/android/service/voice/VisualQueryDetectionServiceFailure.java b/core/java/android/service/voice/VisualQueryDetectionServiceFailure.java index aa02299b2b28..4657e37486bf 100644 --- a/core/java/android/service/voice/VisualQueryDetectionServiceFailure.java +++ b/core/java/android/service/voice/VisualQueryDetectionServiceFailure.java @@ -22,6 +22,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -33,7 +34,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -public final class VisualQueryDetectionServiceFailure extends DetectorFailure { +public final class VisualQueryDetectionServiceFailure implements Parcelable { /** * An error code which means an unknown error occurs. @@ -79,12 +80,19 @@ public final class VisualQueryDetectionServiceFailure extends DetectorFailure { @Retention(RetentionPolicy.SOURCE) public @interface VisualQueryDetectionServiceErrorCode {} + private int mErrorCode = ERROR_CODE_UNKNOWN; + private String mErrorMessage = "Unknown"; + /** * @hide */ @TestApi public VisualQueryDetectionServiceFailure(int errorCode, @NonNull String errorMessage) { - super(ERROR_SOURCE_TYPE_VISUAL_QUERY_DETECTION, errorCode, errorMessage); + if (TextUtils.isEmpty(errorMessage)) { + throw new IllegalArgumentException("errorMessage is empty or null."); + } + mErrorCode = errorCode; + mErrorMessage = errorMessage; } /** @@ -92,21 +100,32 @@ public final class VisualQueryDetectionServiceFailure extends DetectorFailure { */ @VisualQueryDetectionServiceErrorCode public int getErrorCode() { - return super.getErrorCode(); + return mErrorCode; } - @Override + /** + * Returns the error message. + */ + @NonNull + public String getErrorMessage() { + return mErrorMessage; + } + + /** + * Returns the suggested action. + */ + @FailureSuggestedAction.FailureSuggestedActionDef public int getSuggestedAction() { - switch (getErrorCode()) { + switch (mErrorCode) { case ERROR_CODE_BIND_FAILURE: case ERROR_CODE_BINDING_DIED: case ERROR_CODE_ILLEGAL_ATTENTION_STATE: case ERROR_CODE_REMOTE_EXCEPTION: - return SUGGESTED_ACTION_RECREATE_DETECTOR; + return FailureSuggestedAction.RECREATE_DETECTOR; case ERROR_CODE_ILLEGAL_STREAMING_STATE: - return SUGGESTED_ACTION_RESTART_RECOGNITION; + return FailureSuggestedAction.RESTART_RECOGNITION; default: - return SUGGESTED_ACTION_NONE; + return FailureSuggestedAction.NONE; } } @@ -117,7 +136,14 @@ public final class VisualQueryDetectionServiceFailure extends DetectorFailure { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - super.writeToParcel(dest, flags); + dest.writeInt(mErrorCode); + dest.writeString8(mErrorMessage); + } + + @Override + public String toString() { + return "VisualQueryDetectionServiceFailure { errorCode = " + mErrorCode + + ", errorMessage = " + mErrorMessage + " }"; } public static final @NonNull Parcelable.Creator<VisualQueryDetectionServiceFailure> CREATOR = @@ -129,8 +155,7 @@ public final class VisualQueryDetectionServiceFailure extends DetectorFailure { @Override public VisualQueryDetectionServiceFailure createFromParcel(@NonNull Parcel in) { - DetectorFailure detectorFailure = DetectorFailure.CREATOR.createFromParcel(in); - return (VisualQueryDetectionServiceFailure) detectorFailure; + return new VisualQueryDetectionServiceFailure(in.readInt(), in.readString8()); } }; } diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java index d7bf07498715..b4f5ff1046ae 100644 --- a/core/java/android/service/voice/VisualQueryDetector.java +++ b/core/java/android/service/voice/VisualQueryDetector.java @@ -32,6 +32,7 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SharedMemory; +import android.text.TextUtils; import android.util.Slog; import com.android.internal.app.IHotwordRecognitionStatusCallback; @@ -216,9 +217,23 @@ public class VisualQueryDetector { void onVisualQueryDetectionServiceRestarted(); /** - * Called when the detection fails due to an error. + * Called when the detection fails due to an error occurs in the + * {@link VisualQueryDetectionService}, {@link VisualQueryDetectionServiceFailure} will be + * reported to the detector. + * + * @param visualQueryDetectionServiceFailure It provides the error code, error message and + * suggested action. + */ + void onFailure( + @NonNull VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure); + + /** + * Called when the detection fails due to an unknown error occurs, an error message + * will be reported to the detector. + * + * @param errorMessage It provides the error message. */ - void onFailure(@NonNull DetectorFailure detectorFailure); + void onUnknownFailure(@NonNull String errorMessage); } private class VisualQueryDetectorInitializationDelegate extends AbstractDetector { @@ -295,10 +310,17 @@ public class VisualQueryDetector { /** Called when the detection fails due to an error. */ @Override - public void onDetectionFailure(DetectorFailure detectorFailure) { - Slog.v(TAG, "BinderCallback#onDetectionFailure"); - Binder.withCleanCallingIdentity(() -> mExecutor.execute( - () -> mCallback.onFailure(detectorFailure))); + public void onVisualQueryDetectionServiceFailure( + VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure) { + Slog.v(TAG, "BinderCallback#onVisualQueryDetectionServiceFailure: " + + visualQueryDetectionServiceFailure); + Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { + if (visualQueryDetectionServiceFailure != null) { + mCallback.onFailure(visualQueryDetectionServiceFailure); + } else { + mCallback.onUnknownFailure("Error data is null"); + } + })); } } @@ -375,7 +397,35 @@ public class VisualQueryDetector { } @Override - public void onDetectionFailure(DetectorFailure detectorFailure) throws RemoteException { + public void onHotwordDetectionServiceFailure( + HotwordDetectionServiceFailure hotwordDetectionServiceFailure) + throws RemoteException { + // It should never be called here. + Slog.w(TAG, "onHotwordDetectionServiceFailure: " + hotwordDetectionServiceFailure); + } + + @Override + public void onVisualQueryDetectionServiceFailure( + VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure) + throws RemoteException { + Slog.v(TAG, "onVisualQueryDetectionServiceFailure: " + + visualQueryDetectionServiceFailure); + Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { + if (visualQueryDetectionServiceFailure != null) { + mCallback.onFailure(visualQueryDetectionServiceFailure); + } else { + mCallback.onUnknownFailure("Error data is null"); + } + })); + } + + @Override + public void onUnknownFailure(String errorMessage) throws RemoteException { + Slog.v(TAG, "onUnknownFailure: " + errorMessage); + Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> { + mCallback.onUnknownFailure( + !TextUtils.isEmpty(errorMessage) ? errorMessage : "Error data is null"); + })); } } } diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl index 813febf33964..ad0d1a401991 100644 --- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl +++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl @@ -17,9 +17,10 @@ package com.android.internal.app; import android.hardware.soundtrigger.SoundTrigger; -import android.service.voice.DetectorFailure; import android.service.voice.HotwordDetectedResult; +import android.service.voice.HotwordDetectionServiceFailure; import android.service.voice.HotwordRejectedResult; +import android.service.voice.VisualQueryDetectionServiceFailure; /** * @hide @@ -63,11 +64,31 @@ oneway interface IHotwordRecognitionStatusCallback { void onError(int status); /** - * Called when the detection fails due to an error. + * Called when the detection fails due to an error occurs in the + * {@link HotwordDetectionService}. + * + * @param hotwordDetectionServiceFailure It provides the error code, error message and + * suggested action. + */ + void onHotwordDetectionServiceFailure( + in HotwordDetectionServiceFailure hotwordDetectionServiceFailure); + + /** + * Called when the detection fails due to an error occurs in the + * {@link VisualQueryDetectionService}. + * + * @param visualQueryDetectionServiceFailure It provides the error code, error message and + * suggested action. + */ + void onVisualQueryDetectionServiceFailure( + in VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure); + + /** + * Called when the detection fails due to an unknown error occurs. * - * @param detectorFailure It provides the error code, error message and suggested action. + * @param errorMessage It provides the error message. */ - void onDetectionFailure(in DetectorFailure detectorFailure); + void onUnknownFailure(in String errorMessage); /** * Called when the recognition is paused temporarily for some reason. diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java index dbc824c384a2..cd29dace2263 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java @@ -26,6 +26,7 @@ import static android.service.voice.HotwordDetectionService.ENABLE_PROXIMITY_RES import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_SUCCESS; import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN; import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS; +import static android.service.voice.HotwordDetectionServiceFailure.ERROR_CODE_COPY_AUDIO_DATA_FAILURE; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_ERROR; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_SUCCESS; @@ -68,7 +69,6 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SharedMemory; -import android.service.voice.DetectorFailure; import android.service.voice.HotwordDetectedResult; import android.service.voice.HotwordDetectionService; import android.service.voice.HotwordDetectionServiceFailure; @@ -76,6 +76,7 @@ import android.service.voice.HotwordDetector; import android.service.voice.HotwordRejectedResult; import android.service.voice.IDspHotwordDetectionCallback; import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback; +import android.service.voice.VisualQueryDetectionServiceFailure; import android.text.TextUtils; import android.util.Pair; import android.util.Slog; @@ -124,17 +125,12 @@ abstract class DetectorSession { private static final String HOTWORD_DETECTION_OP_MESSAGE = "Providing hotword detection result to VoiceInteractionService"; - // The error codes are used for onError callback - static final int HOTWORD_DETECTION_SERVICE_DIED = - HotwordDetectionServiceFailure.ERROR_CODE_BINDING_DIED; - static final int CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION = + // The error codes are used for onHotwordDetectionServiceFailure callback. + // Define these due to lines longer than 100 characters. + static final int ONDETECTED_GOT_SECURITY_EXCEPTION = HotwordDetectionServiceFailure.ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION; - static final int CALLBACK_DETECT_TIMEOUT = - HotwordDetectionServiceFailure.ERROR_CODE_DETECT_TIMEOUT; - static final int CALLBACK_ONDETECTED_STREAM_COPY_ERROR = + static final int ONDETECTED_STREAM_COPY_ERROR = HotwordDetectionServiceFailure.ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE; - static final int CALLBACK_COPY_AUDIO_DATA_FAILURE = - HotwordDetectionServiceFailure.ERROR_CODE_COPY_AUDIO_DATA_FAILURE; // TODO: These constants need to be refined. private static final long MAX_UPDATE_TIMEOUT_MILLIS = 30000; @@ -449,11 +445,11 @@ abstract class DetectorSession { Slog.w(TAG, "Failed supplying audio data to validator", e); try { - callback.onError( - new HotwordDetectionServiceFailure(CALLBACK_COPY_AUDIO_DATA_FAILURE, + callback.onHotwordDetectionServiceFailure( + new HotwordDetectionServiceFailure(ERROR_CODE_COPY_AUDIO_DATA_FAILURE, "Copy audio data failure for external source detection.")); } catch (RemoteException ex) { - Slog.w(TAG, "Failed to report onError status: " + ex); + Slog.w(TAG, "Failed to report onHotwordDetectionServiceFailure status: " + ex); if (getDetectorType() != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) { HotwordMetricsLogger.writeDetectorEvent(getDetectorType(), HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_ERROR_EXCEPTION, @@ -538,10 +534,11 @@ abstract class DetectorSession { EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION, mVoiceInteractionServiceUid); try { - callback.onError(new HotwordDetectionServiceFailure( - CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION, - "Security exception occurs in #onDetected" - + " method.")); + callback.onHotwordDetectionServiceFailure( + new HotwordDetectionServiceFailure( + ONDETECTED_GOT_SECURITY_EXCEPTION, + "Security exception occurs in " + + "#onDetected method")); } catch (RemoteException e1) { notifyOnDetectorRemoteException(); throw e1; @@ -557,9 +554,10 @@ abstract class DetectorSession { + "IOException", e); // TODO: Write event try { - callback.onError(new HotwordDetectionServiceFailure( - CALLBACK_ONDETECTED_STREAM_COPY_ERROR, - "Copy audio stream failure.")); + callback.onHotwordDetectionServiceFailure( + new HotwordDetectionServiceFailure( + ONDETECTED_STREAM_COPY_ERROR, + "Copy audio stream failure.")); } catch (RemoteException e1) { notifyOnDetectorRemoteException(); throw e1; @@ -624,17 +622,40 @@ abstract class DetectorSession { mRemoteDetectionService = remoteDetectionService; } - void reportErrorLocked(@NonNull DetectorFailure detectorFailure) { + private void reportErrorGetRemoteException() { + if (getDetectorType() != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) { + HotwordMetricsLogger.writeDetectorEvent(getDetectorType(), + HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_ERROR_EXCEPTION, + mVoiceInteractionServiceUid); + } + notifyOnDetectorRemoteException(); + } + + void reportErrorLocked(@NonNull HotwordDetectionServiceFailure hotwordDetectionServiceFailure) { try { - mCallback.onDetectionFailure(detectorFailure); + mCallback.onHotwordDetectionServiceFailure(hotwordDetectionServiceFailure); } catch (RemoteException e) { - Slog.w(TAG, "Failed to report onError status: " + e); - if (getDetectorType() != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) { - HotwordMetricsLogger.writeDetectorEvent(getDetectorType(), - HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_ERROR_EXCEPTION, - mVoiceInteractionServiceUid); - } - notifyOnDetectorRemoteException(); + Slog.w(TAG, "Failed to call onHotwordDetectionServiceFailure: " + e); + reportErrorGetRemoteException(); + } + } + + void reportErrorLocked( + @NonNull VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure) { + try { + mCallback.onVisualQueryDetectionServiceFailure(visualQueryDetectionServiceFailure); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call onVisualQueryDetectionServiceFailure: " + e); + reportErrorGetRemoteException(); + } + } + + void reportErrorLocked(@NonNull String errorMessage) { + try { + mCallback.onUnknownFailure(errorMessage); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call onUnknownFailure: " + e); + reportErrorGetRemoteException(); } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java index f9b5111f5348..9a4fbdc4516a 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java @@ -16,6 +16,10 @@ package com.android.server.voiceinteraction; +import static android.service.voice.HotwordDetectionServiceFailure.ERROR_CODE_DETECT_TIMEOUT; +import static android.service.voice.HotwordDetectionServiceFailure.ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION; +import static android.service.voice.HotwordDetectionServiceFailure.ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE; + import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_DETECTED_EXCEPTION; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_ERROR_EXCEPTION; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_PROCESS_RESTARTED_EXCEPTION; @@ -135,9 +139,10 @@ final class DspTrustedHotwordDetectorSession extends DetectorSession { METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION, mVoiceInteractionServiceUid); try { - externalCallback.onDetectionFailure(new HotwordDetectionServiceFailure( - CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION, - "Security exception occurs in #onDetected method.")); + externalCallback.onHotwordDetectionServiceFailure( + new HotwordDetectionServiceFailure( + ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION, + "Security exception occurs in #onDetected method.")); } catch (RemoteException e1) { notifyOnDetectorRemoteException(); HotwordMetricsLogger.writeDetectorEvent( @@ -155,9 +160,10 @@ final class DspTrustedHotwordDetectorSession extends DetectorSession { } catch (IOException e) { try { Slog.w(TAG, "Ignoring #onDetected due to a IOException", e); - externalCallback.onDetectionFailure(new HotwordDetectionServiceFailure( - CALLBACK_ONDETECTED_STREAM_COPY_ERROR, - "Copy audio stream failure.")); + externalCallback.onHotwordDetectionServiceFailure( + new HotwordDetectionServiceFailure( + ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE, + "Copy audio stream failure.")); } catch (RemoteException e1) { notifyOnDetectorRemoteException(); throw e1; @@ -242,8 +248,8 @@ final class DspTrustedHotwordDetectorSession extends DetectorSession { HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT, mVoiceInteractionServiceUid); try { - externalCallback.onDetectionFailure( - new HotwordDetectionServiceFailure(CALLBACK_DETECT_TIMEOUT, + externalCallback.onHotwordDetectionServiceFailure( + new HotwordDetectionServiceFailure(ERROR_CODE_DETECT_TIMEOUT, "Timeout to response to the detection result.")); } catch (RemoteException e) { Slog.w(TAG, "Failed to report onError status: ", e); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 4fd5979b3d9f..3eabea67e890 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -56,7 +56,6 @@ import android.service.voice.HotwordDetector; import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback; import android.service.voice.ISandboxedDetectionService; import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback; -import android.service.voice.UnknownFailure; import android.service.voice.VisualQueryDetectionService; import android.service.voice.VisualQueryDetectionServiceFailure; import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity; @@ -786,8 +785,8 @@ final class HotwordDetectionConnection { VisualQueryDetectionServiceFailure.ERROR_CODE_BINDING_DIED, "Detection service is dead.")); } else { - detectorSession.reportErrorLocked(new UnknownFailure( - "Detection service is dead with unknown detection service type.")); + detectorSession.reportErrorLocked( + "Detection service is dead with unknown detection service type."); } } @@ -804,8 +803,8 @@ final class HotwordDetectionConnection { VisualQueryDetectionServiceFailure.ERROR_CODE_BIND_FAILURE, "Bind detection service failure.")); } else { - detectorSession.reportErrorLocked(new UnknownFailure( - "Bind detection service failure with unknown detection service type.")); + detectorSession.reportErrorLocked( + "Bind detection service failure with unknown detection service type."); } } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java index 367fb8166b00..f06c99729a19 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java @@ -17,6 +17,8 @@ package com.android.server.voiceinteraction; import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE; +import static android.service.voice.HotwordDetectionServiceFailure.ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION; +import static android.service.voice.HotwordDetectionServiceFailure.ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_DETECTED_EXCEPTION; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_ON_ERROR_EXCEPTION; @@ -128,9 +130,10 @@ final class SoftwareTrustedHotwordDetectorSession extends DetectorSession { METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION, mVoiceInteractionServiceUid); try { - mSoftwareCallback.onError(new HotwordDetectionServiceFailure( - CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION, - "Security exception occurs in #onDetected method.")); + mSoftwareCallback.onHotwordDetectionServiceFailure( + new HotwordDetectionServiceFailure( + ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION, + "Security exception occurs in #onDetected method.")); } catch (RemoteException e1) { notifyOnDetectorRemoteException(); HotwordMetricsLogger.writeDetectorEvent( @@ -149,9 +152,10 @@ final class SoftwareTrustedHotwordDetectorSession extends DetectorSession { Slog.w(TAG, "Ignoring #onDetected due to a IOException", e); // TODO: Write event try { - mSoftwareCallback.onError(new HotwordDetectionServiceFailure( - CALLBACK_ONDETECTED_STREAM_COPY_ERROR, - "Copy audio stream failure.")); + mSoftwareCallback.onHotwordDetectionServiceFailure( + new HotwordDetectionServiceFailure( + ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE, + "Copy audio stream failure.")); } catch (RemoteException e1) { notifyOnDetectorRemoteException(); HotwordMetricsLogger.writeDetectorEvent( diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java index afe5dab0b78b..aadb38da5469 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java @@ -110,11 +110,12 @@ final class VisualQueryDetectorSession extends DetectorSession { } catch (RemoteException e) { Slog.e(TAG, "Error delivering attention gained event.", e); try { - callback.onDetectionFailure(new VisualQueryDetectionServiceFailure( - ERROR_CODE_ILLEGAL_ATTENTION_STATE, - "Attention listener failed to switch to GAINED state.")); + callback.onVisualQueryDetectionServiceFailure( + new VisualQueryDetectionServiceFailure( + ERROR_CODE_ILLEGAL_ATTENTION_STATE, + "Attention listener failed to switch to GAINED state.")); } catch (RemoteException ex) { - Slog.v(TAG, "Fail to call onDetectionFailure"); + Slog.v(TAG, "Fail to call onVisualQueryDetectionServiceFailure"); } return; } @@ -132,11 +133,12 @@ final class VisualQueryDetectorSession extends DetectorSession { } catch (RemoteException e) { Slog.e(TAG, "Error delivering attention lost event.", e); try { - callback.onDetectionFailure(new VisualQueryDetectionServiceFailure( - ERROR_CODE_ILLEGAL_ATTENTION_STATE, - "Attention listener failed to switch to LOST state.")); + callback.onVisualQueryDetectionServiceFailure( + new VisualQueryDetectionServiceFailure( + ERROR_CODE_ILLEGAL_ATTENTION_STATE, + "Attention listener failed to switch to LOST state.")); } catch (RemoteException ex) { - Slog.v(TAG, "Fail to call onDetectionFailure"); + Slog.v(TAG, "Fail to call onVisualQueryDetectionServiceFailure"); } return; } @@ -148,9 +150,10 @@ final class VisualQueryDetectorSession extends DetectorSession { Slog.v(TAG, "BinderCallback#onQueryDetected"); if (!mEgressingData) { Slog.v(TAG, "Query should not be egressed within the unattention state."); - callback.onDetectionFailure(new VisualQueryDetectionServiceFailure( - ERROR_CODE_ILLEGAL_STREAMING_STATE, - "Cannot stream queries without attention signals.")); + callback.onVisualQueryDetectionServiceFailure( + new VisualQueryDetectionServiceFailure( + ERROR_CODE_ILLEGAL_STREAMING_STATE, + "Cannot stream queries without attention signals.")); return; } mQueryStreaming = true; @@ -164,9 +167,10 @@ final class VisualQueryDetectorSession extends DetectorSession { if (!mQueryStreaming) { Slog.v(TAG, "Query streaming state signal FINISHED is block since there is" + " no active query being streamed."); - callback.onDetectionFailure(new VisualQueryDetectionServiceFailure( - ERROR_CODE_ILLEGAL_STREAMING_STATE, - "Cannot send FINISHED signal with no query streamed.")); + callback.onVisualQueryDetectionServiceFailure( + new VisualQueryDetectionServiceFailure( + ERROR_CODE_ILLEGAL_STREAMING_STATE, + "Cannot send FINISHED signal with no query streamed.")); return; } callback.onQueryFinished(); @@ -179,9 +183,10 @@ final class VisualQueryDetectorSession extends DetectorSession { if (!mQueryStreaming) { Slog.v(TAG, "Query streaming state signal REJECTED is block since there is" + " no active query being streamed."); - callback.onDetectionFailure(new VisualQueryDetectionServiceFailure( - ERROR_CODE_ILLEGAL_STREAMING_STATE, - "Cannot send REJECTED signal with no query streamed.")); + callback.onVisualQueryDetectionServiceFailure( + new VisualQueryDetectionServiceFailure( + ERROR_CODE_ILLEGAL_STREAMING_STATE, + "Cannot send REJECTED signal with no query streamed.")); return; } callback.onQueryRejected(); |