1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.service.voice;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.annotation.TestApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.text.TextUtils;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 
30 /**
31  * This class is used by the assistant application to know what went wrong during using the
32  * {@link HotwordDetector} and which action that the application should take. When an error occurs
33  * from Dsp hotword detection, software hotword detection and {@link HotwordDetectionService}, the
34  * system will send {@link HotwordDetectionServiceFailure} which contains the error code, error
35  * message and the suggested action to help the assistant application to take the next action.
36  *
37  * @hide
38  */
39 @SystemApi
40 public final class HotwordDetectionServiceFailure implements Parcelable {
41 
42     /**
43      * An error code which means an unknown error occurs.
44      */
45     public static final int ERROR_CODE_UNKNOWN = 0;
46 
47     /**
48      * Indicates that the system server binds hotword detection service failure.
49      */
50     public static final int ERROR_CODE_BIND_FAILURE = 1;
51 
52     /**
53      * Indicates that the hotword detection service is dead.
54      */
55     public static final int ERROR_CODE_BINDING_DIED = 2;
56 
57     /**
58      * Indicates to copy audio data failure for external source detection.
59      */
60     public static final int ERROR_CODE_COPY_AUDIO_DATA_FAILURE = 3;
61 
62     /**
63      * Indicates that the detection service doesn’t respond to the detection result before timeout.
64      */
65     public static final int ERROR_CODE_DETECT_TIMEOUT = 4;
66 
67     /**
68      * Indicates that the security exception occurs in #onDetected method.
69      */
70     public static final int ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION = 5;
71 
72     /**
73      * Indicates to copy the audio stream failure in #onDetected method.
74      */
75     public static final int ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE = 6;
76 
77     /**
78      * Indicates that the remote exception occurs when calling callback method.
79      */
80     public static final int ERROR_CODE_REMOTE_EXCEPTION = 7;
81 
82     /**
83      * @hide
84      */
85     @IntDef(prefix = {"ERROR_CODE_"}, value = {
86             ERROR_CODE_UNKNOWN,
87             ERROR_CODE_BIND_FAILURE,
88             ERROR_CODE_BINDING_DIED,
89             ERROR_CODE_COPY_AUDIO_DATA_FAILURE,
90             ERROR_CODE_DETECT_TIMEOUT,
91             ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION,
92             ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE,
93             ERROR_CODE_REMOTE_EXCEPTION
94     })
95     @Retention(RetentionPolicy.SOURCE)
96     public @interface HotwordDetectionServiceErrorCode {}
97 
98     private int mErrorCode = ERROR_CODE_UNKNOWN;
99     private String mErrorMessage = "Unknown";
100 
101     /**
102      * @hide
103      */
104     @TestApi
HotwordDetectionServiceFailure(int errorCode, @NonNull String errorMessage)105     public HotwordDetectionServiceFailure(int errorCode, @NonNull String errorMessage) {
106         if (TextUtils.isEmpty(errorMessage)) {
107             throw new IllegalArgumentException("errorMessage is empty or null.");
108         }
109         mErrorCode = errorCode;
110         mErrorMessage = errorMessage;
111     }
112 
113     /**
114      * Returns the error code.
115      */
116     @HotwordDetectionServiceErrorCode
getErrorCode()117     public int getErrorCode() {
118         return mErrorCode;
119     }
120 
121     /**
122      * Returns the error message.
123      */
124     @NonNull
getErrorMessage()125     public String getErrorMessage() {
126         return mErrorMessage;
127     }
128 
129     /**
130      * Returns the suggested action.
131      */
132     @FailureSuggestedAction.FailureSuggestedActionDef
getSuggestedAction()133     public int getSuggestedAction() {
134         switch (mErrorCode) {
135             case ERROR_CODE_BIND_FAILURE:
136             case ERROR_CODE_BINDING_DIED:
137             case ERROR_CODE_REMOTE_EXCEPTION:
138                 return FailureSuggestedAction.RECREATE_DETECTOR;
139             case ERROR_CODE_DETECT_TIMEOUT:
140             case ERROR_CODE_ON_DETECTED_SECURITY_EXCEPTION:
141             case ERROR_CODE_ON_DETECTED_STREAM_COPY_FAILURE:
142                 return FailureSuggestedAction.RESTART_RECOGNITION;
143             default:
144                 return FailureSuggestedAction.NONE;
145         }
146     }
147 
148     @Override
describeContents()149     public int describeContents() {
150         return 0;
151     }
152 
153     @Override
writeToParcel(@onNull Parcel dest, int flags)154     public void writeToParcel(@NonNull Parcel dest, int flags) {
155         dest.writeInt(mErrorCode);
156         dest.writeString8(mErrorMessage);
157     }
158 
159     @Override
toString()160     public String toString() {
161         return "HotwordDetectionServiceFailure { errorCode = " + mErrorCode + ", errorMessage = "
162                 + mErrorMessage + " }";
163     }
164 
165     public static final @NonNull Parcelable.Creator<HotwordDetectionServiceFailure> CREATOR =
166             new Parcelable.Creator<HotwordDetectionServiceFailure>() {
167                 @Override
168                 public HotwordDetectionServiceFailure[] newArray(int size) {
169                     return new HotwordDetectionServiceFailure[size];
170                 }
171 
172                 @Override
173                 public HotwordDetectionServiceFailure createFromParcel(@NonNull Parcel in) {
174                     return new HotwordDetectionServiceFailure(in.readInt(), in.readString8());
175                 }
176             };
177 }
178