Home | History | Annotate | Download | only in soundtrigger
      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 
     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 
    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 
    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
    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
    189         public int describeContents() {
    190             return 0;
    191         }
    192 
    193         @Override
    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 
    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
    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
    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 
    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 
    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
    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
    355         public int describeContents() {
    356             return 0;
    357         }
    358 
    359         @Override
    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
    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
    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 
    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 
    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
    447         public int describeContents() {
    448             return 0;
    449         }
    450 
    451         @Override
    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
    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
    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
    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 
    514         public GenericSoundModel(UUID uuid, UUID vendorUuid, byte[] data) {
    515             super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data);
    516         }
    517 
    518         @Override
    519         public int describeContents() {
    520             return 0;
    521         }
    522 
    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
    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
    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 */
    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          */
    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          */
    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          */
    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          */
    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 */
    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 */
    756         public int describeContents() {
    757             return 0;
    758         }
    759 
    760         /** @hide */
    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
    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
    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
    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 
    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 
    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
    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
    918         public int describeContents() {
    919             return 0;
    920         }
    921 
    922         @Override
    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 
    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 
    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
    967         public void writeToParcel(Parcel dest, int flags) {
    968             dest.writeInt(userId);
    969             dest.writeInt(confidenceLevel);
    970         }
    971 
    972         @Override
    973         public int describeContents() {
    974             return 0;
    975         }
    976 
    977         @Override
    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
    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
   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 
   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 
   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
   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
   1067         public int describeContents() {
   1068             return 0;
   1069         }
   1070 
   1071         @Override
   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
   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
   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 
   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 
   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
   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
   1188         public int describeContents() {
   1189             return 0;
   1190         }
   1191 
   1192         @Override
   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
   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
   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 {
   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 
   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
   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
   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 
   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 
   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
   1333         public int describeContents() {
   1334             return 0;
   1335         }
   1336 
   1337         @Override
   1338         public void writeToParcel(Parcel dest, int flags) {
   1339             dest.writeInt(status);
   1340             dest.writeInt(soundModelHandle);
   1341             dest.writeBlob(data);
   1342         }
   1343 
   1344         @Override
   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
   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
   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      */
   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      */
   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          */
   1441         public abstract void onRecognition(RecognitionEvent event);
   1442 
   1443         /**
   1444          * Called when a sound model has been updated
   1445          */
   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          */
   1453         public abstract void onServiceStateChange(int state);
   1454 
   1455         /**
   1456          * Called when the sound trigger native service dies
   1457          */
   1458         public abstract void onServiceDied();
   1459     }
   1460 }
   1461