• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * 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 
17 package android.hardware.soundtrigger;
18 
19 import static android.system.OsConstants.EINVAL;
20 import static android.system.OsConstants.ENODEV;
21 import static android.system.OsConstants.ENOSYS;
22 import static android.system.OsConstants.EPERM;
23 import static android.system.OsConstants.EPIPE;
24 
25 import android.annotation.Nullable;
26 import android.annotation.SystemApi;
27 import android.media.AudioFormat;
28 import android.os.Handler;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.UUID;
35 
36 /**
37  * The SoundTrigger class provides access via JNI to the native service managing
38  * the sound trigger HAL.
39  *
40  * @hide
41  */
42 @SystemApi
43 public class SoundTrigger {
44 
SoundTrigger()45     private SoundTrigger() {
46     }
47 
48     /**
49      * Status code used when the operation succeeded
50      */
51     public static final int STATUS_OK = 0;
52     /** @hide */
53     public static final int STATUS_ERROR = Integer.MIN_VALUE;
54     /** @hide */
55     public static final int STATUS_PERMISSION_DENIED = -EPERM;
56     /** @hide */
57     public static final int STATUS_NO_INIT = -ENODEV;
58     /** @hide */
59     public static final int STATUS_BAD_VALUE = -EINVAL;
60     /** @hide */
61     public static final int STATUS_DEAD_OBJECT = -EPIPE;
62     /** @hide */
63     public static final int STATUS_INVALID_OPERATION = -ENOSYS;
64 
65     /*****************************************************************************
66      * A ModuleProperties describes a given sound trigger hardware module
67      * managed by the native sound trigger service. Each module has a unique
68      * ID used to target any API call to this paricular module. Module
69      * properties are returned by listModules() method.
70      *
71      * @hide
72      ****************************************************************************/
73     public static class ModuleProperties implements Parcelable {
74         /** Unique module ID provided by the native service */
75         public final int id;
76 
77         /** human readable voice detection engine implementor */
78         public final String implementor;
79 
80         /** human readable voice detection engine description */
81         public final String description;
82 
83         /** Unique voice engine Id (changes with each version) */
84         public final UUID uuid;
85 
86         /** Voice detection engine version */
87         public final int version;
88 
89         /** Maximum number of active sound models */
90         public final int maxSoundModels;
91 
92         /** Maximum number of key phrases */
93         public final int maxKeyphrases;
94 
95         /** Maximum number of users per key phrase */
96         public final int maxUsers;
97 
98         /** Supported recognition modes (bit field, RECOGNITION_MODE_VOICE_TRIGGER ...) */
99         public final int recognitionModes;
100 
101         /** Supports seamless transition to capture mode after recognition */
102         public final boolean supportsCaptureTransition;
103 
104         /** Maximum buffering capacity in ms if supportsCaptureTransition() is true */
105         public final int maxBufferMs;
106 
107         /** Supports capture by other use cases while detection is active */
108         public final boolean supportsConcurrentCapture;
109 
110         /** Rated power consumption when detection is active with TDB silence/sound/speech ratio */
111         public final int powerConsumptionMw;
112 
113         /** Returns the trigger (key phrase) capture in the binary data of the
114          * recognition callback event */
115         public final boolean returnsTriggerInEvent;
116 
ModuleProperties(int id, String implementor, String description, String uuid, int version, int maxSoundModels, int maxKeyphrases, int maxUsers, int recognitionModes, boolean supportsCaptureTransition, int maxBufferMs, boolean supportsConcurrentCapture, int powerConsumptionMw, boolean returnsTriggerInEvent)117         ModuleProperties(int id, String implementor, String description,
118                 String uuid, int version, int maxSoundModels, int maxKeyphrases,
119                 int maxUsers, int recognitionModes, boolean supportsCaptureTransition,
120                 int maxBufferMs, boolean supportsConcurrentCapture,
121                 int powerConsumptionMw, boolean returnsTriggerInEvent) {
122             this.id = id;
123             this.implementor = implementor;
124             this.description = description;
125             this.uuid = UUID.fromString(uuid);
126             this.version = version;
127             this.maxSoundModels = maxSoundModels;
128             this.maxKeyphrases = maxKeyphrases;
129             this.maxUsers = maxUsers;
130             this.recognitionModes = recognitionModes;
131             this.supportsCaptureTransition = supportsCaptureTransition;
132             this.maxBufferMs = maxBufferMs;
133             this.supportsConcurrentCapture = supportsConcurrentCapture;
134             this.powerConsumptionMw = powerConsumptionMw;
135             this.returnsTriggerInEvent = returnsTriggerInEvent;
136         }
137 
138         public static final Parcelable.Creator<ModuleProperties> CREATOR
139                 = new Parcelable.Creator<ModuleProperties>() {
140             public ModuleProperties createFromParcel(Parcel in) {
141                 return ModuleProperties.fromParcel(in);
142             }
143 
144             public ModuleProperties[] newArray(int size) {
145                 return new ModuleProperties[size];
146             }
147         };
148 
fromParcel(Parcel in)149         private static ModuleProperties fromParcel(Parcel in) {
150             int id = in.readInt();
151             String implementor = in.readString();
152             String description = in.readString();
153             String uuid = in.readString();
154             int version = in.readInt();
155             int maxSoundModels = in.readInt();
156             int maxKeyphrases = in.readInt();
157             int maxUsers = in.readInt();
158             int recognitionModes = in.readInt();
159             boolean supportsCaptureTransition = in.readByte() == 1;
160             int maxBufferMs = in.readInt();
161             boolean supportsConcurrentCapture = in.readByte() == 1;
162             int powerConsumptionMw = in.readInt();
163             boolean returnsTriggerInEvent = in.readByte() == 1;
164             return new ModuleProperties(id, implementor, description, uuid, version,
165                     maxSoundModels, maxKeyphrases, maxUsers, recognitionModes,
166                     supportsCaptureTransition, maxBufferMs, supportsConcurrentCapture,
167                     powerConsumptionMw, returnsTriggerInEvent);
168         }
169 
170         @Override
writeToParcel(Parcel dest, int flags)171         public void writeToParcel(Parcel dest, int flags) {
172             dest.writeInt(id);
173             dest.writeString(implementor);
174             dest.writeString(description);
175             dest.writeString(uuid.toString());
176             dest.writeInt(version);
177             dest.writeInt(maxSoundModels);
178             dest.writeInt(maxKeyphrases);
179             dest.writeInt(maxUsers);
180             dest.writeInt(recognitionModes);
181             dest.writeByte((byte) (supportsCaptureTransition ? 1 : 0));
182             dest.writeInt(maxBufferMs);
183             dest.writeByte((byte) (supportsConcurrentCapture ? 1 : 0));
184             dest.writeInt(powerConsumptionMw);
185             dest.writeByte((byte) (returnsTriggerInEvent ? 1 : 0));
186         }
187 
188         @Override
describeContents()189         public int describeContents() {
190             return 0;
191         }
192 
193         @Override
toString()194         public String toString() {
195             return "ModuleProperties [id=" + id + ", implementor=" + implementor + ", description="
196                     + description + ", uuid=" + uuid + ", version=" + version + ", maxSoundModels="
197                     + maxSoundModels + ", maxKeyphrases=" + maxKeyphrases + ", maxUsers="
198                     + maxUsers + ", recognitionModes=" + recognitionModes
199                     + ", supportsCaptureTransition=" + supportsCaptureTransition + ", maxBufferMs="
200                     + maxBufferMs + ", supportsConcurrentCapture=" + supportsConcurrentCapture
201                     + ", powerConsumptionMw=" + powerConsumptionMw
202                     + ", returnsTriggerInEvent=" + returnsTriggerInEvent + "]";
203         }
204     }
205 
206     /*****************************************************************************
207      * A SoundModel describes the attributes and contains the binary data used by the hardware
208      * implementation to detect a particular sound pattern.
209      * A specialized version {@link KeyphraseSoundModel} is defined for key phrase
210      * sound models.
211      *
212      * @hide
213      ****************************************************************************/
214     public static class SoundModel {
215         /** Undefined sound model type */
216         public static final int TYPE_UNKNOWN = -1;
217 
218         /** Keyphrase sound model */
219         public static final int TYPE_KEYPHRASE = 0;
220 
221         /**
222          * A generic sound model. Use this type only for non-keyphrase sound models such as
223          * ones that match a particular sound pattern.
224          */
225         public static final int TYPE_GENERIC_SOUND = 1;
226 
227         /** Unique sound model identifier */
228         public final UUID uuid;
229 
230         /** Sound model type (e.g. TYPE_KEYPHRASE); */
231         public final int type;
232 
233         /** Unique sound model vendor identifier */
234         public final UUID vendorUuid;
235 
236         /** Opaque data. For use by vendor implementation and enrollment application */
237         public final byte[] data;
238 
SoundModel(UUID uuid, UUID vendorUuid, int type, byte[] data)239         public SoundModel(UUID uuid, UUID vendorUuid, int type, byte[] data) {
240             this.uuid = uuid;
241             this.vendorUuid = vendorUuid;
242             this.type = type;
243             this.data = data;
244         }
245 
246         @Override
hashCode()247         public int hashCode() {
248             final int prime = 31;
249             int result = 1;
250             result = prime * result + Arrays.hashCode(data);
251             result = prime * result + type;
252             result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
253             result = prime * result + ((vendorUuid == null) ? 0 : vendorUuid.hashCode());
254             return result;
255         }
256 
257         @Override
equals(Object obj)258         public boolean equals(Object obj) {
259             if (this == obj)
260                 return true;
261             if (obj == null)
262                 return false;
263             if (!(obj instanceof SoundModel))
264                 return false;
265             SoundModel other = (SoundModel) obj;
266             if (!Arrays.equals(data, other.data))
267                 return false;
268             if (type != other.type)
269                 return false;
270             if (uuid == null) {
271                 if (other.uuid != null)
272                     return false;
273             } else if (!uuid.equals(other.uuid))
274                 return false;
275             if (vendorUuid == null) {
276                 if (other.vendorUuid != null)
277                     return false;
278             } else if (!vendorUuid.equals(other.vendorUuid))
279                 return false;
280             return true;
281         }
282     }
283 
284     /*****************************************************************************
285      * A Keyphrase describes a key phrase that can be detected by a
286      * {@link KeyphraseSoundModel}
287      *
288      * @hide
289      ****************************************************************************/
290     public static class Keyphrase implements Parcelable {
291         /** Unique identifier for this keyphrase */
292         public final int id;
293 
294         /** Recognition modes supported for this key phrase in the model */
295         public final int recognitionModes;
296 
297         /** Locale of the keyphrase. JAVA Locale string e.g en_US */
298         public final String locale;
299 
300         /** Key phrase text */
301         public final String text;
302 
303         /** Users this key phrase has been trained for. countains sound trigger specific user IDs
304          * derived from system user IDs {@link android.os.UserHandle#getIdentifier()}. */
305         public final int[] users;
306 
Keyphrase(int id, int recognitionModes, String locale, String text, int[] users)307         public Keyphrase(int id, int recognitionModes, String locale, String text, int[] users) {
308             this.id = id;
309             this.recognitionModes = recognitionModes;
310             this.locale = locale;
311             this.text = text;
312             this.users = users;
313         }
314 
315         public static final Parcelable.Creator<Keyphrase> CREATOR
316                 = new Parcelable.Creator<Keyphrase>() {
317             public Keyphrase createFromParcel(Parcel in) {
318                 return Keyphrase.fromParcel(in);
319             }
320 
321             public Keyphrase[] newArray(int size) {
322                 return new Keyphrase[size];
323             }
324         };
325 
fromParcel(Parcel in)326         private static Keyphrase fromParcel(Parcel in) {
327             int id = in.readInt();
328             int recognitionModes = in.readInt();
329             String locale = in.readString();
330             String text = in.readString();
331             int[] users = null;
332             int numUsers = in.readInt();
333             if (numUsers >= 0) {
334                 users = new int[numUsers];
335                 in.readIntArray(users);
336             }
337             return new Keyphrase(id, recognitionModes, locale, text, users);
338         }
339 
340         @Override
writeToParcel(Parcel dest, int flags)341         public void writeToParcel(Parcel dest, int flags) {
342             dest.writeInt(id);
343             dest.writeInt(recognitionModes);
344             dest.writeString(locale);
345             dest.writeString(text);
346             if (users != null) {
347                 dest.writeInt(users.length);
348                 dest.writeIntArray(users);
349             } else {
350                 dest.writeInt(-1);
351             }
352         }
353 
354         @Override
describeContents()355         public int describeContents() {
356             return 0;
357         }
358 
359         @Override
hashCode()360         public int hashCode() {
361             final int prime = 31;
362             int result = 1;
363             result = prime * result + ((text == null) ? 0 : text.hashCode());
364             result = prime * result + id;
365             result = prime * result + ((locale == null) ? 0 : locale.hashCode());
366             result = prime * result + recognitionModes;
367             result = prime * result + Arrays.hashCode(users);
368             return result;
369         }
370 
371         @Override
equals(Object obj)372         public boolean equals(Object obj) {
373             if (this == obj)
374                 return true;
375             if (obj == null)
376                 return false;
377             if (getClass() != obj.getClass())
378                 return false;
379             Keyphrase other = (Keyphrase) obj;
380             if (text == null) {
381                 if (other.text != null)
382                     return false;
383             } else if (!text.equals(other.text))
384                 return false;
385             if (id != other.id)
386                 return false;
387             if (locale == null) {
388                 if (other.locale != null)
389                     return false;
390             } else if (!locale.equals(other.locale))
391                 return false;
392             if (recognitionModes != other.recognitionModes)
393                 return false;
394             if (!Arrays.equals(users, other.users))
395                 return false;
396             return true;
397         }
398 
399         @Override
toString()400         public String toString() {
401             return "Keyphrase [id=" + id + ", recognitionModes=" + recognitionModes + ", locale="
402                     + locale + ", text=" + text + ", users=" + Arrays.toString(users) + "]";
403         }
404     }
405 
406     /*****************************************************************************
407      * A KeyphraseSoundModel is a specialized {@link SoundModel} for key phrases.
408      * It contains data needed by the hardware to detect a certain number of key phrases
409      * and the list of corresponding {@link Keyphrase} descriptors.
410      *
411      * @hide
412      ****************************************************************************/
413     public static class KeyphraseSoundModel extends SoundModel implements Parcelable {
414         /** Key phrases in this sound model */
415         public final Keyphrase[] keyphrases; // keyword phrases in model
416 
KeyphraseSoundModel( UUID uuid, UUID vendorUuid, byte[] data, Keyphrase[] keyphrases)417         public KeyphraseSoundModel(
418                 UUID uuid, UUID vendorUuid, byte[] data, Keyphrase[] keyphrases) {
419             super(uuid, vendorUuid, TYPE_KEYPHRASE, data);
420             this.keyphrases = keyphrases;
421         }
422 
423         public static final Parcelable.Creator<KeyphraseSoundModel> CREATOR
424                 = new Parcelable.Creator<KeyphraseSoundModel>() {
425             public KeyphraseSoundModel createFromParcel(Parcel in) {
426                 return KeyphraseSoundModel.fromParcel(in);
427             }
428 
429             public KeyphraseSoundModel[] newArray(int size) {
430                 return new KeyphraseSoundModel[size];
431             }
432         };
433 
fromParcel(Parcel in)434         private static KeyphraseSoundModel fromParcel(Parcel in) {
435             UUID uuid = UUID.fromString(in.readString());
436             UUID vendorUuid = null;
437             int length = in.readInt();
438             if (length >= 0) {
439                 vendorUuid = UUID.fromString(in.readString());
440             }
441             byte[] data = in.readBlob();
442             Keyphrase[] keyphrases = in.createTypedArray(Keyphrase.CREATOR);
443             return new KeyphraseSoundModel(uuid, vendorUuid, data, keyphrases);
444         }
445 
446         @Override
describeContents()447         public int describeContents() {
448             return 0;
449         }
450 
451         @Override
writeToParcel(Parcel dest, int flags)452         public void writeToParcel(Parcel dest, int flags) {
453             dest.writeString(uuid.toString());
454             if (vendorUuid == null) {
455                 dest.writeInt(-1);
456             } else {
457                 dest.writeInt(vendorUuid.toString().length());
458                 dest.writeString(vendorUuid.toString());
459             }
460             dest.writeBlob(data);
461             dest.writeTypedArray(keyphrases, flags);
462         }
463 
464         @Override
toString()465         public String toString() {
466             return "KeyphraseSoundModel [keyphrases=" + Arrays.toString(keyphrases)
467                     + ", uuid=" + uuid + ", vendorUuid=" + vendorUuid
468                     + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]";
469         }
470 
471         @Override
hashCode()472         public int hashCode() {
473             final int prime = 31;
474             int result = super.hashCode();
475             result = prime * result + Arrays.hashCode(keyphrases);
476             return result;
477         }
478 
479         @Override
equals(Object obj)480         public boolean equals(Object obj) {
481             if (this == obj)
482                 return true;
483             if (!super.equals(obj))
484                 return false;
485             if (!(obj instanceof KeyphraseSoundModel))
486                 return false;
487             KeyphraseSoundModel other = (KeyphraseSoundModel) obj;
488             if (!Arrays.equals(keyphrases, other.keyphrases))
489                 return false;
490             return true;
491         }
492     }
493 
494 
495     /*****************************************************************************
496      * A GenericSoundModel is a specialized {@link SoundModel} for non-voice sound
497      * patterns.
498      *
499      * @hide
500      ****************************************************************************/
501     public static class GenericSoundModel extends SoundModel implements Parcelable {
502 
503         public static final Parcelable.Creator<GenericSoundModel> CREATOR
504                 = new Parcelable.Creator<GenericSoundModel>() {
505             public GenericSoundModel createFromParcel(Parcel in) {
506                 return GenericSoundModel.fromParcel(in);
507             }
508 
509             public GenericSoundModel[] newArray(int size) {
510                 return new GenericSoundModel[size];
511             }
512         };
513 
GenericSoundModel(UUID uuid, UUID vendorUuid, byte[] data)514         public GenericSoundModel(UUID uuid, UUID vendorUuid, byte[] data) {
515             super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data);
516         }
517 
518         @Override
describeContents()519         public int describeContents() {
520             return 0;
521         }
522 
fromParcel(Parcel in)523         private static GenericSoundModel fromParcel(Parcel in) {
524             UUID uuid = UUID.fromString(in.readString());
525             UUID vendorUuid = null;
526             int length = in.readInt();
527             if (length >= 0) {
528                 vendorUuid = UUID.fromString(in.readString());
529             }
530             byte[] data = in.readBlob();
531             return new GenericSoundModel(uuid, vendorUuid, data);
532         }
533 
534         @Override
writeToParcel(Parcel dest, int flags)535         public void writeToParcel(Parcel dest, int flags) {
536             dest.writeString(uuid.toString());
537             if (vendorUuid == null) {
538                 dest.writeInt(-1);
539             } else {
540                 dest.writeInt(vendorUuid.toString().length());
541                 dest.writeString(vendorUuid.toString());
542             }
543             dest.writeBlob(data);
544         }
545 
546         @Override
toString()547         public String toString() {
548             return "GenericSoundModel [uuid=" + uuid + ", vendorUuid=" + vendorUuid
549                     + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]";
550         }
551     }
552 
553     /**
554      *  Modes for key phrase recognition
555      */
556 
557     /**
558      * Simple recognition of the key phrase
559      *
560      * @hide
561      */
562     public static final int RECOGNITION_MODE_VOICE_TRIGGER = 0x1;
563     /**
564      * Trigger only if one user is identified
565      *
566      * @hide
567      */
568     public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 0x2;
569     /**
570      * Trigger only if one user is authenticated
571      *
572      * @hide
573      */
574     public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 0x4;
575 
576     /**
577      *  Status codes for {@link RecognitionEvent}
578      */
579     /**
580      * Recognition success
581      *
582      * @hide
583      */
584     public static final int RECOGNITION_STATUS_SUCCESS = 0;
585     /**
586      * Recognition aborted (e.g. capture preempted by anotehr use case
587      *
588      * @hide
589      */
590     public static final int RECOGNITION_STATUS_ABORT = 1;
591     /**
592      * Recognition failure
593      *
594      * @hide
595      */
596     public static final int RECOGNITION_STATUS_FAILURE = 2;
597 
598     /**
599      *  A RecognitionEvent is provided by the
600      *  {@code StatusListener#onRecognition(RecognitionEvent)}
601      *  callback upon recognition success or failure.
602      */
603     public static class RecognitionEvent {
604         /**
605          * Recognition status e.g RECOGNITION_STATUS_SUCCESS
606          *
607          * @hide
608          */
609         public final int status;
610         /**
611          *
612          * Sound Model corresponding to this event callback
613          *
614          * @hide
615          */
616         public final int soundModelHandle;
617         /**
618          * True if it is possible to capture audio from this utterance buffered by the hardware
619          *
620          * @hide
621          */
622         public final boolean captureAvailable;
623         /**
624          * Audio session ID to be used when capturing the utterance with an AudioRecord
625          * if captureAvailable() is true.
626          *
627          * @hide
628          */
629         public final int captureSession;
630         /**
631          * Delay in ms between end of model detection and start of audio available for capture.
632          * A negative value is possible (e.g. if keyphrase is also available for capture)
633          *
634          * @hide
635          */
636         public final int captureDelayMs;
637         /**
638          * Duration in ms of audio captured before the start of the trigger. 0 if none.
639          *
640          * @hide
641          */
642         public final int capturePreambleMs;
643         /**
644          * True if  the trigger (key phrase capture is present in binary data
645          *
646          * @hide
647          */
648         public final boolean triggerInData;
649         /**
650          * Audio format of either the trigger in event data or to use for capture of the
651          * rest of the utterance
652          *
653          * @hide
654          */
655         public final AudioFormat captureFormat;
656         /**
657          * Opaque data for use by system applications who know about voice engine internals,
658          * typically during enrollment.
659          *
660          * @hide
661          */
662         public final byte[] data;
663 
664         /** @hide */
RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, AudioFormat captureFormat, byte[] data)665         public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
666                 int captureSession, int captureDelayMs, int capturePreambleMs,
667                 boolean triggerInData, AudioFormat captureFormat, byte[] data) {
668             this.status = status;
669             this.soundModelHandle = soundModelHandle;
670             this.captureAvailable = captureAvailable;
671             this.captureSession = captureSession;
672             this.captureDelayMs = captureDelayMs;
673             this.capturePreambleMs = capturePreambleMs;
674             this.triggerInData = triggerInData;
675             this.captureFormat = captureFormat;
676             this.data = data;
677         }
678 
679         /**
680          * Check if is possible to capture audio from this utterance buffered by the hardware.
681          *
682          * @return {@code true} iff a capturing is possible
683          */
isCaptureAvailable()684         public boolean isCaptureAvailable() {
685             return captureAvailable;
686         }
687 
688         /**
689          * Get the audio format of either the trigger in event data or to use for capture of the
690          * rest of the utterance
691          *
692          * @return the audio format
693          */
getCaptureFormat()694         @Nullable public AudioFormat getCaptureFormat() {
695             return captureFormat;
696         }
697 
698         /**
699          * Get Audio session ID to be used when capturing the utterance with an {@link AudioRecord}
700          * if {@link #isCaptureAvailable()} is true.
701          *
702          * @return The id of the capture session
703          */
getCaptureSession()704         public int getCaptureSession() {
705             return captureSession;
706         }
707 
708         /**
709          * Get the opaque data for use by system applications who know about voice engine
710          * internals, typically during enrollment.
711          *
712          * @return The data of the event
713          */
getData()714         public byte[] getData() {
715             return data;
716         }
717 
718         /** @hide */
719         public static final Parcelable.Creator<RecognitionEvent> CREATOR
720                 = new Parcelable.Creator<RecognitionEvent>() {
721             public RecognitionEvent createFromParcel(Parcel in) {
722                 return RecognitionEvent.fromParcel(in);
723             }
724 
725             public RecognitionEvent[] newArray(int size) {
726                 return new RecognitionEvent[size];
727             }
728         };
729 
730         /** @hide */
fromParcel(Parcel in)731         protected static RecognitionEvent fromParcel(Parcel in) {
732             int status = in.readInt();
733             int soundModelHandle = in.readInt();
734             boolean captureAvailable = in.readByte() == 1;
735             int captureSession = in.readInt();
736             int captureDelayMs = in.readInt();
737             int capturePreambleMs = in.readInt();
738             boolean triggerInData = in.readByte() == 1;
739             AudioFormat captureFormat = null;
740             if (in.readByte() == 1) {
741                 int sampleRate = in.readInt();
742                 int encoding = in.readInt();
743                 int channelMask = in.readInt();
744                 captureFormat = (new AudioFormat.Builder())
745                         .setChannelMask(channelMask)
746                         .setEncoding(encoding)
747                         .setSampleRate(sampleRate)
748                         .build();
749             }
750             byte[] data = in.readBlob();
751             return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession,
752                     captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data);
753         }
754 
755         /** @hide */
describeContents()756         public int describeContents() {
757             return 0;
758         }
759 
760         /** @hide */
writeToParcel(Parcel dest, int flags)761         public void writeToParcel(Parcel dest, int flags) {
762             dest.writeInt(status);
763             dest.writeInt(soundModelHandle);
764             dest.writeByte((byte) (captureAvailable ? 1 : 0));
765             dest.writeInt(captureSession);
766             dest.writeInt(captureDelayMs);
767             dest.writeInt(capturePreambleMs);
768             dest.writeByte((byte) (triggerInData ? 1 : 0));
769             if (captureFormat != null) {
770                 dest.writeByte((byte)1);
771                 dest.writeInt(captureFormat.getSampleRate());
772                 dest.writeInt(captureFormat.getEncoding());
773                 dest.writeInt(captureFormat.getChannelMask());
774             } else {
775                 dest.writeByte((byte)0);
776             }
777             dest.writeBlob(data);
778         }
779 
780         @Override
hashCode()781         public int hashCode() {
782             final int prime = 31;
783             int result = 1;
784             result = prime * result + (captureAvailable ? 1231 : 1237);
785             result = prime * result + captureDelayMs;
786             result = prime * result + capturePreambleMs;
787             result = prime * result + captureSession;
788             result = prime * result + (triggerInData ? 1231 : 1237);
789             if (captureFormat != null) {
790                 result = prime * result + captureFormat.getSampleRate();
791                 result = prime * result + captureFormat.getEncoding();
792                 result = prime * result + captureFormat.getChannelMask();
793             }
794             result = prime * result + Arrays.hashCode(data);
795             result = prime * result + soundModelHandle;
796             result = prime * result + status;
797             return result;
798         }
799 
800         @Override
equals(Object obj)801         public boolean equals(Object obj) {
802             if (this == obj)
803                 return true;
804             if (obj == null)
805                 return false;
806             if (getClass() != obj.getClass())
807                 return false;
808             RecognitionEvent other = (RecognitionEvent) obj;
809             if (captureAvailable != other.captureAvailable)
810                 return false;
811             if (captureDelayMs != other.captureDelayMs)
812                 return false;
813             if (capturePreambleMs != other.capturePreambleMs)
814                 return false;
815             if (captureSession != other.captureSession)
816                 return false;
817             if (!Arrays.equals(data, other.data))
818                 return false;
819             if (soundModelHandle != other.soundModelHandle)
820                 return false;
821             if (status != other.status)
822                 return false;
823             if (triggerInData != other.triggerInData)
824                 return false;
825             if (captureFormat == null) {
826                 if (other.captureFormat != null)
827                     return false;
828             } else {
829                 if (other.captureFormat == null)
830                     return false;
831                 if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
832                     return false;
833                 if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
834                     return false;
835                 if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
836                     return false;
837             }
838             return true;
839         }
840 
841         @Override
toString()842         public String toString() {
843             return "RecognitionEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
844                     + ", captureAvailable=" + captureAvailable + ", captureSession="
845                     + captureSession + ", captureDelayMs=" + captureDelayMs
846                     + ", capturePreambleMs=" + capturePreambleMs
847                     + ", triggerInData=" + triggerInData
848                     + ((captureFormat == null) ? "" :
849                         (", sampleRate=" + captureFormat.getSampleRate()))
850                     + ((captureFormat == null) ? "" :
851                         (", encoding=" + captureFormat.getEncoding()))
852                     + ((captureFormat == null) ? "" :
853                         (", channelMask=" + captureFormat.getChannelMask()))
854                     + ", data=" + (data == null ? 0 : data.length) + "]";
855         }
856     }
857 
858     /**
859      *  A RecognitionConfig is provided to
860      *  {@link SoundTriggerModule#startRecognition(int, RecognitionConfig)} to configure the
861      *  recognition request.
862      *
863      *  @hide
864      */
865     public static class RecognitionConfig implements Parcelable {
866         /** True if the DSP should capture the trigger sound and make it available for further
867          * capture. */
868         public final boolean captureRequested;
869         /**
870          * True if the service should restart listening after the DSP triggers.
871          * Note: This config flag is currently used at the service layer rather than by the DSP.
872          */
873         public final boolean allowMultipleTriggers;
874         /** List of all keyphrases in the sound model for which recognition should be performed with
875          * options for each keyphrase. */
876         public final KeyphraseRecognitionExtra keyphrases[];
877         /** Opaque data for use by system applications who know about voice engine internals,
878          * typically during enrollment. */
879         public final byte[] data;
880 
RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers, KeyphraseRecognitionExtra[] keyphrases, byte[] data)881         public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
882                 KeyphraseRecognitionExtra[] keyphrases, byte[] data) {
883             this.captureRequested = captureRequested;
884             this.allowMultipleTriggers = allowMultipleTriggers;
885             this.keyphrases = keyphrases;
886             this.data = data;
887         }
888 
889         public static final Parcelable.Creator<RecognitionConfig> CREATOR
890                 = new Parcelable.Creator<RecognitionConfig>() {
891             public RecognitionConfig createFromParcel(Parcel in) {
892                 return RecognitionConfig.fromParcel(in);
893             }
894 
895             public RecognitionConfig[] newArray(int size) {
896                 return new RecognitionConfig[size];
897             }
898         };
899 
fromParcel(Parcel in)900         private static RecognitionConfig fromParcel(Parcel in) {
901             boolean captureRequested = in.readByte() == 1;
902             boolean allowMultipleTriggers = in.readByte() == 1;
903             KeyphraseRecognitionExtra[] keyphrases =
904                     in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
905             byte[] data = in.readBlob();
906             return new RecognitionConfig(captureRequested, allowMultipleTriggers, keyphrases, data);
907         }
908 
909         @Override
writeToParcel(Parcel dest, int flags)910         public void writeToParcel(Parcel dest, int flags) {
911             dest.writeByte((byte) (captureRequested ? 1 : 0));
912             dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0));
913             dest.writeTypedArray(keyphrases, flags);
914             dest.writeBlob(data);
915         }
916 
917         @Override
describeContents()918         public int describeContents() {
919             return 0;
920         }
921 
922         @Override
toString()923         public String toString() {
924             return "RecognitionConfig [captureRequested=" + captureRequested
925                     + ", allowMultipleTriggers=" + allowMultipleTriggers + ", keyphrases="
926                     + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data) + "]";
927         }
928     }
929 
930     /**
931      * Confidence level for users defined in a keyphrase.
932      * - The confidence level is expressed in percent (0% -100%).
933      * When used in a {@link KeyphraseRecognitionEvent} it indicates the detected confidence level
934      * When used in a {@link RecognitionConfig} it indicates the minimum confidence level that
935      * should trigger a recognition.
936      * - The user ID is derived from the system ID {@link android.os.UserHandle#getIdentifier()}.
937      *
938      * @hide
939      */
940     public static class ConfidenceLevel implements Parcelable {
941         public final int userId;
942         public final int confidenceLevel;
943 
ConfidenceLevel(int userId, int confidenceLevel)944         public ConfidenceLevel(int userId, int confidenceLevel) {
945             this.userId = userId;
946             this.confidenceLevel = confidenceLevel;
947         }
948 
949         public static final Parcelable.Creator<ConfidenceLevel> CREATOR
950                 = new Parcelable.Creator<ConfidenceLevel>() {
951             public ConfidenceLevel createFromParcel(Parcel in) {
952                 return ConfidenceLevel.fromParcel(in);
953             }
954 
955             public ConfidenceLevel[] newArray(int size) {
956                 return new ConfidenceLevel[size];
957             }
958         };
959 
fromParcel(Parcel in)960         private static ConfidenceLevel fromParcel(Parcel in) {
961             int userId = in.readInt();
962             int confidenceLevel = in.readInt();
963             return new ConfidenceLevel(userId, confidenceLevel);
964         }
965 
966         @Override
writeToParcel(Parcel dest, int flags)967         public void writeToParcel(Parcel dest, int flags) {
968             dest.writeInt(userId);
969             dest.writeInt(confidenceLevel);
970         }
971 
972         @Override
describeContents()973         public int describeContents() {
974             return 0;
975         }
976 
977         @Override
hashCode()978         public int hashCode() {
979             final int prime = 31;
980             int result = 1;
981             result = prime * result + confidenceLevel;
982             result = prime * result + userId;
983             return result;
984         }
985 
986         @Override
equals(Object obj)987         public boolean equals(Object obj) {
988             if (this == obj)
989                 return true;
990             if (obj == null)
991                 return false;
992             if (getClass() != obj.getClass())
993                 return false;
994             ConfidenceLevel other = (ConfidenceLevel) obj;
995             if (confidenceLevel != other.confidenceLevel)
996                 return false;
997             if (userId != other.userId)
998                 return false;
999             return true;
1000         }
1001 
1002         @Override
toString()1003         public String toString() {
1004             return "ConfidenceLevel [userId=" + userId
1005                     + ", confidenceLevel=" + confidenceLevel + "]";
1006         }
1007     }
1008 
1009     /**
1010      *  Additional data conveyed by a {@link KeyphraseRecognitionEvent}
1011      *  for a key phrase detection.
1012      *
1013      * @hide
1014      */
1015     public static class KeyphraseRecognitionExtra implements Parcelable {
1016         /** The keyphrase ID */
1017         public final int id;
1018 
1019         /** Recognition modes matched for this event */
1020         public final int recognitionModes;
1021 
1022         /** Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification
1023          * is not performed */
1024         public final int coarseConfidenceLevel;
1025 
1026         /** Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to
1027          * be recognized (RecognitionConfig) */
1028         public final ConfidenceLevel[] confidenceLevels;
1029 
KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel, ConfidenceLevel[] confidenceLevels)1030         public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel,
1031                 ConfidenceLevel[] confidenceLevels) {
1032             this.id = id;
1033             this.recognitionModes = recognitionModes;
1034             this.coarseConfidenceLevel = coarseConfidenceLevel;
1035             this.confidenceLevels = confidenceLevels;
1036         }
1037 
1038         public static final Parcelable.Creator<KeyphraseRecognitionExtra> CREATOR
1039                 = new Parcelable.Creator<KeyphraseRecognitionExtra>() {
1040             public KeyphraseRecognitionExtra createFromParcel(Parcel in) {
1041                 return KeyphraseRecognitionExtra.fromParcel(in);
1042             }
1043 
1044             public KeyphraseRecognitionExtra[] newArray(int size) {
1045                 return new KeyphraseRecognitionExtra[size];
1046             }
1047         };
1048 
fromParcel(Parcel in)1049         private static KeyphraseRecognitionExtra fromParcel(Parcel in) {
1050             int id = in.readInt();
1051             int recognitionModes = in.readInt();
1052             int coarseConfidenceLevel = in.readInt();
1053             ConfidenceLevel[] confidenceLevels = in.createTypedArray(ConfidenceLevel.CREATOR);
1054             return new KeyphraseRecognitionExtra(id, recognitionModes, coarseConfidenceLevel,
1055                     confidenceLevels);
1056         }
1057 
1058         @Override
writeToParcel(Parcel dest, int flags)1059         public void writeToParcel(Parcel dest, int flags) {
1060             dest.writeInt(id);
1061             dest.writeInt(recognitionModes);
1062             dest.writeInt(coarseConfidenceLevel);
1063             dest.writeTypedArray(confidenceLevels, flags);
1064         }
1065 
1066         @Override
describeContents()1067         public int describeContents() {
1068             return 0;
1069         }
1070 
1071         @Override
hashCode()1072         public int hashCode() {
1073             final int prime = 31;
1074             int result = 1;
1075             result = prime * result + Arrays.hashCode(confidenceLevels);
1076             result = prime * result + id;
1077             result = prime * result + recognitionModes;
1078             result = prime * result + coarseConfidenceLevel;
1079             return result;
1080         }
1081 
1082         @Override
equals(Object obj)1083         public boolean equals(Object obj) {
1084             if (this == obj)
1085                 return true;
1086             if (obj == null)
1087                 return false;
1088             if (getClass() != obj.getClass())
1089                 return false;
1090             KeyphraseRecognitionExtra other = (KeyphraseRecognitionExtra) obj;
1091             if (!Arrays.equals(confidenceLevels, other.confidenceLevels))
1092                 return false;
1093             if (id != other.id)
1094                 return false;
1095             if (recognitionModes != other.recognitionModes)
1096                 return false;
1097             if (coarseConfidenceLevel != other.coarseConfidenceLevel)
1098                 return false;
1099             return true;
1100         }
1101 
1102         @Override
toString()1103         public String toString() {
1104             return "KeyphraseRecognitionExtra [id=" + id + ", recognitionModes=" + recognitionModes
1105                     + ", coarseConfidenceLevel=" + coarseConfidenceLevel
1106                     + ", confidenceLevels=" + Arrays.toString(confidenceLevels) + "]";
1107         }
1108     }
1109 
1110     /**
1111      *  Specialized {@link RecognitionEvent} for a key phrase detection.
1112      *
1113      *  @hide
1114      */
1115     public static class KeyphraseRecognitionEvent extends RecognitionEvent implements Parcelable {
1116         /** Indicates if the key phrase is present in the buffered audio available for capture */
1117         public final KeyphraseRecognitionExtra[] keyphraseExtras;
1118 
KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, AudioFormat captureFormat, byte[] data, KeyphraseRecognitionExtra[] keyphraseExtras)1119         public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable,
1120                int captureSession, int captureDelayMs, int capturePreambleMs,
1121                boolean triggerInData, AudioFormat captureFormat, byte[] data,
1122                KeyphraseRecognitionExtra[] keyphraseExtras) {
1123             super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs,
1124                   capturePreambleMs, triggerInData, captureFormat, data);
1125             this.keyphraseExtras = keyphraseExtras;
1126         }
1127 
1128         public static final Parcelable.Creator<KeyphraseRecognitionEvent> CREATOR
1129                 = new Parcelable.Creator<KeyphraseRecognitionEvent>() {
1130             public KeyphraseRecognitionEvent createFromParcel(Parcel in) {
1131                 return KeyphraseRecognitionEvent.fromParcelForKeyphrase(in);
1132             }
1133 
1134             public KeyphraseRecognitionEvent[] newArray(int size) {
1135                 return new KeyphraseRecognitionEvent[size];
1136             }
1137         };
1138 
fromParcelForKeyphrase(Parcel in)1139         private static KeyphraseRecognitionEvent fromParcelForKeyphrase(Parcel in) {
1140             int status = in.readInt();
1141             int soundModelHandle = in.readInt();
1142             boolean captureAvailable = in.readByte() == 1;
1143             int captureSession = in.readInt();
1144             int captureDelayMs = in.readInt();
1145             int capturePreambleMs = in.readInt();
1146             boolean triggerInData = in.readByte() == 1;
1147             AudioFormat captureFormat = null;
1148             if (in.readByte() == 1) {
1149                 int sampleRate = in.readInt();
1150                 int encoding = in.readInt();
1151                 int channelMask = in.readInt();
1152                 captureFormat = (new AudioFormat.Builder())
1153                     .setChannelMask(channelMask)
1154                     .setEncoding(encoding)
1155                     .setSampleRate(sampleRate)
1156                     .build();
1157             }
1158             byte[] data = in.readBlob();
1159             KeyphraseRecognitionExtra[] keyphraseExtras =
1160                     in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
1161             return new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
1162                     captureSession, captureDelayMs, capturePreambleMs, triggerInData,
1163                     captureFormat, data, keyphraseExtras);
1164         }
1165 
1166         @Override
writeToParcel(Parcel dest, int flags)1167         public void writeToParcel(Parcel dest, int flags) {
1168             dest.writeInt(status);
1169             dest.writeInt(soundModelHandle);
1170             dest.writeByte((byte) (captureAvailable ? 1 : 0));
1171             dest.writeInt(captureSession);
1172             dest.writeInt(captureDelayMs);
1173             dest.writeInt(capturePreambleMs);
1174             dest.writeByte((byte) (triggerInData ? 1 : 0));
1175             if (captureFormat != null) {
1176                 dest.writeByte((byte)1);
1177                 dest.writeInt(captureFormat.getSampleRate());
1178                 dest.writeInt(captureFormat.getEncoding());
1179                 dest.writeInt(captureFormat.getChannelMask());
1180             } else {
1181                 dest.writeByte((byte)0);
1182             }
1183             dest.writeBlob(data);
1184             dest.writeTypedArray(keyphraseExtras, flags);
1185         }
1186 
1187         @Override
describeContents()1188         public int describeContents() {
1189             return 0;
1190         }
1191 
1192         @Override
hashCode()1193         public int hashCode() {
1194             final int prime = 31;
1195             int result = super.hashCode();
1196             result = prime * result + Arrays.hashCode(keyphraseExtras);
1197             return result;
1198         }
1199 
1200         @Override
equals(Object obj)1201         public boolean equals(Object obj) {
1202             if (this == obj)
1203                 return true;
1204             if (!super.equals(obj))
1205                 return false;
1206             if (getClass() != obj.getClass())
1207                 return false;
1208             KeyphraseRecognitionEvent other = (KeyphraseRecognitionEvent) obj;
1209             if (!Arrays.equals(keyphraseExtras, other.keyphraseExtras))
1210                 return false;
1211             return true;
1212         }
1213 
1214         @Override
toString()1215         public String toString() {
1216             return "KeyphraseRecognitionEvent [keyphraseExtras=" + Arrays.toString(keyphraseExtras)
1217                     + ", status=" + status
1218                     + ", soundModelHandle=" + soundModelHandle + ", captureAvailable="
1219                     + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs="
1220                     + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs
1221                     + ", triggerInData=" + triggerInData
1222                     + ((captureFormat == null) ? "" :
1223                         (", sampleRate=" + captureFormat.getSampleRate()))
1224                     + ((captureFormat == null) ? "" :
1225                         (", encoding=" + captureFormat.getEncoding()))
1226                     + ((captureFormat == null) ? "" :
1227                         (", channelMask=" + captureFormat.getChannelMask()))
1228                     + ", data=" + (data == null ? 0 : data.length) + "]";
1229         }
1230     }
1231 
1232     /**
1233      * Sub-class of RecognitionEvent specifically for sound-trigger based sound
1234      * models(non-keyphrase). Currently does not contain any additional fields.
1235      *
1236      * @hide
1237      */
1238     public static class GenericRecognitionEvent extends RecognitionEvent implements Parcelable {
GenericRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, AudioFormat captureFormat, byte[] data)1239         public GenericRecognitionEvent(int status, int soundModelHandle,
1240                 boolean captureAvailable, int captureSession, int captureDelayMs,
1241                 int capturePreambleMs, boolean triggerInData, AudioFormat captureFormat,
1242                 byte[] data) {
1243             super(status, soundModelHandle, captureAvailable, captureSession,
1244                     captureDelayMs, capturePreambleMs, triggerInData, captureFormat,
1245                     data);
1246         }
1247 
1248         public static final Parcelable.Creator<GenericRecognitionEvent> CREATOR
1249                 = new Parcelable.Creator<GenericRecognitionEvent>() {
1250             public GenericRecognitionEvent createFromParcel(Parcel in) {
1251                 return GenericRecognitionEvent.fromParcelForGeneric(in);
1252             }
1253 
1254             public GenericRecognitionEvent[] newArray(int size) {
1255                 return new GenericRecognitionEvent[size];
1256             }
1257         };
1258 
fromParcelForGeneric(Parcel in)1259         private static GenericRecognitionEvent fromParcelForGeneric(Parcel in) {
1260             RecognitionEvent event = RecognitionEvent.fromParcel(in);
1261             return new GenericRecognitionEvent(event.status, event.soundModelHandle,
1262                     event.captureAvailable, event.captureSession, event.captureDelayMs,
1263                     event.capturePreambleMs, event.triggerInData, event.captureFormat, event.data);
1264         }
1265 
1266         @Override
equals(Object obj)1267         public boolean equals(Object obj) {
1268             if (this == obj)
1269                 return true;
1270             if (obj == null)
1271                 return false;
1272             if (getClass() != obj.getClass()) return false;
1273             RecognitionEvent other = (RecognitionEvent) obj;
1274             return super.equals(obj);
1275         }
1276 
1277         @Override
toString()1278         public String toString() {
1279             return "GenericRecognitionEvent ::" + super.toString();
1280         }
1281     }
1282 
1283     /**
1284      *  Status codes for {@link SoundModelEvent}
1285      */
1286     /**
1287      * Sound Model was updated
1288      *
1289      * @hide
1290      */
1291     public static final int SOUNDMODEL_STATUS_UPDATED = 0;
1292 
1293     /**
1294      *  A SoundModelEvent is provided by the
1295      *  {@link StatusListener#onSoundModelUpdate(SoundModelEvent)}
1296      *  callback when a sound model has been updated by the implementation
1297      *
1298      *  @hide
1299      */
1300     public static class SoundModelEvent implements Parcelable {
1301         /** Status e.g {@link #SOUNDMODEL_STATUS_UPDATED} */
1302         public final int status;
1303         /** The updated sound model handle */
1304         public final int soundModelHandle;
1305         /** New sound model data */
1306         public final byte[] data;
1307 
SoundModelEvent(int status, int soundModelHandle, byte[] data)1308         SoundModelEvent(int status, int soundModelHandle, byte[] data) {
1309             this.status = status;
1310             this.soundModelHandle = soundModelHandle;
1311             this.data = data;
1312         }
1313 
1314         public static final Parcelable.Creator<SoundModelEvent> CREATOR
1315                 = new Parcelable.Creator<SoundModelEvent>() {
1316             public SoundModelEvent createFromParcel(Parcel in) {
1317                 return SoundModelEvent.fromParcel(in);
1318             }
1319 
1320             public SoundModelEvent[] newArray(int size) {
1321                 return new SoundModelEvent[size];
1322             }
1323         };
1324 
fromParcel(Parcel in)1325         private static SoundModelEvent fromParcel(Parcel in) {
1326             int status = in.readInt();
1327             int soundModelHandle = in.readInt();
1328             byte[] data = in.readBlob();
1329             return new SoundModelEvent(status, soundModelHandle, data);
1330         }
1331 
1332         @Override
describeContents()1333         public int describeContents() {
1334             return 0;
1335         }
1336 
1337         @Override
writeToParcel(Parcel dest, int flags)1338         public void writeToParcel(Parcel dest, int flags) {
1339             dest.writeInt(status);
1340             dest.writeInt(soundModelHandle);
1341             dest.writeBlob(data);
1342         }
1343 
1344         @Override
hashCode()1345         public int hashCode() {
1346             final int prime = 31;
1347             int result = 1;
1348             result = prime * result + Arrays.hashCode(data);
1349             result = prime * result + soundModelHandle;
1350             result = prime * result + status;
1351             return result;
1352         }
1353 
1354         @Override
equals(Object obj)1355         public boolean equals(Object obj) {
1356             if (this == obj)
1357                 return true;
1358             if (obj == null)
1359                 return false;
1360             if (getClass() != obj.getClass())
1361                 return false;
1362             SoundModelEvent other = (SoundModelEvent) obj;
1363             if (!Arrays.equals(data, other.data))
1364                 return false;
1365             if (soundModelHandle != other.soundModelHandle)
1366                 return false;
1367             if (status != other.status)
1368                 return false;
1369             return true;
1370         }
1371 
1372         @Override
toString()1373         public String toString() {
1374             return "SoundModelEvent [status=" + status + ", soundModelHandle=" + soundModelHandle
1375                     + ", data=" + (data == null ? 0 : data.length) + "]";
1376         }
1377     }
1378 
1379     /**
1380      *  Native service state. {@link StatusListener#onServiceStateChange(int)}
1381      */
1382     // Keep in sync with system/core/include/system/sound_trigger.h
1383     /**
1384      * Sound trigger service is enabled
1385      *
1386      * @hide
1387      */
1388     public static final int SERVICE_STATE_ENABLED = 0;
1389     /**
1390      * Sound trigger service is disabled
1391      *
1392      * @hide
1393      */
1394     public static final int SERVICE_STATE_DISABLED = 1;
1395 
1396     /**
1397      * Returns a list of descriptors for all hardware modules loaded.
1398      * @param modules A ModuleProperties array where the list will be returned.
1399      * @return - {@link #STATUS_OK} in case of success
1400      *         - {@link #STATUS_ERROR} in case of unspecified error
1401      *         - {@link #STATUS_PERMISSION_DENIED} if the caller does not have system permission
1402      *         - {@link #STATUS_NO_INIT} if the native service cannot be reached
1403      *         - {@link #STATUS_BAD_VALUE} if modules is null
1404      *         - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails
1405      *
1406      * @hide
1407      */
listModules(ArrayList <ModuleProperties> modules)1408     public static native int listModules(ArrayList <ModuleProperties> modules);
1409 
1410     /**
1411      * Get an interface on a hardware module to control sound models and recognition on
1412      * this module.
1413      * @param moduleId Sound module system identifier {@link ModuleProperties#id}. mandatory.
1414      * @param listener {@link StatusListener} interface. Mandatory.
1415      * @param handler the Handler that will receive the callabcks. Can be null if default handler
1416      *                is OK.
1417      * @return a valid sound module in case of success or null in case of error.
1418      *
1419      * @hide
1420      */
attachModule(int moduleId, StatusListener listener, Handler handler)1421     public static SoundTriggerModule attachModule(int moduleId,
1422                                                   StatusListener listener,
1423                                                   Handler handler) {
1424         if (listener == null) {
1425             return null;
1426         }
1427         SoundTriggerModule module = new SoundTriggerModule(moduleId, listener, handler);
1428         return module;
1429     }
1430 
1431     /**
1432      * Interface provided by the client application when attaching to a {@link SoundTriggerModule}
1433      * to received recognition and error notifications.
1434      *
1435      * @hide
1436      */
1437     public static interface StatusListener {
1438         /**
1439          * Called when recognition succeeds of fails
1440          */
onRecognition(RecognitionEvent event)1441         public abstract void onRecognition(RecognitionEvent event);
1442 
1443         /**
1444          * Called when a sound model has been updated
1445          */
onSoundModelUpdate(SoundModelEvent event)1446         public abstract void onSoundModelUpdate(SoundModelEvent event);
1447 
1448         /**
1449          * Called when the sound trigger native service state changes.
1450          * @param state Native service state. One of {@link SoundTrigger#SERVICE_STATE_ENABLED},
1451          * {@link SoundTrigger#SERVICE_STATE_DISABLED}
1452          */
onServiceStateChange(int state)1453         public abstract void onServiceStateChange(int state);
1454 
1455         /**
1456          * Called when the sound trigger native service dies
1457          */
onServiceDied()1458         public abstract void onServiceDied();
1459     }
1460 }
1461