summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author lpeter <lpeter@google.com> 2022-12-28 18:50:58 +0000
committer Peter Li <lpeter@google.com> 2023-02-17 11:53:18 +0000
commit321950f3684ddff31ae52dc75b491795dfa7fbb0 (patch)
treee1c1d3f771d375da42f21fec2c0f7ddce6697417
parent7137d9165d25c7ddec6fe92e9d83a83ceceeafb0 (diff)
Improve error handling for Trusted Hotword
Add a new callback with an DetectorFailure parameter to let the assistant know what went wrong during using the hotword detector. Bug: 256780491 Bug: 261012843 Test: atest CtsVoiceInteractionTestCases Change-Id: I0b7d9625abfa10f93ad8564e85faedd1db4fa51d
-rw-r--r--core/api/system-current.txt5
-rw-r--r--core/java/android/service/voice/AbstractDetector.java9
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java21
-rw-r--r--core/java/android/service/voice/HotwordDetector.java19
-rw-r--r--core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl3
-rw-r--r--core/java/android/service/voice/IVisualQueryDetectionVoiceInteractionCallback.aidl5
-rw-r--r--core/java/android/service/voice/SoftwareHotwordDetector.java19
-rw-r--r--core/java/android/service/voice/VisualQueryDetector.java14
-rw-r--r--core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl8
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java34
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java13
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java4
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java9
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java27
14 files changed, 153 insertions, 37 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 6581c421f970..5f83313895bf 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -13141,7 +13141,8 @@ package android.service.voice {
public static interface HotwordDetector.Callback {
method public void onDetected(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload);
- method public void onError();
+ method @Deprecated public void onError();
+ method public default void onFailure(@NonNull android.service.voice.DetectorFailure);
method public void onHotwordDetectionServiceInitialized(int);
method public void onHotwordDetectionServiceRestarted();
method public void onRecognitionPaused();
@@ -13202,7 +13203,7 @@ package android.service.voice {
}
public static interface VisualQueryDetector.Callback {
- method public void onError();
+ method public void onFailure(@NonNull android.service.voice.DetectorFailure);
method public void onQueryDetected(@NonNull String);
method public void onQueryFinished();
method public void onQueryRejected();
diff --git a/core/java/android/service/voice/AbstractDetector.java b/core/java/android/service/voice/AbstractDetector.java
index 39c2b98fd9bc..466bc0520ee5 100644
--- a/core/java/android/service/voice/AbstractDetector.java
+++ b/core/java/android/service/voice/AbstractDetector.java
@@ -231,9 +231,12 @@ abstract class AbstractDetector implements HotwordDetector {
/** Called when the detection fails due to an error. */
@Override
- public void onError() {
- Slog.v(TAG, "BinderCallback#onError");
- Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> mCallback.onError()));
+ public void onError(DetectorFailure detectorFailure) {
+ Slog.v(TAG, "BinderCallback#onError detectorFailure: " + detectorFailure);
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> {
+ mCallback.onFailure(detectorFailure != null ? detectorFailure
+ : new UnknownFailure("Error data is null"));
+ }));
}
@Override
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 48b7a5915658..bb3f03d70308 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -732,7 +732,13 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
*/
public abstract void onDetected(@NonNull EventPayload eventPayload);
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ *
+ * @deprecated Use {@link HotwordDetector.Callback#onError(DetectorFailure)} instead.
+ */
+ @Deprecated
+ @Override
public abstract void onError();
/** {@inheritDoc} */
@@ -1658,10 +1664,19 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
@Override
public void onError(int status) {
Slog.i(TAG, "onError: " + status);
- mHandler.sendEmptyMessage(MSG_DETECTION_ERROR);
+ // 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();
}
@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();
+ }
+ @Override
public void onRecognitionPaused() {
Slog.i(TAG, "onRecognitionPaused");
mHandler.sendEmptyMessage(MSG_DETECTION_PAUSE);
@@ -1716,7 +1731,7 @@ public class AlwaysOnHotwordDetector extends AbstractDetector {
mExternalCallback.onDetected((EventPayload) message.obj);
break;
case MSG_DETECTION_ERROR:
- mExternalCallback.onError();
+ mExternalCallback.onFailure((DetectorFailure) msg.obj);
break;
case MSG_DETECTION_PAUSE:
mExternalCallback.onRecognitionPaused();
diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java
index 562277e9d097..22d97b7bbcaa 100644
--- a/core/java/android/service/voice/HotwordDetector.java
+++ b/core/java/android/service/voice/HotwordDetector.java
@@ -231,10 +231,29 @@ public interface HotwordDetector {
/**
* Called when the detection fails due to an error.
+ *
+ * @deprecated On Android 14 and above, implement {@link #onFailure(DetectorFailure)}
+ * instead.
*/
+ @Deprecated
void onError();
/**
+ * Called when the detection fails due to an error, the subclasses of
+ * {@link DetectorFailure} 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 detectorFailure It provides the error code, error message and suggested action.
+ */
+ default void onFailure(@NonNull DetectorFailure detectorFailure) {
+ onError();
+ }
+
+ /**
* Called when the recognition is paused temporarily for some reason.
* This is an informational callback, and the clients shouldn't be doing anything here
* except showing an indication on their UI if they have to.
diff --git a/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl b/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
index 61ac68be9775..f800c1ee22d6 100644
--- a/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
+++ b/core/java/android/service/voice/IMicrophoneHotwordDetectionVoiceInteractionCallback.aidl
@@ -17,6 +17,7 @@
package android.service.voice;
import android.media.AudioFormat;
+import android.service.voice.DetectorFailure;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordRejectedResult;
@@ -38,7 +39,7 @@ oneway interface IMicrophoneHotwordDetectionVoiceInteractionCallback {
/**
* Called when the detection fails due to an error.
*/
- void onError();
+ void onError(in DetectorFailure detectorFailure);
/**
* 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 2eb24706da30..1a935c0acbf6 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.media.AudioFormat;
+import android.service.voice.DetectorFailure;
/**
* Callback for returning the detected result from the VisualQueryDetectionService.
@@ -43,6 +43,5 @@ oneway interface IVisualQueryDetectionVoiceInteractionCallback {
/**
* Called when the detection fails due to an error.
*/
- void onError();
-
+ void onDetectionFailure(in DetectorFailure detectorFailure);
}
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 6e17bd0e656d..d4b6f3bf5c4c 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -169,9 +169,12 @@ class SoftwareHotwordDetector extends AbstractDetector {
/** Called when the detection fails due to an error. */
@Override
- public void onError() {
- Slog.v(TAG, "BinderCallback#onError");
- Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> mCallback.onError()));
+ public void onError(DetectorFailure detectorFailure) {
+ Slog.v(TAG, "BinderCallback#onError detectorFailure: " + detectorFailure);
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> {
+ mCallback.onFailure(detectorFailure != null ? detectorFailure
+ : new UnknownFailure("Error data is null"));
+ }));
}
@Override
@@ -222,6 +225,16 @@ class SoftwareHotwordDetector extends AbstractDetector {
if (DEBUG) {
Slog.i(TAG, "Ignored #onError (" + status + ") event");
}
+ // TODO: Check if we still need to implement this method with DetectorFailure mechanism.
+ }
+
+ @Override
+ public void onDetectionFailure(DetectorFailure detectorFailure) throws RemoteException {
+ Slog.v(TAG, "onDetectionFailure detectorFailure: " + detectorFailure);
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> {
+ mCallback.onFailure(detectorFailure != null ? detectorFailure
+ : new UnknownFailure("Error data is null"));
+ }));
}
@Override
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index e4c47ef7cee3..0be3253fc570 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -216,8 +216,7 @@ public class VisualQueryDetector {
/**
* Called when the detection fails due to an error.
*/
- //TODO(b/265390855): Replace this callback with the new onError(DetectorError) design.
- void onError();
+ void onFailure(@NonNull DetectorFailure detectorFailure);
}
private class VisualQueryDetectorInitializationDelegate extends AbstractDetector {
@@ -294,12 +293,11 @@ public class VisualQueryDetector {
/** Called when the detection fails due to an error. */
@Override
- public void onError() {
- Slog.v(TAG, "BinderCallback#onError");
+ public void onDetectionFailure(DetectorFailure detectorFailure) {
+ Slog.v(TAG, "BinderCallback#onDetectionFailure");
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
- () -> mCallback.onError()));
+ () -> mCallback.onFailure(detectorFailure)));
}
-
}
@@ -373,5 +371,9 @@ public class VisualQueryDetector {
Slog.v(TAG, "Initialization Error: (" + status + ")");
// Do nothing
}
+
+ @Override
+ public void onDetectionFailure(DetectorFailure detectorFailure) throws RemoteException {
+ }
}
}
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index d0214e6e0082..813febf33964 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -17,6 +17,7 @@
package com.android.internal.app;
import android.hardware.soundtrigger.SoundTrigger;
+import android.service.voice.DetectorFailure;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordRejectedResult;
@@ -62,6 +63,13 @@ oneway interface IHotwordRecognitionStatusCallback {
void onError(int status);
/**
+ * Called when the detection fails due to an error.
+ *
+ * @param detectorFailure It provides the error code, error message and suggested action.
+ */
+ void onDetectionFailure(in DetectorFailure detectorFailure);
+
+ /**
* Called when the recognition is paused temporarily for some reason.
*/
void onRecognitionPaused();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index afee94000edc..ec9bd2fbfa6d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -70,6 +70,7 @@ import android.os.RemoteException;
import android.os.SharedMemory;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
+import android.service.voice.HotwordDetectionServiceFailure;
import android.service.voice.HotwordDetector;
import android.service.voice.HotwordRejectedResult;
import android.service.voice.IDspHotwordDetectionCallback;
@@ -122,10 +123,16 @@ abstract class DetectorSession {
"Providing hotword detection result to VoiceInteractionService";
// The error codes are used for onError callback
- static final int HOTWORD_DETECTION_SERVICE_DIED = -1;
- static final int CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION = -2;
- static final int CALLBACK_DETECT_TIMEOUT = -3;
- static final int CALLBACK_ONDETECTED_STREAM_COPY_ERROR = -4;
+ static final int HOTWORD_DETECTION_SERVICE_DIED =
+ HotwordDetectionServiceFailure.ERROR_CODE_BINDING_DIED;
+ static final int CALLBACK_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 =
+ 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;
@@ -426,7 +433,9 @@ abstract class DetectorSession {
Slog.w(TAG, "Failed supplying audio data to validator", e);
try {
- callback.onError();
+ callback.onError(
+ new HotwordDetectionServiceFailure(CALLBACK_COPY_AUDIO_DATA_FAILURE,
+ "Copy audio data failure for external source detection."));
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to report onError status: " + ex);
if (getDetectorType() != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
@@ -505,7 +514,10 @@ abstract class DetectorSession {
getDetectorType(),
EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION,
mVoiceInteractionServiceUid);
- callback.onError();
+ callback.onError(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION,
+ "Security exception occurs in #onDetected"
+ + " method."));
return;
}
HotwordDetectedResult newResult;
@@ -514,7 +526,9 @@ abstract class DetectorSession {
.startCopyingAudioStreams(triggerResult);
} catch (IOException e) {
// TODO: Write event
- callback.onError();
+ callback.onError(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_STREAM_COPY_ERROR,
+ "Copy audio stream failure."));
return;
}
callback.onDetected(newResult, /* audioFormat= */ null,
@@ -569,9 +583,11 @@ abstract class DetectorSession {
mRemoteDetectionService = remoteDetectionService;
}
- void reportErrorLocked(int status) {
+ void reportErrorLocked(int errorCode, @NonNull String errorMessage) {
try {
- mCallback.onError(status);
+ // TODO: Use instanceof(this) to get different detector to set the right error source.
+ mCallback.onDetectionFailure(
+ new HotwordDetectionServiceFailure(errorCode, errorMessage));
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report onError status: " + e);
if (getDetectorType() != HotwordDetector.DETECTOR_TYPE_VISUAL_QUERY_DETECTOR) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
index cb5b9300c197..63e0f466bb10 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java
@@ -34,6 +34,7 @@ import android.os.RemoteException;
import android.os.SharedMemory;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
+import android.service.voice.HotwordDetectionServiceFailure;
import android.service.voice.HotwordDetector;
import android.service.voice.HotwordRejectedResult;
import android.service.voice.IDspHotwordDetectionCallback;
@@ -130,7 +131,9 @@ final class DspTrustedHotwordDetectorSession extends DetectorSession {
HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP,
METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION,
mVoiceInteractionServiceUid);
- externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
+ externalCallback.onDetectionFailure(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION,
+ "Security exception occurs in #onDetected method."));
return;
}
saveProximityValueToBundle(result);
@@ -138,7 +141,9 @@ final class DspTrustedHotwordDetectorSession extends DetectorSession {
try {
newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result);
} catch (IOException e) {
- externalCallback.onError(CALLBACK_ONDETECTED_STREAM_COPY_ERROR);
+ externalCallback.onDetectionFailure(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_STREAM_COPY_ERROR,
+ "Copy audio stream failure."));
return;
}
externalCallback.onKeyphraseDetected(recognitionEvent, newResult);
@@ -201,7 +206,9 @@ final class DspTrustedHotwordDetectorSession extends DetectorSession {
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT,
mVoiceInteractionServiceUid);
try {
- externalCallback.onError(CALLBACK_DETECT_TIMEOUT);
+ externalCallback.onDetectionFailure(
+ new HotwordDetectionServiceFailure(CALLBACK_DETECT_TIMEOUT,
+ "Timeout to response to the detection result."));
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report onError status: ", e);
HotwordMetricsLogger.writeDetectorEvent(
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index b672b00fa8c3..1ba397529bbd 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -690,8 +690,8 @@ final class HotwordDetectionConnection {
//TODO(b265535257): report error to either service only.
synchronized (HotwordDetectionConnection.this.mLock) {
runForEachDetectorSessionLocked((session) -> {
- session.reportErrorLocked(
- DetectorSession.HOTWORD_DETECTION_SERVICE_DIED);
+ session.reportErrorLocked(DetectorSession.HOTWORD_DETECTION_SERVICE_DIED,
+ "Detection service is dead.");
});
}
// Can improve to log exit reason if needed
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
index 3ad963d21943..522d832c41bc 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java
@@ -33,6 +33,7 @@ import android.os.RemoteException;
import android.os.SharedMemory;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
+import android.service.voice.HotwordDetectionServiceFailure;
import android.service.voice.HotwordDetector;
import android.service.voice.HotwordRejectedResult;
import android.service.voice.IDspHotwordDetectionCallback;
@@ -121,7 +122,9 @@ final class SoftwareTrustedHotwordDetectorSession extends DetectorSession {
HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE,
METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION,
mVoiceInteractionServiceUid);
- mSoftwareCallback.onError();
+ mSoftwareCallback.onError(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION,
+ "Security exception occurs in #onDetected method."));
return;
}
saveProximityValueToBundle(result);
@@ -130,7 +133,9 @@ final class SoftwareTrustedHotwordDetectorSession extends DetectorSession {
newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result);
} catch (IOException e) {
// TODO: Write event
- mSoftwareCallback.onError();
+ mSoftwareCallback.onError(new HotwordDetectionServiceFailure(
+ CALLBACK_ONDETECTED_STREAM_COPY_ERROR,
+ "Copy audio stream failure."));
return;
}
mSoftwareCallback.onDetected(newResult, null, null);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
index 33150d8789eb..c397812b4158 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
@@ -16,6 +16,9 @@
package com.android.server.voiceinteraction;
+import static android.service.voice.VisualQueryDetectionServiceFailure.ERROR_CODE_ILLEGAL_ATTENTION_STATE;
+import static android.service.voice.VisualQueryDetectionServiceFailure.ERROR_CODE_ILLEGAL_STREAMING_STATE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -30,6 +33,7 @@ import android.service.voice.IDetectorSessionVisualQueryDetectionCallback;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
import android.service.voice.ISandboxedDetectionService;
import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
+import android.service.voice.VisualQueryDetectionServiceFailure;
import android.util.Slog;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
@@ -102,6 +106,13 @@ final class VisualQueryDetectorSession extends DetectorSession {
mAttentionListener.onAttentionGained();
} 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."));
+ } catch (RemoteException ex) {
+ Slog.v(TAG, "Fail to call onDetectionFailure");
+ }
return;
}
}
@@ -117,6 +128,13 @@ final class VisualQueryDetectorSession extends DetectorSession {
mAttentionListener.onAttentionLost();
} 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."));
+ } catch (RemoteException ex) {
+ Slog.v(TAG, "Fail to call onDetectionFailure");
+ }
return;
}
}
@@ -127,6 +145,9 @@ 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."));
return;
}
mQueryStreaming = true;
@@ -140,6 +161,9 @@ 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."));
return;
}
callback.onQueryFinished();
@@ -152,6 +176,9 @@ 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."));
return;
}
callback.onQueryRejected();