blob: a74871d29041af15eeea52eb6c5d70cb1477aadd [file] [log] [blame]
Sandeepd7018202014-07-10 15:15:39 -07001/**
Eric Laurente48188c2014-04-18 17:44:11 -07002 * Copyright (C) 2014 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
17package android.hardware.soundtrigger;
18
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080019import static android.system.OsConstants.EINVAL;
20import static android.system.OsConstants.ENODEV;
21import static android.system.OsConstants.ENOSYS;
22import static android.system.OsConstants.EPERM;
23import static android.system.OsConstants.EPIPE;
24
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080025import static java.util.Objects.requireNonNull;
26
Nicholas Ambur7092a562019-12-16 11:18:55 -080027import android.annotation.IntDef;
Aurimas Liutikas4d1699d2019-08-28 13:01:05 -070028import android.annotation.NonNull;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080029import android.annotation.Nullable;
30import android.annotation.SystemApi;
jiabin1f4b4dd2019-03-18 18:07:03 -070031import android.app.ActivityThread;
Artur Satayev26958002019-12-10 17:47:52 +000032import android.compat.annotation.UnsupportedAppUsage;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080033import android.content.Context;
Eric Laurentd3b82232014-07-30 08:57:39 -070034import android.media.AudioFormat;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080035import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
36import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
Ytai Ben-Tsvi2e8f78b2020-01-15 11:57:34 -080037import android.media.soundtrigger_middleware.Status;
Eric Laurente48188c2014-04-18 17:44:11 -070038import android.os.Handler;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080039import android.os.IBinder;
40import android.os.Looper;
Sandeep Siddhartha05589722014-07-17 16:21:54 -070041import android.os.Parcel;
42import android.os.Parcelable;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080043import android.os.RemoteException;
44import android.os.ServiceManager;
Ytai Ben-Tsvi2e8f78b2020-01-15 11:57:34 -080045import android.os.ServiceSpecificException;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080046import android.util.Log;
Eric Laurente48188c2014-04-18 17:44:11 -070047
Nicholas Ambur7092a562019-12-16 11:18:55 -080048import java.lang.annotation.Retention;
49import java.lang.annotation.RetentionPolicy;
Eric Laurente48188c2014-04-18 17:44:11 -070050import java.util.ArrayList;
Sandeep Siddhartha05589722014-07-17 16:21:54 -070051import java.util.Arrays;
Nicholas Amburef84fc42020-01-14 20:28:37 -080052import java.util.Locale;
Eric Laurente48188c2014-04-18 17:44:11 -070053import java.util.UUID;
54
55/**
Ytai Ben-Tsvic59b2802020-01-07 14:08:16 -080056 * The SoundTrigger class provides access to the service managing the sound trigger HAL.
Eric Laurente48188c2014-04-18 17:44:11 -070057 *
58 * @hide
59 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080060@SystemApi
Eric Laurente48188c2014-04-18 17:44:11 -070061public class SoundTrigger {
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -080062 private static final String TAG = "SoundTrigger";
Eric Laurente48188c2014-04-18 17:44:11 -070063
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080064 private SoundTrigger() {
65 }
66
67 /**
68 * Status code used when the operation succeeded
69 */
Eric Laurente48188c2014-04-18 17:44:11 -070070 public static final int STATUS_OK = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080071 /** @hide */
Eric Laurente48188c2014-04-18 17:44:11 -070072 public static final int STATUS_ERROR = Integer.MIN_VALUE;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080073 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020074 public static final int STATUS_PERMISSION_DENIED = -EPERM;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080075 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020076 public static final int STATUS_NO_INIT = -ENODEV;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080077 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020078 public static final int STATUS_BAD_VALUE = -EINVAL;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080079 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020080 public static final int STATUS_DEAD_OBJECT = -EPIPE;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080081 /** @hide */
Lazar Trsic8ea56f62015-07-07 17:31:20 +020082 public static final int STATUS_INVALID_OPERATION = -ENOSYS;
Eric Laurente48188c2014-04-18 17:44:11 -070083
84 /*****************************************************************************
85 * A ModuleProperties describes a given sound trigger hardware module
86 * managed by the native sound trigger service. Each module has a unique
87 * ID used to target any API call to this paricular module. Module
88 * properties are returned by listModules() method.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -080089 *
Eric Laurente48188c2014-04-18 17:44:11 -070090 ****************************************************************************/
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -070091 public static final class ModuleProperties implements Parcelable {
Nicholas Ambur7092a562019-12-16 11:18:55 -080092
93 /**
94 * Bit field values of AudioCapabilities supported by the implemented HAL
95 * driver.
96 * @hide
97 */
98 @Retention(RetentionPolicy.SOURCE)
99 @IntDef(flag = true, prefix = { "AUDIO_CAPABILITY_" }, value = {
Nicholas Amburce5cd842020-02-04 13:39:59 -0800100 AUDIO_CAPABILITY_ECHO_CANCELLATION,
101 AUDIO_CAPABILITY_NOISE_SUPPRESSION
Nicholas Ambur7092a562019-12-16 11:18:55 -0800102 })
103 public @interface AudioCapabilities {}
104
105 /**
106 * If set the underlying module supports AEC.
107 * Describes bit field {@link ModuleProperties#audioCapabilities}
108 */
Nicholas Amburce5cd842020-02-04 13:39:59 -0800109 public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION = 0x1;
Nicholas Ambur7092a562019-12-16 11:18:55 -0800110 /**
111 * If set, the underlying module supports noise suppression.
112 * Describes bit field {@link ModuleProperties#audioCapabilities}
113 */
Nicholas Amburce5cd842020-02-04 13:39:59 -0800114 public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION = 0x2;
Nicholas Ambur7092a562019-12-16 11:18:55 -0800115
Eric Laurente48188c2014-04-18 17:44:11 -0700116 /** Unique module ID provided by the native service */
117 public final int id;
118
119 /** human readable voice detection engine implementor */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -0700120 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700121 public final String implementor;
122
123 /** human readable voice detection engine description */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -0700124 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700125 public final String description;
126
127 /** Unique voice engine Id (changes with each version) */
Nicholas Ambur1aa4b4b2019-08-22 12:13:29 -0700128 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700129 public final UUID uuid;
130
131 /** Voice detection engine version */
132 public final int version;
133
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800134 /**
135 * String naming the architecture used for running the supported models.
136 * (eg. a platform running models on a DSP could implement this string to convey the DSP
137 * architecture used)
138 */
139 @NonNull
140 public final String supportedModelArch;
141
Eric Laurente48188c2014-04-18 17:44:11 -0700142 /** Maximum number of active sound models */
143 public final int maxSoundModels;
144
145 /** Maximum number of key phrases */
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700146 public final int maxKeyphrases;
Eric Laurente48188c2014-04-18 17:44:11 -0700147
148 /** Maximum number of users per key phrase */
149 public final int maxUsers;
150
151 /** Supported recognition modes (bit field, RECOGNITION_MODE_VOICE_TRIGGER ...) */
Nicholas Amburef84fc42020-01-14 20:28:37 -0800152 @RecognitionModes
Eric Laurente48188c2014-04-18 17:44:11 -0700153 public final int recognitionModes;
154
155 /** Supports seamless transition to capture mode after recognition */
156 public final boolean supportsCaptureTransition;
157
158 /** Maximum buffering capacity in ms if supportsCaptureTransition() is true */
159 public final int maxBufferMs;
160
161 /** Supports capture by other use cases while detection is active */
162 public final boolean supportsConcurrentCapture;
163
164 /** Rated power consumption when detection is active with TDB silence/sound/speech ratio */
165 public final int powerConsumptionMw;
166
Eric Laurentd3b82232014-07-30 08:57:39 -0700167 /** Returns the trigger (key phrase) capture in the binary data of the
168 * recognition callback event */
169 public final boolean returnsTriggerInEvent;
170
Nicholas Ambur7092a562019-12-16 11:18:55 -0800171 /**
172 * Bit field encoding of the AudioCapabilities
173 * supported by the firmware.
174 */
175 @AudioCapabilities
176 public final int audioCapabilities;
177
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800178 ModuleProperties(int id, @NonNull String implementor, @NonNull String description,
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800179 @NonNull String uuid, int version, @NonNull String supportedModelArch,
Nicholas Amburef84fc42020-01-14 20:28:37 -0800180 int maxSoundModels, int maxKeyphrases, int maxUsers,
181 @RecognitionModes int recognitionModes, boolean supportsCaptureTransition,
182 int maxBufferMs, boolean supportsConcurrentCapture, int powerConsumptionMw,
Nicholas Ambur7092a562019-12-16 11:18:55 -0800183 boolean returnsTriggerInEvent, int audioCapabilities) {
Eric Laurente48188c2014-04-18 17:44:11 -0700184 this.id = id;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800185 this.implementor = requireNonNull(implementor);
186 this.description = requireNonNull(description);
187 this.uuid = UUID.fromString(requireNonNull(uuid));
Eric Laurente48188c2014-04-18 17:44:11 -0700188 this.version = version;
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800189 this.supportedModelArch = requireNonNull(supportedModelArch);
Eric Laurente48188c2014-04-18 17:44:11 -0700190 this.maxSoundModels = maxSoundModels;
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700191 this.maxKeyphrases = maxKeyphrases;
Eric Laurente48188c2014-04-18 17:44:11 -0700192 this.maxUsers = maxUsers;
193 this.recognitionModes = recognitionModes;
194 this.supportsCaptureTransition = supportsCaptureTransition;
195 this.maxBufferMs = maxBufferMs;
196 this.supportsConcurrentCapture = supportsConcurrentCapture;
197 this.powerConsumptionMw = powerConsumptionMw;
Eric Laurentd3b82232014-07-30 08:57:39 -0700198 this.returnsTriggerInEvent = returnsTriggerInEvent;
Nicholas Ambur7092a562019-12-16 11:18:55 -0800199 this.audioCapabilities = audioCapabilities;
Eric Laurente48188c2014-04-18 17:44:11 -0700200 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700201
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700202 public static final @android.annotation.NonNull Parcelable.Creator<ModuleProperties> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700203 = new Parcelable.Creator<ModuleProperties>() {
204 public ModuleProperties createFromParcel(Parcel in) {
205 return ModuleProperties.fromParcel(in);
206 }
207
208 public ModuleProperties[] newArray(int size) {
209 return new ModuleProperties[size];
210 }
211 };
212
213 private static ModuleProperties fromParcel(Parcel in) {
214 int id = in.readInt();
215 String implementor = in.readString();
216 String description = in.readString();
217 String uuid = in.readString();
218 int version = in.readInt();
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800219 String supportedModelArch = in.readString();
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700220 int maxSoundModels = in.readInt();
221 int maxKeyphrases = in.readInt();
222 int maxUsers = in.readInt();
223 int recognitionModes = in.readInt();
224 boolean supportsCaptureTransition = in.readByte() == 1;
225 int maxBufferMs = in.readInt();
226 boolean supportsConcurrentCapture = in.readByte() == 1;
227 int powerConsumptionMw = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -0700228 boolean returnsTriggerInEvent = in.readByte() == 1;
Nicholas Ambur7092a562019-12-16 11:18:55 -0800229 int audioCapabilities = in.readInt();
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700230 return new ModuleProperties(id, implementor, description, uuid, version,
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800231 supportedModelArch, maxSoundModels, maxKeyphrases, maxUsers, recognitionModes,
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700232 supportsCaptureTransition, maxBufferMs, supportsConcurrentCapture,
Nicholas Ambur7092a562019-12-16 11:18:55 -0800233 powerConsumptionMw, returnsTriggerInEvent, audioCapabilities);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700234 }
235
236 @Override
237 public void writeToParcel(Parcel dest, int flags) {
238 dest.writeInt(id);
239 dest.writeString(implementor);
240 dest.writeString(description);
241 dest.writeString(uuid.toString());
242 dest.writeInt(version);
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800243 dest.writeString(supportedModelArch);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700244 dest.writeInt(maxSoundModels);
245 dest.writeInt(maxKeyphrases);
246 dest.writeInt(maxUsers);
247 dest.writeInt(recognitionModes);
248 dest.writeByte((byte) (supportsCaptureTransition ? 1 : 0));
249 dest.writeInt(maxBufferMs);
250 dest.writeByte((byte) (supportsConcurrentCapture ? 1 : 0));
251 dest.writeInt(powerConsumptionMw);
Eric Laurentd3b82232014-07-30 08:57:39 -0700252 dest.writeByte((byte) (returnsTriggerInEvent ? 1 : 0));
Nicholas Ambur7092a562019-12-16 11:18:55 -0800253 dest.writeInt(audioCapabilities);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700254 }
255
256 @Override
257 public int describeContents() {
258 return 0;
259 }
260
261 @Override
262 public String toString() {
263 return "ModuleProperties [id=" + id + ", implementor=" + implementor + ", description="
Nicholas Ambur38027cd2019-12-16 00:06:19 -0800264 + description + ", uuid=" + uuid + ", version=" + version
265 + " , supportedModelArch=" + supportedModelArch + ", maxSoundModels="
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700266 + maxSoundModels + ", maxKeyphrases=" + maxKeyphrases + ", maxUsers="
267 + maxUsers + ", recognitionModes=" + recognitionModes
268 + ", supportsCaptureTransition=" + supportsCaptureTransition + ", maxBufferMs="
269 + maxBufferMs + ", supportsConcurrentCapture=" + supportsConcurrentCapture
Eric Laurentd3b82232014-07-30 08:57:39 -0700270 + ", powerConsumptionMw=" + powerConsumptionMw
Nicholas Ambur7092a562019-12-16 11:18:55 -0800271 + ", returnsTriggerInEvent=" + returnsTriggerInEvent
272 + ", audioCapabilities=" + audioCapabilities + "]";
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700273 }
Eric Laurente48188c2014-04-18 17:44:11 -0700274 }
275
Nicholas Amburef84fc42020-01-14 20:28:37 -0800276 /**
Eric Laurente48188c2014-04-18 17:44:11 -0700277 * A SoundModel describes the attributes and contains the binary data used by the hardware
278 * implementation to detect a particular sound pattern.
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700279 * A specialized version {@link KeyphraseSoundModel} is defined for key phrase
Eric Laurente48188c2014-04-18 17:44:11 -0700280 * sound models.
Nicholas Amburef84fc42020-01-14 20:28:37 -0800281 */
Eric Laurente48188c2014-04-18 17:44:11 -0700282 public static class SoundModel {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800283
284 /** @hide */
285 @Retention(RetentionPolicy.SOURCE)
286 @IntDef({
287 TYPE_GENERIC_SOUND,
288 TYPE_KEYPHRASE,
289 TYPE_UNKNOWN,
290 })
291 public @interface SoundModelType {}
292
293 /**
294 * Undefined sound model type
295 * @hide
296 */
Eric Laurente48188c2014-04-18 17:44:11 -0700297 public static final int TYPE_UNKNOWN = -1;
298
299 /** Keyphrase sound model */
300 public static final int TYPE_KEYPHRASE = 0;
301
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800302 /**
303 * A generic sound model. Use this type only for non-keyphrase sound models such as
304 * ones that match a particular sound pattern.
305 */
306 public static final int TYPE_GENERIC_SOUND = 1;
307
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700308 /** Unique sound model identifier */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800309 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700310 public final UUID uuid;
311
Eric Laurente48188c2014-04-18 17:44:11 -0700312 /** Sound model type (e.g. TYPE_KEYPHRASE); */
Nicholas Amburef84fc42020-01-14 20:28:37 -0800313 @SoundModelType
Eric Laurente48188c2014-04-18 17:44:11 -0700314 public final int type;
315
Eric Laurentd3b82232014-07-30 08:57:39 -0700316 /** Unique sound model vendor identifier */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800317 @NonNull
Eric Laurentd3b82232014-07-30 08:57:39 -0700318 public final UUID vendorUuid;
319
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800320 /** vendor specific version number of the model */
321 public final int version;
322
Eric Laurente48188c2014-04-18 17:44:11 -0700323 /** Opaque data. For use by vendor implementation and enrollment application */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800324 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700325 public final byte[] data;
326
Nicholas Amburef84fc42020-01-14 20:28:37 -0800327 /** @hide */
328 public SoundModel(@NonNull UUID uuid, @Nullable UUID vendorUuid, @SoundModelType int type,
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800329 @Nullable byte[] data, int version) {
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800330 this.uuid = requireNonNull(uuid);
331 this.vendorUuid = vendorUuid != null ? vendorUuid : new UUID(0, 0);
Eric Laurente48188c2014-04-18 17:44:11 -0700332 this.type = type;
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800333 this.version = version;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800334 this.data = data != null ? data : new byte[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700335 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700336
337 @Override
338 public int hashCode() {
339 final int prime = 31;
340 int result = 1;
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800341 result = prime * result + version;
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700342 result = prime * result + Arrays.hashCode(data);
343 result = prime * result + type;
344 result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
345 result = prime * result + ((vendorUuid == null) ? 0 : vendorUuid.hashCode());
346 return result;
347 }
348
349 @Override
350 public boolean equals(Object obj) {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800351 if (this == obj) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700352 return true;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800353 }
354 if (obj == null) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700355 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800356 }
357 if (!(obj instanceof SoundModel)) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700358 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800359 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700360 SoundModel other = (SoundModel) obj;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800361 if (type != other.type) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700362 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800363 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700364 if (uuid == null) {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800365 if (other.uuid != null) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700366 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800367 }
368 } else if (!uuid.equals(other.uuid)) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700369 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800370 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700371 if (vendorUuid == null) {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800372 if (other.vendorUuid != null) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700373 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800374 }
375 } else if (!vendorUuid.equals(other.vendorUuid)) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700376 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800377 }
378 if (!Arrays.equals(data, other.data)) {
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800379 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800380 }
381 if (version != other.version) {
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800382 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800383 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700384 return true;
385 }
Eric Laurente48188c2014-04-18 17:44:11 -0700386 }
387
Nicholas Amburef84fc42020-01-14 20:28:37 -0800388 /**
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700389 * A Keyphrase describes a key phrase that can be detected by a
390 * {@link KeyphraseSoundModel}
Nicholas Amburef84fc42020-01-14 20:28:37 -0800391 */
392 public static final class Keyphrase implements Parcelable {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700393 /** Unique identifier for this keyphrase */
394 public final int id;
395
Nicholas Amburef84fc42020-01-14 20:28:37 -0800396 /**
397 * Recognition modes supported for this key phrase in the model
398 *
399 * @see #RECOGNITION_MODE_VOICE_TRIGGER
400 * @see #RECOGNITION_MODE_USER_IDENTIFICATION
401 * @see #RECOGNITION_MODE_USER_AUTHENTICATION
402 * @see #RECOGNITION_MODE_GENERIC
403 */
404 @RecognitionModes
Eric Laurente48188c2014-04-18 17:44:11 -0700405 public final int recognitionModes;
406
Nicholas Amburef84fc42020-01-14 20:28:37 -0800407 /** Locale of the keyphrase. */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800408 @NonNull
Nicholas Amburef84fc42020-01-14 20:28:37 -0800409 public final Locale locale;
Eric Laurente48188c2014-04-18 17:44:11 -0700410
411 /** Key phrase text */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800412 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700413 public final String text;
414
Nicholas Amburef84fc42020-01-14 20:28:37 -0800415 /**
416 * Users this key phrase has been trained for. countains sound trigger specific user IDs
417 * derived from system user IDs {@link android.os.UserHandle#getIdentifier()}.
418 */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800419 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -0700420 public final int[] users;
Eric Laurente48188c2014-04-18 17:44:11 -0700421
Nicholas Amburef84fc42020-01-14 20:28:37 -0800422 /**
423 * Constructor for Keyphrase describes a key phrase that can be detected by a
424 * {@link KeyphraseSoundModel}
425 *
426 * @param id Unique keyphrase identifier for this keyphrase
427 * @param recognitionModes Bit field representation of recognition modes this keyphrase
428 * supports
429 * @param locale Locale of the keyphrase
430 * @param text Key phrase text
431 * @param users Users this key phrase has been trained for.
432 */
433 public Keyphrase(int id, @RecognitionModes int recognitionModes, @NonNull Locale locale,
434 @NonNull String text, @Nullable int[] users) {
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700435 this.id = id;
Eric Laurente48188c2014-04-18 17:44:11 -0700436 this.recognitionModes = recognitionModes;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800437 this.locale = requireNonNull(locale);
438 this.text = requireNonNull(text);
439 this.users = users != null ? users : new int[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700440 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700441
Nicholas Amburef84fc42020-01-14 20:28:37 -0800442 public static final @NonNull Parcelable.Creator<Keyphrase> CREATOR =
443 new Parcelable.Creator<Keyphrase>() {
444 @NonNull
445 public Keyphrase createFromParcel(@NonNull Parcel in) {
446 return Keyphrase.readFromParcel(in);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700447 }
448
Nicholas Amburef84fc42020-01-14 20:28:37 -0800449 @NonNull
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700450 public Keyphrase[] newArray(int size) {
451 return new Keyphrase[size];
452 }
453 };
454
Nicholas Amburef84fc42020-01-14 20:28:37 -0800455 /**
456 * Read from Parcel to generate keyphrase
457 */
458 @NonNull
459 public static Keyphrase readFromParcel(@NonNull Parcel in) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700460 int id = in.readInt();
461 int recognitionModes = in.readInt();
Nicholas Amburef84fc42020-01-14 20:28:37 -0800462 Locale locale = Locale.forLanguageTag(in.readString());
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700463 String text = in.readString();
464 int[] users = null;
465 int numUsers = in.readInt();
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700466 if (numUsers >= 0) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700467 users = new int[numUsers];
468 in.readIntArray(users);
469 }
470 return new Keyphrase(id, recognitionModes, locale, text, users);
471 }
472
473 @Override
Nicholas Amburef84fc42020-01-14 20:28:37 -0800474 public void writeToParcel(@NonNull Parcel dest, int flags) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700475 dest.writeInt(id);
476 dest.writeInt(recognitionModes);
Nicholas Amburef84fc42020-01-14 20:28:37 -0800477 dest.writeString(locale.toLanguageTag());
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700478 dest.writeString(text);
479 if (users != null) {
480 dest.writeInt(users.length);
481 dest.writeIntArray(users);
482 } else {
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700483 dest.writeInt(-1);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700484 }
485 }
486
Nicholas Amburef84fc42020-01-14 20:28:37 -0800487 /** @hide */
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700488 @Override
489 public int describeContents() {
490 return 0;
491 }
492
493 @Override
494 public int hashCode() {
495 final int prime = 31;
496 int result = 1;
497 result = prime * result + ((text == null) ? 0 : text.hashCode());
498 result = prime * result + id;
499 result = prime * result + ((locale == null) ? 0 : locale.hashCode());
500 result = prime * result + recognitionModes;
501 result = prime * result + Arrays.hashCode(users);
502 return result;
503 }
504
505 @Override
506 public boolean equals(Object obj) {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800507 if (this == obj) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700508 return true;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800509 }
510 if (obj == null) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700511 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800512 }
513 if (getClass() != obj.getClass()) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700514 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800515 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700516 Keyphrase other = (Keyphrase) obj;
517 if (text == null) {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800518 if (other.text != null) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700519 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800520 }
521 } else if (!text.equals(other.text)) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700522 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800523 }
524 if (id != other.id) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700525 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800526 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700527 if (locale == null) {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800528 if (other.locale != null) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700529 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800530 }
531 } else if (!locale.equals(other.locale)) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700532 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800533 }
534 if (recognitionModes != other.recognitionModes) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700535 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800536 }
537 if (!Arrays.equals(users, other.users)) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700538 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800539 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700540 return true;
541 }
542
543 @Override
544 public String toString() {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800545 return "Keyphrase [id=" + id + ", recognitionModes=" + recognitionModes
546 + ", locale=" + locale.toLanguageTag() + ", text=" + text
547 + ", users=" + Arrays.toString(users) + "]";
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700548 }
Eric Laurente48188c2014-04-18 17:44:11 -0700549 }
550
Nicholas Amburef84fc42020-01-14 20:28:37 -0800551 /**
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700552 * A KeyphraseSoundModel is a specialized {@link SoundModel} for key phrases.
Eric Laurente48188c2014-04-18 17:44:11 -0700553 * It contains data needed by the hardware to detect a certain number of key phrases
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700554 * and the list of corresponding {@link Keyphrase} descriptors.
Nicholas Amburef84fc42020-01-14 20:28:37 -0800555 */
556 public static final class KeyphraseSoundModel extends SoundModel implements Parcelable {
Eric Laurente48188c2014-04-18 17:44:11 -0700557 /** Key phrases in this sound model */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800558 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -0700559 public final Keyphrase[] keyphrases; // keyword phrases in model
Eric Laurente48188c2014-04-18 17:44:11 -0700560
Eric Laurentd3b82232014-07-30 08:57:39 -0700561 public KeyphraseSoundModel(
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800562 @NonNull UUID uuid, @NonNull UUID vendorUuid, @Nullable byte[] data,
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800563 @Nullable Keyphrase[] keyphrases, int version) {
564 super(uuid, vendorUuid, TYPE_KEYPHRASE, data, version);
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800565 this.keyphrases = keyphrases != null ? keyphrases : new Keyphrase[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700566 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700567
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800568 public KeyphraseSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
569 @Nullable byte[] data, @Nullable Keyphrase[] keyphrases) {
570 this(uuid, vendorUuid, data, keyphrases, -1);
571 }
572
Nicholas Amburef84fc42020-01-14 20:28:37 -0800573 public static final @NonNull Parcelable.Creator<KeyphraseSoundModel> CREATOR =
574 new Parcelable.Creator<KeyphraseSoundModel>() {
575 @NonNull
576 public KeyphraseSoundModel createFromParcel(@NonNull Parcel in) {
577 return KeyphraseSoundModel.readFromParcel(in);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700578 }
579
Nicholas Amburef84fc42020-01-14 20:28:37 -0800580 @NonNull
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700581 public KeyphraseSoundModel[] newArray(int size) {
582 return new KeyphraseSoundModel[size];
583 }
584 };
585
Nicholas Amburef84fc42020-01-14 20:28:37 -0800586 /**
587 * Read from Parcel to generate KeyphraseSoundModel
588 */
589 @NonNull
590 public static KeyphraseSoundModel readFromParcel(@NonNull Parcel in) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700591 UUID uuid = UUID.fromString(in.readString());
Eric Laurentd3b82232014-07-30 08:57:39 -0700592 UUID vendorUuid = null;
593 int length = in.readInt();
594 if (length >= 0) {
595 vendorUuid = UUID.fromString(in.readString());
596 }
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800597 int version = in.readInt();
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700598 byte[] data = in.readBlob();
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700599 Keyphrase[] keyphrases = in.createTypedArray(Keyphrase.CREATOR);
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800600 return new KeyphraseSoundModel(uuid, vendorUuid, data, keyphrases, version);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700601 }
602
Nicholas Amburef84fc42020-01-14 20:28:37 -0800603 /** @hide */
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700604 @Override
605 public int describeContents() {
606 return 0;
607 }
608
609 @Override
Nicholas Amburef84fc42020-01-14 20:28:37 -0800610 public void writeToParcel(@NonNull Parcel dest, int flags) {
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700611 dest.writeString(uuid.toString());
Eric Laurentd3b82232014-07-30 08:57:39 -0700612 if (vendorUuid == null) {
613 dest.writeInt(-1);
614 } else {
615 dest.writeInt(vendorUuid.toString().length());
616 dest.writeString(vendorUuid.toString());
617 }
Nicholas Ambur43970b52020-01-14 18:54:26 -0800618 dest.writeInt(version);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700619 dest.writeBlob(data);
Sandeep Siddhartha68173372014-07-28 13:25:30 -0700620 dest.writeTypedArray(keyphrases, flags);
Sandeep Siddhartha05589722014-07-17 16:21:54 -0700621 }
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700622
623 @Override
624 public String toString() {
Eric Laurentd3b82232014-07-30 08:57:39 -0700625 return "KeyphraseSoundModel [keyphrases=" + Arrays.toString(keyphrases)
626 + ", uuid=" + uuid + ", vendorUuid=" + vendorUuid
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800627 + ", type=" + type
628 + ", data=" + (data == null ? 0 : data.length)
629 + ", version=" + version + "]";
Sandeep Siddhartha110f5692014-07-20 12:22:56 -0700630 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700631
632 @Override
633 public int hashCode() {
634 final int prime = 31;
635 int result = super.hashCode();
636 result = prime * result + Arrays.hashCode(keyphrases);
637 return result;
638 }
639
640 @Override
641 public boolean equals(Object obj) {
Nicholas Amburef84fc42020-01-14 20:28:37 -0800642 if (this == obj) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700643 return true;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800644 }
645 if (!super.equals(obj)) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700646 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800647 }
648 if (!(obj instanceof KeyphraseSoundModel)) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700649 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800650 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700651 KeyphraseSoundModel other = (KeyphraseSoundModel) obj;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800652 if (!Arrays.equals(keyphrases, other.keyphrases)) {
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700653 return false;
Nicholas Amburef84fc42020-01-14 20:28:37 -0800654 }
Sandeep Siddhartha45c00b52014-10-16 16:17:11 -0700655 return true;
656 }
Eric Laurente48188c2014-04-18 17:44:11 -0700657 }
658
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800659
660 /*****************************************************************************
661 * A GenericSoundModel is a specialized {@link SoundModel} for non-voice sound
662 * patterns.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800663 *
664 * @hide
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800665 ****************************************************************************/
666 public static class GenericSoundModel extends SoundModel implements Parcelable {
667
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700668 public static final @android.annotation.NonNull Parcelable.Creator<GenericSoundModel> CREATOR
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800669 = new Parcelable.Creator<GenericSoundModel>() {
670 public GenericSoundModel createFromParcel(Parcel in) {
671 return GenericSoundModel.fromParcel(in);
672 }
673
674 public GenericSoundModel[] newArray(int size) {
675 return new GenericSoundModel[size];
676 }
677 };
678
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800679 public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
680 @Nullable byte[] data, int version) {
681 super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data, version);
682 }
683
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100684 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800685 public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
686 @Nullable byte[] data) {
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800687 this(uuid, vendorUuid, data, -1);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800688 }
689
690 @Override
691 public int describeContents() {
692 return 0;
693 }
694
695 private static GenericSoundModel fromParcel(Parcel in) {
696 UUID uuid = UUID.fromString(in.readString());
697 UUID vendorUuid = null;
698 int length = in.readInt();
699 if (length >= 0) {
700 vendorUuid = UUID.fromString(in.readString());
701 }
702 byte[] data = in.readBlob();
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800703 int version = in.readInt();
704 return new GenericSoundModel(uuid, vendorUuid, data, version);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800705 }
706
707 @Override
708 public void writeToParcel(Parcel dest, int flags) {
709 dest.writeString(uuid.toString());
710 if (vendorUuid == null) {
711 dest.writeInt(-1);
712 } else {
713 dest.writeInt(vendorUuid.toString().length());
714 dest.writeString(vendorUuid.toString());
715 }
716 dest.writeBlob(data);
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800717 dest.writeInt(version);
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800718 }
719
720 @Override
721 public String toString() {
722 return "GenericSoundModel [uuid=" + uuid + ", vendorUuid=" + vendorUuid
Nicholas Amburd3ec82f2020-01-03 17:44:19 -0800723 + ", type=" + type
724 + ", data=" + (data == null ? 0 : data.length)
725 + ", version=" + version + "]";
Arunesh Mishraa772e5f2016-01-25 10:33:11 -0800726 }
727 }
728
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800729 /**
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700730 * A ModelParamRange is a representation of supported parameter range for a
731 * given loaded model.
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800732 */
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700733 public static final class ModelParamRange implements Parcelable {
734
735 /**
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800736 * The inclusive start of supported range.
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700737 */
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800738 private final int mStart;
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700739
740 /**
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800741 * The inclusive end of supported range.
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700742 */
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800743 private final int mEnd;
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700744
745 ModelParamRange(int start, int end) {
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800746 this.mStart = start;
747 this.mEnd = end;
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700748 }
749
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800750 /** @hide */
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700751 private ModelParamRange(@NonNull Parcel in) {
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800752 this.mStart = in.readInt();
753 this.mEnd = in.readInt();
754 }
755
756 /**
757 * Get the beginning of the param range
758 *
759 * @return The inclusive start of the supported range.
760 */
761 public int getStart() {
762 return mStart;
763 }
764
765 /**
766 * Get the end of the param range
767 *
768 * @return The inclusive end of the supported range.
769 */
770 public int getEnd() {
771 return mEnd;
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700772 }
773
774 @NonNull
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800775 public static final Creator<ModelParamRange> CREATOR =
776 new Creator<ModelParamRange>() {
777 @Override
778 @NonNull
779 public ModelParamRange createFromParcel(@NonNull Parcel in) {
780 return new ModelParamRange(in);
781 }
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700782
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800783 @Override
784 @NonNull
785 public ModelParamRange[] newArray(int size) {
786 return new ModelParamRange[size];
787 }
788 };
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700789
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800790 /** @hide */
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700791 @Override
792 public int describeContents() {
793 return 0;
794 }
795
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800796 /** @hide */
797 @Override
798 public int hashCode() {
799 final int prime = 31;
800 int result = 1;
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800801 result = prime * result + (mStart);
802 result = prime * result + (mEnd);
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800803 return result;
804 }
805
806 @Override
807 public boolean equals(@Nullable Object obj) {
808 if (this == obj) {
809 return true;
810 }
811 if (obj == null) {
812 return false;
813 }
814 if (getClass() != obj.getClass()) {
815 return false;
816 }
817 ModelParamRange other = (ModelParamRange) obj;
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800818 if (mStart != other.mStart) {
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800819 return false;
820 }
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800821 if (mEnd != other.mEnd) {
Nicholas Amburf94db1c2019-12-08 19:04:06 -0800822 return false;
823 }
824 return true;
825 }
826
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700827 @Override
828 public void writeToParcel(@NonNull Parcel dest, int flags) {
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800829 dest.writeInt(mStart);
830 dest.writeInt(mEnd);
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700831 }
832
833 @Override
834 @NonNull
835 public String toString() {
Nicholas Amburb6e48c22020-02-04 14:24:34 -0800836 return "ModelParamRange [start=" + mStart + ", end=" + mEnd + "]";
Nicholas Ambura0be6be2019-10-01 10:11:39 -0700837 }
838 }
839
Eric Laurente48188c2014-04-18 17:44:11 -0700840 /**
Nicholas Amburef84fc42020-01-14 20:28:37 -0800841 * Modes for key phrase recognition
842 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -0700843 */
Nicholas Amburef84fc42020-01-14 20:28:37 -0800844 @Retention(RetentionPolicy.SOURCE)
845 @IntDef(flag = true, prefix = { "RECOGNITION_MODE_" }, value = {
846 RECOGNITION_MODE_VOICE_TRIGGER,
847 RECOGNITION_MODE_USER_IDENTIFICATION,
848 RECOGNITION_MODE_USER_AUTHENTICATION,
849 RECOGNITION_MODE_GENERIC
850 })
851 public @interface RecognitionModes {}
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800852
853 /**
Nicholas Amburef84fc42020-01-14 20:28:37 -0800854 * Trigger on recognition of a key phrase
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800855 */
Eric Laurente48188c2014-04-18 17:44:11 -0700856 public static final int RECOGNITION_MODE_VOICE_TRIGGER = 0x1;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800857 /**
858 * Trigger only if one user is identified
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800859 */
Eric Laurente48188c2014-04-18 17:44:11 -0700860 public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 0x2;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800861 /**
862 * Trigger only if one user is authenticated
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800863 */
Eric Laurente48188c2014-04-18 17:44:11 -0700864 public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 0x4;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800865 /**
866 * Generic (non-speech) recognition.
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800867 */
868 public static final int RECOGNITION_MODE_GENERIC = 0x8;
Eric Laurente48188c2014-04-18 17:44:11 -0700869
870 /**
871 * Status codes for {@link RecognitionEvent}
872 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800873 /**
874 * Recognition success
875 *
876 * @hide
877 */
Eric Laurente48188c2014-04-18 17:44:11 -0700878 public static final int RECOGNITION_STATUS_SUCCESS = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800879 /**
880 * Recognition aborted (e.g. capture preempted by anotehr use case
881 *
882 * @hide
883 */
Eric Laurente48188c2014-04-18 17:44:11 -0700884 public static final int RECOGNITION_STATUS_ABORT = 1;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800885 /**
886 * Recognition failure
887 *
888 * @hide
889 */
Eric Laurente48188c2014-04-18 17:44:11 -0700890 public static final int RECOGNITION_STATUS_FAILURE = 2;
mike dooleyb2ab04a2018-11-07 15:48:54 +0100891 /**
892 * Recognition event was triggered by a getModelState request, not by the
893 * DSP.
894 *
895 * @hide
896 */
897 public static final int RECOGNITION_STATUS_GET_STATE_RESPONSE = 3;
Eric Laurente48188c2014-04-18 17:44:11 -0700898
899 /**
900 * A RecognitionEvent is provided by the
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800901 * {@code StatusListener#onRecognition(RecognitionEvent)}
Eric Laurente48188c2014-04-18 17:44:11 -0700902 * callback upon recognition success or failure.
903 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800904 public static class RecognitionEvent {
905 /**
906 * Recognition status e.g RECOGNITION_STATUS_SUCCESS
907 *
908 * @hide
909 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100910 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700911 public final int status;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800912 /**
913 *
914 * Sound Model corresponding to this event callback
915 *
916 * @hide
917 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100918 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700919 public final int soundModelHandle;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800920 /**
921 * True if it is possible to capture audio from this utterance buffered by the hardware
922 *
923 * @hide
924 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100925 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700926 public final boolean captureAvailable;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800927 /**
928 * Audio session ID to be used when capturing the utterance with an AudioRecord
929 * if captureAvailable() is true.
930 *
931 * @hide
932 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100933 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -0700934 public final int captureSession;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800935 /**
936 * Delay in ms between end of model detection and start of audio available for capture.
937 * A negative value is possible (e.g. if keyphrase is also available for capture)
938 *
939 * @hide
940 */
Eric Laurente48188c2014-04-18 17:44:11 -0700941 public final int captureDelayMs;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800942 /**
943 * Duration in ms of audio captured before the start of the trigger. 0 if none.
944 *
945 * @hide
946 */
Eric Laurent013f66b2014-07-06 16:35:00 -0700947 public final int capturePreambleMs;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800948 /**
949 * True if the trigger (key phrase capture is present in binary data
950 *
951 * @hide
952 */
Eric Laurentd3b82232014-07-30 08:57:39 -0700953 public final boolean triggerInData;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800954 /**
955 * Audio format of either the trigger in event data or to use for capture of the
956 * rest of the utterance
957 *
958 * @hide
959 */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800960 @NonNull
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800961 public final AudioFormat captureFormat;
962 /**
963 * Opaque data for use by system applications who know about voice engine internals,
964 * typically during enrollment.
965 *
966 * @hide
967 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100968 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800969 @NonNull
Eric Laurente48188c2014-04-18 17:44:11 -0700970 public final byte[] data;
971
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800972 /** @hide */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +0100973 @UnsupportedAppUsage
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700974 public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -0700975 int captureSession, int captureDelayMs, int capturePreambleMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800976 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) {
Eric Laurente48188c2014-04-18 17:44:11 -0700977 this.status = status;
978 this.soundModelHandle = soundModelHandle;
979 this.captureAvailable = captureAvailable;
980 this.captureSession = captureSession;
981 this.captureDelayMs = captureDelayMs;
Eric Laurent013f66b2014-07-06 16:35:00 -0700982 this.capturePreambleMs = capturePreambleMs;
Eric Laurentd3b82232014-07-30 08:57:39 -0700983 this.triggerInData = triggerInData;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -0800984 this.captureFormat = requireNonNull(captureFormat);
985 this.data = data != null ? data : new byte[0];
Eric Laurente48188c2014-04-18 17:44:11 -0700986 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -0700987
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -0800988 /**
989 * Check if is possible to capture audio from this utterance buffered by the hardware.
990 *
991 * @return {@code true} iff a capturing is possible
992 */
993 public boolean isCaptureAvailable() {
994 return captureAvailable;
995 }
996
997 /**
998 * Get the audio format of either the trigger in event data or to use for capture of the
999 * rest of the utterance
1000 *
1001 * @return the audio format
1002 */
1003 @Nullable public AudioFormat getCaptureFormat() {
1004 return captureFormat;
1005 }
1006
1007 /**
1008 * Get Audio session ID to be used when capturing the utterance with an {@link AudioRecord}
1009 * if {@link #isCaptureAvailable()} is true.
1010 *
1011 * @return The id of the capture session
1012 */
1013 public int getCaptureSession() {
1014 return captureSession;
1015 }
1016
1017 /**
1018 * Get the opaque data for use by system applications who know about voice engine
1019 * internals, typically during enrollment.
1020 *
1021 * @return The data of the event
1022 */
1023 public byte[] getData() {
1024 return data;
1025 }
1026
1027 /** @hide */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001028 public static final @android.annotation.NonNull Parcelable.Creator<RecognitionEvent> CREATOR
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001029 = new Parcelable.Creator<RecognitionEvent>() {
1030 public RecognitionEvent createFromParcel(Parcel in) {
1031 return RecognitionEvent.fromParcel(in);
1032 }
1033
1034 public RecognitionEvent[] newArray(int size) {
1035 return new RecognitionEvent[size];
1036 }
1037 };
1038
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001039 /** @hide */
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001040 protected static RecognitionEvent fromParcel(Parcel in) {
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001041 int status = in.readInt();
1042 int soundModelHandle = in.readInt();
1043 boolean captureAvailable = in.readByte() == 1;
1044 int captureSession = in.readInt();
1045 int captureDelayMs = in.readInt();
1046 int capturePreambleMs = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -07001047 boolean triggerInData = in.readByte() == 1;
1048 AudioFormat captureFormat = null;
Eric Laurent39fcca02014-09-05 16:44:19 -07001049 if (in.readByte() == 1) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001050 int sampleRate = in.readInt();
1051 int encoding = in.readInt();
1052 int channelMask = in.readInt();
1053 captureFormat = (new AudioFormat.Builder())
1054 .setChannelMask(channelMask)
1055 .setEncoding(encoding)
1056 .setSampleRate(sampleRate)
1057 .build();
1058 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001059 byte[] data = in.readBlob();
1060 return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession,
Eric Laurentd3b82232014-07-30 08:57:39 -07001061 captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001062 }
1063
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001064 /** @hide */
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001065 public int describeContents() {
1066 return 0;
1067 }
1068
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001069 /** @hide */
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001070 public void writeToParcel(Parcel dest, int flags) {
1071 dest.writeInt(status);
1072 dest.writeInt(soundModelHandle);
1073 dest.writeByte((byte) (captureAvailable ? 1 : 0));
1074 dest.writeInt(captureSession);
1075 dest.writeInt(captureDelayMs);
1076 dest.writeInt(capturePreambleMs);
Eric Laurent39fcca02014-09-05 16:44:19 -07001077 dest.writeByte((byte) (triggerInData ? 1 : 0));
1078 if (captureFormat != null) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001079 dest.writeByte((byte)1);
1080 dest.writeInt(captureFormat.getSampleRate());
1081 dest.writeInt(captureFormat.getEncoding());
1082 dest.writeInt(captureFormat.getChannelMask());
1083 } else {
1084 dest.writeByte((byte)0);
1085 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001086 dest.writeBlob(data);
1087 }
1088
1089 @Override
1090 public int hashCode() {
1091 final int prime = 31;
1092 int result = 1;
1093 result = prime * result + (captureAvailable ? 1231 : 1237);
1094 result = prime * result + captureDelayMs;
1095 result = prime * result + capturePreambleMs;
1096 result = prime * result + captureSession;
Eric Laurentd3b82232014-07-30 08:57:39 -07001097 result = prime * result + (triggerInData ? 1231 : 1237);
1098 if (captureFormat != null) {
1099 result = prime * result + captureFormat.getSampleRate();
1100 result = prime * result + captureFormat.getEncoding();
1101 result = prime * result + captureFormat.getChannelMask();
1102 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001103 result = prime * result + Arrays.hashCode(data);
1104 result = prime * result + soundModelHandle;
1105 result = prime * result + status;
1106 return result;
1107 }
1108
1109 @Override
Aurimas Liutikas4d1699d2019-08-28 13:01:05 -07001110 public boolean equals(@Nullable Object obj) {
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001111 if (this == obj)
1112 return true;
1113 if (obj == null)
1114 return false;
1115 if (getClass() != obj.getClass())
1116 return false;
1117 RecognitionEvent other = (RecognitionEvent) obj;
1118 if (captureAvailable != other.captureAvailable)
1119 return false;
1120 if (captureDelayMs != other.captureDelayMs)
1121 return false;
1122 if (capturePreambleMs != other.capturePreambleMs)
1123 return false;
1124 if (captureSession != other.captureSession)
1125 return false;
1126 if (!Arrays.equals(data, other.data))
1127 return false;
1128 if (soundModelHandle != other.soundModelHandle)
1129 return false;
1130 if (status != other.status)
1131 return false;
Eric Laurentd3b82232014-07-30 08:57:39 -07001132 if (triggerInData != other.triggerInData)
1133 return false;
Ryan Bavettaea04e8f2016-03-02 18:34:50 -08001134 if (captureFormat == null) {
1135 if (other.captureFormat != null)
1136 return false;
1137 } else {
1138 if (other.captureFormat == null)
1139 return false;
1140 if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
1141 return false;
1142 if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
1143 return false;
1144 if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
1145 return false;
1146 }
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001147 return true;
1148 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001149
Aurimas Liutikas4d1699d2019-08-28 13:01:05 -07001150 @NonNull
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001151 @Override
1152 public String toString() {
1153 return "RecognitionEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
1154 + ", captureAvailable=" + captureAvailable + ", captureSession="
1155 + captureSession + ", captureDelayMs=" + captureDelayMs
1156 + ", capturePreambleMs=" + capturePreambleMs
Eric Laurentd3b82232014-07-30 08:57:39 -07001157 + ", triggerInData=" + triggerInData
1158 + ((captureFormat == null) ? "" :
1159 (", sampleRate=" + captureFormat.getSampleRate()))
1160 + ((captureFormat == null) ? "" :
1161 (", encoding=" + captureFormat.getEncoding()))
1162 + ((captureFormat == null) ? "" :
1163 (", channelMask=" + captureFormat.getChannelMask()))
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001164 + ", data=" + (data == null ? 0 : data.length) + "]";
1165 }
Eric Laurente48188c2014-04-18 17:44:11 -07001166 }
1167
1168 /**
Eric Laurent013f66b2014-07-06 16:35:00 -07001169 * A RecognitionConfig is provided to
1170 * {@link SoundTriggerModule#startRecognition(int, RecognitionConfig)} to configure the
1171 * recognition request.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001172 *
1173 * @hide
Eric Laurent013f66b2014-07-06 16:35:00 -07001174 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001175 public static class RecognitionConfig implements Parcelable {
Eric Laurent013f66b2014-07-06 16:35:00 -07001176 /** True if the DSP should capture the trigger sound and make it available for further
1177 * capture. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001178 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001179 public final boolean captureRequested;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001180 /**
1181 * True if the service should restart listening after the DSP triggers.
1182 * Note: This config flag is currently used at the service layer rather than by the DSP.
1183 */
1184 public final boolean allowMultipleTriggers;
Eric Laurent013f66b2014-07-06 16:35:00 -07001185 /** List of all keyphrases in the sound model for which recognition should be performed with
1186 * options for each keyphrase. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001187 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001188 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -07001189 public final KeyphraseRecognitionExtra keyphrases[];
1190 /** Opaque data for use by system applications who know about voice engine internals,
1191 * typically during enrollment. */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001192 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001193 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -07001194 public final byte[] data;
1195
Nicholas Ambur7092a562019-12-16 11:18:55 -08001196 /**
1197 * Bit field encoding of the AudioCapabilities
1198 * supported by the firmware.
1199 */
1200 @ModuleProperties.AudioCapabilities
1201 public final int audioCapabilities;
1202
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001203 public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
Nicholas Ambur7092a562019-12-16 11:18:55 -08001204 @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data,
1205 int audioCapabilities) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001206 this.captureRequested = captureRequested;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001207 this.allowMultipleTriggers = allowMultipleTriggers;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001208 this.keyphrases = keyphrases != null ? keyphrases : new KeyphraseRecognitionExtra[0];
1209 this.data = data != null ? data : new byte[0];
Nicholas Ambur7092a562019-12-16 11:18:55 -08001210 this.audioCapabilities = audioCapabilities;
1211 }
1212
1213 @UnsupportedAppUsage
1214 public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
1215 @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data) {
1216 this(captureRequested, allowMultipleTriggers, keyphrases, data, 0);
Eric Laurent013f66b2014-07-06 16:35:00 -07001217 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001218
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001219 public static final @android.annotation.NonNull Parcelable.Creator<RecognitionConfig> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001220 = new Parcelable.Creator<RecognitionConfig>() {
1221 public RecognitionConfig createFromParcel(Parcel in) {
1222 return RecognitionConfig.fromParcel(in);
1223 }
1224
1225 public RecognitionConfig[] newArray(int size) {
1226 return new RecognitionConfig[size];
1227 }
1228 };
1229
1230 private static RecognitionConfig fromParcel(Parcel in) {
1231 boolean captureRequested = in.readByte() == 1;
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001232 boolean allowMultipleTriggers = in.readByte() == 1;
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001233 KeyphraseRecognitionExtra[] keyphrases =
1234 in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001235 byte[] data = in.readBlob();
Nicholas Ambur7092a562019-12-16 11:18:55 -08001236 int audioCapabilities = in.readInt();
1237 return new RecognitionConfig(captureRequested, allowMultipleTriggers, keyphrases, data,
1238 audioCapabilities);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001239 }
1240
1241 @Override
1242 public void writeToParcel(Parcel dest, int flags) {
1243 dest.writeByte((byte) (captureRequested ? 1 : 0));
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001244 dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0));
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001245 dest.writeTypedArray(keyphrases, flags);
Sandeep Siddhartha39c12fa2014-07-25 18:37:29 -07001246 dest.writeBlob(data);
Nicholas Ambur7092a562019-12-16 11:18:55 -08001247 dest.writeInt(audioCapabilities);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001248 }
1249
1250 @Override
1251 public int describeContents() {
1252 return 0;
1253 }
Sandeep Siddhartha110f5692014-07-20 12:22:56 -07001254
1255 @Override
1256 public String toString() {
Sandeep Siddhartha2c0273e2014-08-01 11:32:03 -07001257 return "RecognitionConfig [captureRequested=" + captureRequested
1258 + ", allowMultipleTriggers=" + allowMultipleTriggers + ", keyphrases="
Nicholas Ambur7092a562019-12-16 11:18:55 -08001259 + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data)
1260 + ", audioCapabilities=" + Integer.toHexString(audioCapabilities) + "]";
Sandeep Siddhartha110f5692014-07-20 12:22:56 -07001261 }
Eric Laurent013f66b2014-07-06 16:35:00 -07001262 }
1263
1264 /**
1265 * Confidence level for users defined in a keyphrase.
1266 * - The confidence level is expressed in percent (0% -100%).
1267 * When used in a {@link KeyphraseRecognitionEvent} it indicates the detected confidence level
1268 * When used in a {@link RecognitionConfig} it indicates the minimum confidence level that
1269 * should trigger a recognition.
1270 * - The user ID is derived from the system ID {@link android.os.UserHandle#getIdentifier()}.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001271 *
1272 * @hide
Eric Laurent013f66b2014-07-06 16:35:00 -07001273 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001274 public static class ConfidenceLevel implements Parcelable {
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001275 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001276 public final int userId;
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001277 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001278 public final int confidenceLevel;
1279
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001280 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001281 public ConfidenceLevel(int userId, int confidenceLevel) {
1282 this.userId = userId;
1283 this.confidenceLevel = confidenceLevel;
1284 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001285
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001286 public static final @android.annotation.NonNull Parcelable.Creator<ConfidenceLevel> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001287 = new Parcelable.Creator<ConfidenceLevel>() {
1288 public ConfidenceLevel createFromParcel(Parcel in) {
1289 return ConfidenceLevel.fromParcel(in);
1290 }
1291
1292 public ConfidenceLevel[] newArray(int size) {
1293 return new ConfidenceLevel[size];
1294 }
1295 };
1296
1297 private static ConfidenceLevel fromParcel(Parcel in) {
1298 int userId = in.readInt();
1299 int confidenceLevel = in.readInt();
1300 return new ConfidenceLevel(userId, confidenceLevel);
1301 }
1302
1303 @Override
1304 public void writeToParcel(Parcel dest, int flags) {
1305 dest.writeInt(userId);
1306 dest.writeInt(confidenceLevel);
1307 }
1308
1309 @Override
1310 public int describeContents() {
1311 return 0;
1312 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001313
1314 @Override
1315 public int hashCode() {
1316 final int prime = 31;
1317 int result = 1;
1318 result = prime * result + confidenceLevel;
1319 result = prime * result + userId;
1320 return result;
1321 }
1322
1323 @Override
1324 public boolean equals(Object obj) {
1325 if (this == obj)
1326 return true;
1327 if (obj == null)
1328 return false;
1329 if (getClass() != obj.getClass())
1330 return false;
1331 ConfidenceLevel other = (ConfidenceLevel) obj;
1332 if (confidenceLevel != other.confidenceLevel)
1333 return false;
1334 if (userId != other.userId)
1335 return false;
1336 return true;
1337 }
1338
1339 @Override
1340 public String toString() {
1341 return "ConfidenceLevel [userId=" + userId
1342 + ", confidenceLevel=" + confidenceLevel + "]";
1343 }
Eric Laurent013f66b2014-07-06 16:35:00 -07001344 }
1345
1346 /**
Sandeep Siddharthad4233c62014-06-12 18:31:19 -07001347 * Additional data conveyed by a {@link KeyphraseRecognitionEvent}
Eric Laurente48188c2014-04-18 17:44:11 -07001348 * for a key phrase detection.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001349 *
1350 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001351 */
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001352 public static class KeyphraseRecognitionExtra implements Parcelable {
1353 /** The keyphrase ID */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001354 @UnsupportedAppUsage
Eric Laurent013f66b2014-07-06 16:35:00 -07001355 public final int id;
Eric Laurente48188c2014-04-18 17:44:11 -07001356
1357 /** Recognition modes matched for this event */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001358 @UnsupportedAppUsage
Eric Laurente48188c2014-04-18 17:44:11 -07001359 public final int recognitionModes;
1360
Eric Laurentd3b82232014-07-30 08:57:39 -07001361 /** Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
1362 * is not performed */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001363 @UnsupportedAppUsage
Eric Laurentd3b82232014-07-30 08:57:39 -07001364 public final int coarseConfidenceLevel;
1365
Eric Laurent013f66b2014-07-06 16:35:00 -07001366 /** Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to
1367 * be recognized (RecognitionConfig) */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001368 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001369 @NonNull
Eric Laurent013f66b2014-07-06 16:35:00 -07001370 public final ConfidenceLevel[] confidenceLevels;
1371
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001372 @UnsupportedAppUsage
Eric Laurentd3b82232014-07-30 08:57:39 -07001373 public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001374 @Nullable ConfidenceLevel[] confidenceLevels) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001375 this.id = id;
Eric Laurente48188c2014-04-18 17:44:11 -07001376 this.recognitionModes = recognitionModes;
Eric Laurentd3b82232014-07-30 08:57:39 -07001377 this.coarseConfidenceLevel = coarseConfidenceLevel;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001378 this.confidenceLevels =
1379 confidenceLevels != null ? confidenceLevels : new ConfidenceLevel[0];
Eric Laurente48188c2014-04-18 17:44:11 -07001380 }
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001381
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001382 public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionExtra> CREATOR
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001383 = new Parcelable.Creator<KeyphraseRecognitionExtra>() {
1384 public KeyphraseRecognitionExtra createFromParcel(Parcel in) {
1385 return KeyphraseRecognitionExtra.fromParcel(in);
1386 }
1387
1388 public KeyphraseRecognitionExtra[] newArray(int size) {
1389 return new KeyphraseRecognitionExtra[size];
1390 }
1391 };
1392
1393 private static KeyphraseRecognitionExtra fromParcel(Parcel in) {
1394 int id = in.readInt();
1395 int recognitionModes = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -07001396 int coarseConfidenceLevel = in.readInt();
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001397 ConfidenceLevel[] confidenceLevels = in.createTypedArray(ConfidenceLevel.CREATOR);
Eric Laurentd3b82232014-07-30 08:57:39 -07001398 return new KeyphraseRecognitionExtra(id, recognitionModes, coarseConfidenceLevel,
1399 confidenceLevels);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001400 }
1401
1402 @Override
1403 public void writeToParcel(Parcel dest, int flags) {
1404 dest.writeInt(id);
1405 dest.writeInt(recognitionModes);
Eric Laurentd3b82232014-07-30 08:57:39 -07001406 dest.writeInt(coarseConfidenceLevel);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001407 dest.writeTypedArray(confidenceLevels, flags);
Sandeep Siddhartha05589722014-07-17 16:21:54 -07001408 }
1409
1410 @Override
1411 public int describeContents() {
1412 return 0;
1413 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001414
1415 @Override
1416 public int hashCode() {
1417 final int prime = 31;
1418 int result = 1;
1419 result = prime * result + Arrays.hashCode(confidenceLevels);
1420 result = prime * result + id;
1421 result = prime * result + recognitionModes;
Eric Laurentd3b82232014-07-30 08:57:39 -07001422 result = prime * result + coarseConfidenceLevel;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001423 return result;
1424 }
1425
1426 @Override
1427 public boolean equals(Object obj) {
1428 if (this == obj)
1429 return true;
1430 if (obj == null)
1431 return false;
1432 if (getClass() != obj.getClass())
1433 return false;
1434 KeyphraseRecognitionExtra other = (KeyphraseRecognitionExtra) obj;
1435 if (!Arrays.equals(confidenceLevels, other.confidenceLevels))
1436 return false;
1437 if (id != other.id)
1438 return false;
1439 if (recognitionModes != other.recognitionModes)
1440 return false;
Eric Laurentd3b82232014-07-30 08:57:39 -07001441 if (coarseConfidenceLevel != other.coarseConfidenceLevel)
1442 return false;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001443 return true;
1444 }
1445
1446 @Override
1447 public String toString() {
1448 return "KeyphraseRecognitionExtra [id=" + id + ", recognitionModes=" + recognitionModes
Eric Laurentd3b82232014-07-30 08:57:39 -07001449 + ", coarseConfidenceLevel=" + coarseConfidenceLevel
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001450 + ", confidenceLevels=" + Arrays.toString(confidenceLevels) + "]";
1451 }
Eric Laurente48188c2014-04-18 17:44:11 -07001452 }
1453
1454 /**
1455 * Specialized {@link RecognitionEvent} for a key phrase detection.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001456 *
1457 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001458 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001459 public static class KeyphraseRecognitionEvent extends RecognitionEvent implements Parcelable {
Eric Laurente48188c2014-04-18 17:44:11 -07001460 /** Indicates if the key phrase is present in the buffered audio available for capture */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001461 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001462 @NonNull
Sandeep Siddharthad4233c62014-06-12 18:31:19 -07001463 public final KeyphraseRecognitionExtra[] keyphraseExtras;
Eric Laurente48188c2014-04-18 17:44:11 -07001464
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001465 @UnsupportedAppUsage
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001466 public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -07001467 int captureSession, int captureDelayMs, int capturePreambleMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001468 boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
1469 @Nullable KeyphraseRecognitionExtra[] keyphraseExtras) {
Eric Laurent013f66b2014-07-06 16:35:00 -07001470 super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
Eric Laurentd3b82232014-07-30 08:57:39 -07001471 capturePreambleMs, triggerInData, captureFormat, data);
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001472 this.keyphraseExtras =
1473 keyphraseExtras != null ? keyphraseExtras : new KeyphraseRecognitionExtra[0];
Eric Laurente48188c2014-04-18 17:44:11 -07001474 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001475
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001476 public static final @android.annotation.NonNull Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001477 = new Parcelable.Creator<KeyphraseRecognitionEvent>() {
1478 public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001479 return KeyphraseRecognitionEvent.fromParcelForKeyphrase(in);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001480 }
1481
1482 public KeyphraseRecognitionEvent[] newArray(int size) {
1483 return new KeyphraseRecognitionEvent[size];
1484 }
1485 };
1486
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001487 private static KeyphraseRecognitionEvent fromParcelForKeyphrase(Parcel in) {
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001488 int status = in.readInt();
1489 int soundModelHandle = in.readInt();
1490 boolean captureAvailable = in.readByte() == 1;
1491 int captureSession = in.readInt();
1492 int captureDelayMs = in.readInt();
1493 int capturePreambleMs = in.readInt();
Eric Laurentd3b82232014-07-30 08:57:39 -07001494 boolean triggerInData = in.readByte() == 1;
1495 AudioFormat captureFormat = null;
Eric Laurent75b433f2014-09-12 15:45:47 -07001496 if (in.readByte() == 1) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001497 int sampleRate = in.readInt();
1498 int encoding = in.readInt();
1499 int channelMask = in.readInt();
1500 captureFormat = (new AudioFormat.Builder())
Ryan Bavettaea04e8f2016-03-02 18:34:50 -08001501 .setChannelMask(channelMask)
1502 .setEncoding(encoding)
1503 .setSampleRate(sampleRate)
1504 .build();
Eric Laurentd3b82232014-07-30 08:57:39 -07001505 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001506 byte[] data = in.readBlob();
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001507 KeyphraseRecognitionExtra[] keyphraseExtras =
1508 in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
1509 return new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
Eric Laurentd3b82232014-07-30 08:57:39 -07001510 captureSession, captureDelayMs, capturePreambleMs, triggerInData,
1511 captureFormat, data, keyphraseExtras);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001512 }
1513
1514 @Override
1515 public void writeToParcel(Parcel dest, int flags) {
1516 dest.writeInt(status);
1517 dest.writeInt(soundModelHandle);
1518 dest.writeByte((byte) (captureAvailable ? 1 : 0));
1519 dest.writeInt(captureSession);
1520 dest.writeInt(captureDelayMs);
1521 dest.writeInt(capturePreambleMs);
Eric Laurent75b433f2014-09-12 15:45:47 -07001522 dest.writeByte((byte) (triggerInData ? 1 : 0));
1523 if (captureFormat != null) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001524 dest.writeByte((byte)1);
1525 dest.writeInt(captureFormat.getSampleRate());
1526 dest.writeInt(captureFormat.getEncoding());
1527 dest.writeInt(captureFormat.getChannelMask());
1528 } else {
1529 dest.writeByte((byte)0);
1530 }
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001531 dest.writeBlob(data);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001532 dest.writeTypedArray(keyphraseExtras, flags);
1533 }
1534
1535 @Override
1536 public int describeContents() {
1537 return 0;
1538 }
1539
1540 @Override
1541 public int hashCode() {
1542 final int prime = 31;
1543 int result = super.hashCode();
1544 result = prime * result + Arrays.hashCode(keyphraseExtras);
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001545 return result;
1546 }
1547
1548 @Override
1549 public boolean equals(Object obj) {
1550 if (this == obj)
1551 return true;
1552 if (!super.equals(obj))
1553 return false;
1554 if (getClass() != obj.getClass())
1555 return false;
1556 KeyphraseRecognitionEvent other = (KeyphraseRecognitionEvent) obj;
1557 if (!Arrays.equals(keyphraseExtras, other.keyphraseExtras))
1558 return false;
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001559 return true;
1560 }
1561
1562 @Override
1563 public String toString() {
1564 return "KeyphraseRecognitionEvent [keyphraseExtras=" + Arrays.toString(keyphraseExtras)
Eric Laurentd3b82232014-07-30 08:57:39 -07001565 + ", status=" + status
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001566 + ", soundModelHandle=" + soundModelHandle + ", captureAvailable="
1567 + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs="
1568 + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs
Eric Laurentd3b82232014-07-30 08:57:39 -07001569 + ", triggerInData=" + triggerInData
1570 + ((captureFormat == null) ? "" :
1571 (", sampleRate=" + captureFormat.getSampleRate()))
1572 + ((captureFormat == null) ? "" :
1573 (", encoding=" + captureFormat.getEncoding()))
1574 + ((captureFormat == null) ? "" :
1575 (", channelMask=" + captureFormat.getChannelMask()))
Sandeep Siddhartha68173372014-07-28 13:25:30 -07001576 + ", data=" + (data == null ? 0 : data.length) + "]";
1577 }
Eric Laurente48188c2014-04-18 17:44:11 -07001578 }
1579
1580 /**
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001581 * Sub-class of RecognitionEvent specifically for sound-trigger based sound
1582 * models(non-keyphrase). Currently does not contain any additional fields.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001583 *
1584 * @hide
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001585 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001586 public static class GenericRecognitionEvent extends RecognitionEvent implements Parcelable {
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001587 @UnsupportedAppUsage
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001588 public GenericRecognitionEvent(int status, int soundModelHandle,
1589 boolean captureAvailable, int captureSession, int captureDelayMs,
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001590 int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat,
1591 @Nullable byte[] data) {
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001592 super(status, soundModelHandle, captureAvailable, captureSession,
1593 captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
1594 data);
1595 }
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001596
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001597 public static final @android.annotation.NonNull Parcelable.Creator<GenericRecognitionEvent> CREATOR
Arunesh Mishraf47f1732016-02-18 16:16:12 -08001598 = new Parcelable.Creator<GenericRecognitionEvent>() {
1599 public GenericRecognitionEvent createFromParcel(Parcel in) {
1600 return GenericRecognitionEvent.fromParcelForGeneric(in);
1601 }
1602
1603 public GenericRecognitionEvent[] newArray(int size) {
1604 return new GenericRecognitionEvent[size];
1605 }
1606 };
1607
1608 private static GenericRecognitionEvent fromParcelForGeneric(Parcel in) {
1609 RecognitionEvent event = RecognitionEvent.fromParcel(in);
1610 return new GenericRecognitionEvent(event.status, event.soundModelHandle,
1611 event.captureAvailable, event.captureSession, event.captureDelayMs,
1612 event.capturePreambleMs, event.triggerInData, event.captureFormat, event.data);
1613 }
1614
1615 @Override
1616 public boolean equals(Object obj) {
1617 if (this == obj)
1618 return true;
1619 if (obj == null)
1620 return false;
1621 if (getClass() != obj.getClass()) return false;
1622 RecognitionEvent other = (RecognitionEvent) obj;
1623 return super.equals(obj);
1624 }
1625
1626 @Override
1627 public String toString() {
1628 return "GenericRecognitionEvent ::" + super.toString();
1629 }
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001630 }
1631
1632 /**
Eric Laurentd3b82232014-07-30 08:57:39 -07001633 * Status codes for {@link SoundModelEvent}
1634 */
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001635 /**
1636 * Sound Model was updated
1637 *
1638 * @hide
1639 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001640 public static final int SOUNDMODEL_STATUS_UPDATED = 0;
1641
1642 /**
1643 * A SoundModelEvent is provided by the
1644 * {@link StatusListener#onSoundModelUpdate(SoundModelEvent)}
1645 * callback when a sound model has been updated by the implementation
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001646 *
1647 * @hide
Eric Laurentd3b82232014-07-30 08:57:39 -07001648 */
1649 public static class SoundModelEvent implements Parcelable {
1650 /** Status e.g {@link #SOUNDMODEL_STATUS_UPDATED} */
1651 public final int status;
1652 /** The updated sound model handle */
1653 public final int soundModelHandle;
1654 /** New sound model data */
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001655 @NonNull
Eric Laurentd3b82232014-07-30 08:57:39 -07001656 public final byte[] data;
1657
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001658 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001659 SoundModelEvent(int status, int soundModelHandle, @Nullable byte[] data) {
Eric Laurentd3b82232014-07-30 08:57:39 -07001660 this.status = status;
1661 this.soundModelHandle = soundModelHandle;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001662 this.data = data != null ? data : new byte[0];
Eric Laurentd3b82232014-07-30 08:57:39 -07001663 }
1664
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001665 public static final @android.annotation.NonNull Parcelable.Creator<SoundModelEvent> CREATOR
Eric Laurentd3b82232014-07-30 08:57:39 -07001666 = new Parcelable.Creator<SoundModelEvent>() {
1667 public SoundModelEvent createFromParcel(Parcel in) {
1668 return SoundModelEvent.fromParcel(in);
1669 }
1670
1671 public SoundModelEvent[] newArray(int size) {
1672 return new SoundModelEvent[size];
1673 }
1674 };
1675
1676 private static SoundModelEvent fromParcel(Parcel in) {
1677 int status = in.readInt();
1678 int soundModelHandle = in.readInt();
1679 byte[] data = in.readBlob();
1680 return new SoundModelEvent(status, soundModelHandle, data);
1681 }
1682
1683 @Override
1684 public int describeContents() {
1685 return 0;
1686 }
1687
1688 @Override
1689 public void writeToParcel(Parcel dest, int flags) {
1690 dest.writeInt(status);
1691 dest.writeInt(soundModelHandle);
1692 dest.writeBlob(data);
1693 }
1694
1695 @Override
1696 public int hashCode() {
1697 final int prime = 31;
1698 int result = 1;
1699 result = prime * result + Arrays.hashCode(data);
1700 result = prime * result + soundModelHandle;
1701 result = prime * result + status;
1702 return result;
1703 }
1704
1705 @Override
1706 public boolean equals(Object obj) {
1707 if (this == obj)
1708 return true;
1709 if (obj == null)
1710 return false;
1711 if (getClass() != obj.getClass())
1712 return false;
1713 SoundModelEvent other = (SoundModelEvent) obj;
1714 if (!Arrays.equals(data, other.data))
1715 return false;
1716 if (soundModelHandle != other.soundModelHandle)
1717 return false;
1718 if (status != other.status)
1719 return false;
1720 return true;
1721 }
1722
1723 @Override
1724 public String toString() {
1725 return "SoundModelEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
1726 + ", data=" + (data == null ? 0 : data.length) + "]";
1727 }
1728 }
1729
1730 /**
1731 * Native service state. {@link StatusListener#onServiceStateChange(int)}
1732 */
1733 // Keep in sync with system/core/include/system/sound_trigger.h
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001734 /**
1735 * Sound trigger service is enabled
1736 *
1737 * @hide
1738 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001739 public static final int SERVICE_STATE_ENABLED = 0;
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001740 /**
1741 * Sound trigger service is disabled
1742 *
1743 * @hide
1744 */
Eric Laurentd3b82232014-07-30 08:57:39 -07001745 public static final int SERVICE_STATE_DISABLED = 1;
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001746 private static Object mServiceLock = new Object();
1747 private static ISoundTriggerMiddlewareService mService;
1748 /**
jiabin1f4b4dd2019-03-18 18:07:03 -07001749 * @return returns current package name.
1750 */
1751 static String getCurrentOpPackageName() {
1752 String packageName = ActivityThread.currentOpPackageName();
1753 if (packageName == null) {
1754 return "";
1755 }
1756 return packageName;
1757 }
1758
1759 /**
Ytai Ben-Tsvi2e8f78b2020-01-15 11:57:34 -08001760 * Translate an exception thrown from interaction with the underlying service to an error code.
1761 * Throws a runtime exception for unexpected conditions.
1762 * @param e The caught exception.
1763 * @return The error code.
1764 *
1765 * @hide
1766 */
1767 static int handleException(Exception e) {
1768 Log.w(TAG, "Exception caught", e);
1769 if (e instanceof RemoteException) {
1770 return STATUS_DEAD_OBJECT;
1771 }
1772 if (e instanceof ServiceSpecificException) {
1773 switch (((ServiceSpecificException) e).errorCode) {
1774 case Status.OPERATION_NOT_SUPPORTED:
1775 return STATUS_INVALID_OPERATION;
1776 case Status.TEMPORARY_PERMISSION_DENIED:
1777 return STATUS_PERMISSION_DENIED;
1778 case Status.DEAD_OBJECT:
1779 return STATUS_DEAD_OBJECT;
1780 }
1781 return STATUS_ERROR;
1782 }
1783 if (e instanceof SecurityException) {
1784 return STATUS_PERMISSION_DENIED;
1785 }
1786 if (e instanceof IllegalStateException) {
1787 return STATUS_INVALID_OPERATION;
1788 }
1789 if (e instanceof IllegalArgumentException || e instanceof NullPointerException) {
1790 return STATUS_BAD_VALUE;
1791 }
1792 // This is not one of the conditions represented by our error code, escalate to a
1793 // RuntimeException.
1794 Log.e(TAG, "Escalating unexpected exception: ", e);
1795 throw new RuntimeException(e);
1796 }
1797
1798 /**
Arunesh Mishraa772e5f2016-01-25 10:33:11 -08001799 * Returns a list of descriptors for all hardware modules loaded.
Eric Laurente48188c2014-04-18 17:44:11 -07001800 * @param modules A ModuleProperties array where the list will be returned.
1801 * @return - {@link #STATUS_OK} in case of success
1802 * - {@link #STATUS_ERROR} in case of unspecified error
1803 * - {@link #STATUS_PERMISSION_DENIED} if the caller does not have system permission
1804 * - {@link #STATUS_NO_INIT} if the native service cannot be reached
1805 * - {@link #STATUS_BAD_VALUE} if modules is null
1806 * - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001807 *
1808 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001809 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001810 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001811 public static int listModules(@NonNull ArrayList<ModuleProperties> modules) {
1812 try {
1813 SoundTriggerModuleDescriptor[] descs = getService().listModules();
1814 modules.clear();
1815 modules.ensureCapacity(descs.length);
1816 for (SoundTriggerModuleDescriptor desc : descs) {
1817 modules.add(ConversionUtil.aidl2apiModuleDescriptor(desc));
1818 }
1819 return STATUS_OK;
Ytai Ben-Tsvi2e8f78b2020-01-15 11:57:34 -08001820 } catch (Exception e) {
1821 return handleException(e);
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001822 }
jiabin1f4b4dd2019-03-18 18:07:03 -07001823 }
1824
1825 /**
Eric Laurente48188c2014-04-18 17:44:11 -07001826 * Get an interface on a hardware module to control sound models and recognition on
1827 * this module.
1828 * @param moduleId Sound module system identifier {@link ModuleProperties#id}. mandatory.
1829 * @param listener {@link StatusListener} interface. Mandatory.
1830 * @param handler the Handler that will receive the callabcks. Can be null if default handler
1831 * is OK.
1832 * @return a valid sound module in case of success or null in case of error.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001833 *
1834 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001835 */
Mathew Inwoodbcbe4402018-08-08 15:42:59 +01001836 @UnsupportedAppUsage
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001837 public static @NonNull SoundTriggerModule attachModule(int moduleId,
1838 @NonNull StatusListener listener,
1839 @Nullable Handler handler) {
1840 Looper looper = handler != null ? handler.getLooper() : Looper.getMainLooper();
1841 try {
1842 return new SoundTriggerModule(getService(), moduleId, listener, looper);
1843 } catch (RemoteException e) {
1844 Log.e(TAG, "", e);
Eric Laurente48188c2014-04-18 17:44:11 -07001845 return null;
1846 }
Ytai Ben-Tsvi7d383d12019-11-25 12:47:40 -08001847 }
1848
1849 private static ISoundTriggerMiddlewareService getService() {
1850 synchronized (mServiceLock) {
1851 while (true) {
1852 IBinder binder = null;
1853 try {
1854 binder =
1855 ServiceManager.getServiceOrThrow(
1856 Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE);
1857 binder.linkToDeath(() -> {
1858 synchronized (mServiceLock) {
1859 mService = null;
1860 }
1861 }, 0);
1862 mService = ISoundTriggerMiddlewareService.Stub.asInterface(binder);
1863 break;
1864 } catch (Exception e) {
1865 Log.e(TAG, "Failed to bind to soundtrigger service", e);
1866 }
1867 }
1868 return mService;
1869 }
1870
Eric Laurente48188c2014-04-18 17:44:11 -07001871 }
1872
1873 /**
1874 * Interface provided by the client application when attaching to a {@link SoundTriggerModule}
1875 * to received recognition and error notifications.
Philip P. Moltmanna5fd0292018-03-06 13:44:07 -08001876 *
1877 * @hide
Eric Laurente48188c2014-04-18 17:44:11 -07001878 */
1879 public static interface StatusListener {
1880 /**
1881 * Called when recognition succeeds of fails
1882 */
1883 public abstract void onRecognition(RecognitionEvent event);
1884
1885 /**
Eric Laurentd3b82232014-07-30 08:57:39 -07001886 * Called when a sound model has been updated
1887 */
1888 public abstract void onSoundModelUpdate(SoundModelEvent event);
1889
1890 /**
1891 * Called when the sound trigger native service state changes.
1892 * @param state Native service state. One of {@link SoundTrigger#SERVICE_STATE_ENABLED},
1893 * {@link SoundTrigger#SERVICE_STATE_DISABLED}
1894 */
1895 public abstract void onServiceStateChange(int state);
1896
1897 /**
Eric Laurente48188c2014-04-18 17:44:11 -07001898 * Called when the sound trigger native service dies
1899 */
1900 public abstract void onServiceDied();
1901 }
1902}