Merge "add sound trigger JNI"
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index a1cd7f7..de46804 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -140,6 +140,7 @@
android_hardware_camera2_DngCreator.cpp \
android_hardware_SensorManager.cpp \
android_hardware_SerialPort.cpp \
+ android_hardware_SoundTrigger.cpp \
android_hardware_UsbDevice.cpp \
android_hardware_UsbDeviceConnection.cpp \
android_hardware_UsbRequest.cpp \
@@ -235,6 +236,7 @@
libpdfium \
libimg_utils \
libnetd_client \
+ libsoundtrigger
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 16727ab2..4f2028e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -82,6 +82,7 @@
extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
extern int register_android_hardware_SerialPort(JNIEnv *env);
+extern int register_android_hardware_SoundTrigger(JNIEnv *env);
extern int register_android_hardware_UsbDevice(JNIEnv *env);
extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
extern int register_android_hardware_UsbRequest(JNIEnv *env);
@@ -1282,6 +1283,7 @@
REG_JNI(register_android_hardware_camera2_DngCreator),
REG_JNI(register_android_hardware_SensorManager),
REG_JNI(register_android_hardware_SerialPort),
+ REG_JNI(register_android_hardware_SoundTrigger),
REG_JNI(register_android_hardware_UsbDevice),
REG_JNI(register_android_hardware_UsbDeviceConnection),
REG_JNI(register_android_hardware_UsbRequest),
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
new file mode 100644
index 0000000..69e991d
--- /dev/null
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -0,0 +1,661 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundTrigger-JNI"
+#include <utils/Log.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include <system/sound_trigger.h>
+#include <soundtrigger/SoundTriggerCallback.h>
+#include <soundtrigger/SoundTrigger.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
+
+using namespace android;
+
+static jclass gArrayListClass;
+static struct {
+ jmethodID add;
+} gArrayListMethods;
+
+static const char* const kSoundTriggerClassPathName = "android/hardware/soundtrigger/SoundTrigger";
+static jclass gSoundTriggerClass;
+
+static const char* const kModuleClassPathName = "android/hardware/soundtrigger/SoundTriggerModule";
+static jclass gModuleClass;
+static struct {
+ jfieldID mNativeContext;
+ jfieldID mId;
+} gModuleFields;
+static jmethodID gPostEventFromNative;
+
+static const char* const kModulePropertiesClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$ModuleProperties";
+static jclass gModulePropertiesClass;
+static jmethodID gModulePropertiesCstor;
+
+static const char* const kSoundModelClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$SoundModel";
+static jclass gSoundModelClass;
+static struct {
+ jfieldID data;
+} gSoundModelFields;
+
+static const char* const kKeyPhraseClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$KeyPhrase";
+static jclass gKeyPhraseClass;
+static struct {
+ jfieldID recognitionModes;
+ jfieldID locale;
+ jfieldID text;
+ jfieldID numUsers;
+} gKeyPhraseFields;
+
+static const char* const kKeyPhraseSoundModelClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$KeyPhraseSoundModel";
+static jclass gKeyPhraseSoundModelClass;
+static struct {
+ jfieldID keyPhrases;
+} gKeyPhraseSoundModelFields;
+
+
+static const char* const kRecognitionEventClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$RecognitionEvent";
+static jclass gRecognitionEventClass;
+static jmethodID gRecognitionEventCstor;
+
+static const char* const kKeyPhraseRecognitionEventClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$KeyPhraseRecognitionEvent";
+static jclass gKeyPhraseRecognitionEventClass;
+static jmethodID gKeyPhraseRecognitionEventCstor;
+
+static const char* const kKeyPhraseRecognitionExtraClassPathName =
+ "android/hardware/soundtrigger/SoundTrigger$KeyPhraseRecognitionExtra";
+static jclass gKeyPhraseRecognitionExtraClass;
+static jmethodID gKeyPhraseRecognitionExtraCstor;
+
+static Mutex gLock;
+
+enum {
+ SOUNDTRIGGER_STATUS_OK = 0,
+ SOUNDTRIGGER_STATUS_ERROR = INT_MIN,
+ SOUNDTRIGGER_PERMISSION_DENIED = -1,
+ SOUNDTRIGGER_STATUS_NO_INIT = -19,
+ SOUNDTRIGGER_STATUS_BAD_VALUE = -22,
+ SOUNDTRIGGER_STATUS_DEAD_OBJECT = -32,
+ SOUNDTRIGGER_INVALID_OPERATION = -38,
+};
+
+enum {
+ SOUNDTRIGGER_EVENT_RECOGNITION = 1,
+ SOUNDTRIGGER_EVENT_SERVICE_DIED = 2,
+};
+
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class JNISoundTriggerCallback: public SoundTriggerCallback
+{
+public:
+ JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
+ ~JNISoundTriggerCallback();
+
+ virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event);
+ virtual void onServiceDied();
+
+private:
+ jclass mClass; // Reference to SoundTrigger class
+ jobject mObject; // Weak ref to SoundTrigger Java object to call on
+};
+
+JNISoundTriggerCallback::JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
+{
+
+ // Hold onto the SoundTriggerModule class for use in calling the static method
+ // that posts events to the application thread.
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ ALOGE("Can't find class %s", kModuleClassPathName);
+ return;
+ }
+ mClass = (jclass)env->NewGlobalRef(clazz);
+
+ // We use a weak reference so the SoundTriggerModule object can be garbage collected.
+ // The reference is only used as a proxy for callbacks.
+ mObject = env->NewGlobalRef(weak_thiz);
+}
+
+JNISoundTriggerCallback::~JNISoundTriggerCallback()
+{
+ // remove global references
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mObject);
+ env->DeleteGlobalRef(mClass);
+}
+
+void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognition_event *event)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ jobject jEvent;
+
+ jbyteArray jData = NULL;
+ if (event->data_size) {
+ jData = env->NewByteArray(event->data_size);
+ jbyte *nData = env->GetByteArrayElements(jData, NULL);
+ memcpy(nData, (char *)event + event->data_offset, event->data_size);
+ env->ReleaseByteArrayElements(jData, nData, 0);
+ }
+
+ if (event->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ struct sound_trigger_phrase_recognition_event *phraseEvent =
+ (struct sound_trigger_phrase_recognition_event *)event;
+
+ jobjectArray jExtras = env->NewObjectArray(phraseEvent->num_phrases,
+ gKeyPhraseRecognitionExtraClass, NULL);
+ if (jExtras == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < phraseEvent->num_phrases; i++) {
+ jintArray jConfidenceLevels = env->NewIntArray(phraseEvent->phrase_extras[i].num_users);
+ if (jConfidenceLevels == NULL) {
+ return;
+ }
+ jint *nConfidenceLevels = env->GetIntArrayElements(jConfidenceLevels, NULL);
+ memcpy(nConfidenceLevels,
+ phraseEvent->phrase_extras[i].confidence_levels,
+ phraseEvent->phrase_extras[i].num_users * sizeof(int));
+ env->ReleaseIntArrayElements(jConfidenceLevels, nConfidenceLevels, 0);
+ jobject jNewExtra = env->NewObject(gKeyPhraseRecognitionExtraClass,
+ gKeyPhraseRecognitionExtraCstor,
+ jConfidenceLevels,
+ phraseEvent->phrase_extras[i].recognition_modes);
+
+ if (jNewExtra == NULL) {
+ return;
+ }
+ env->SetObjectArrayElement(jExtras, i, jNewExtra);
+
+ }
+ jEvent = env->NewObject(gKeyPhraseRecognitionEventClass, gKeyPhraseRecognitionEventCstor,
+ event->status, event->model, event->capture_available,
+ event->capture_session, event->capture_delay_ms, jData,
+ phraseEvent->key_phrase_in_capture, jExtras);
+ } else {
+ jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor,
+ event->status, event->model, event->capture_available,
+ event->capture_session, event->capture_delay_ms, jData);
+ }
+
+
+ env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
+ SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent);
+ if (env->ExceptionCheck()) {
+ ALOGW("An exception occurred while notifying an event.");
+ env->ExceptionClear();
+ }
+}
+
+void JNISoundTriggerCallback::onServiceDied()
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
+ SOUNDTRIGGER_EVENT_SERVICE_DIED, 0, 0, NULL);
+ if (env->ExceptionCheck()) {
+ ALOGW("An exception occurred while notifying an event.");
+ env->ExceptionClear();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static sp<SoundTrigger> getSoundTrigger(JNIEnv* env, jobject thiz)
+{
+ Mutex::Autolock l(gLock);
+ SoundTrigger* const st = (SoundTrigger*)env->GetLongField(thiz,
+ gModuleFields.mNativeContext);
+ return sp<SoundTrigger>(st);
+}
+
+static sp<SoundTrigger> setSoundTrigger(JNIEnv* env, jobject thiz, const sp<SoundTrigger>& module)
+{
+ Mutex::Autolock l(gLock);
+ sp<SoundTrigger> old = (SoundTrigger*)env->GetLongField(thiz,
+ gModuleFields.mNativeContext);
+ if (module.get()) {
+ module->incStrong((void*)setSoundTrigger);
+ }
+ if (old != 0) {
+ old->decStrong((void*)setSoundTrigger);
+ }
+ env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get());
+ return old;
+}
+
+
+static jint
+android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz,
+ jobject jModules)
+{
+ ALOGV("listModules");
+
+ if (jModules == NULL) {
+ ALOGE("listModules NULL AudioPatch ArrayList");
+ return SOUNDTRIGGER_STATUS_BAD_VALUE;
+ }
+ if (!env->IsInstanceOf(jModules, gArrayListClass)) {
+ ALOGE("listModules not an arraylist");
+ return SOUNDTRIGGER_STATUS_BAD_VALUE;
+ }
+
+ unsigned int numModules = 0;
+ struct sound_trigger_module_descriptor *nModules = NULL;
+
+ status_t status = SoundTrigger::listModules(nModules, &numModules);
+ if (status != NO_ERROR || numModules == 0) {
+ return (jint)status;
+ }
+
+ nModules = (struct sound_trigger_module_descriptor *)
+ calloc(numModules, sizeof(struct sound_trigger_module_descriptor));
+
+ status = SoundTrigger::listModules(nModules, &numModules);
+ ALOGV("listModules SoundTrigger::listModules status %d numModules %d", status, numModules);
+
+ if (status != NO_ERROR) {
+ numModules = 0;
+ }
+
+ for (size_t i = 0; i < numModules; i++) {
+ char str[SOUND_TRIGGER_MAX_STRING_LEN];
+
+ jstring implementor = env->NewStringUTF(nModules[i].properties.implementor);
+ jstring description = env->NewStringUTF(nModules[i].properties.description);
+ SoundTrigger::guidToString(&nModules[i].properties.uuid,
+ str,
+ SOUND_TRIGGER_MAX_STRING_LEN);
+ jstring uuid = env->NewStringUTF(str);
+
+ ALOGV("listModules module %d id %d description %s maxSoundModels %d",
+ i, nModules[i].handle, nModules[i].properties.description,
+ nModules[i].properties.max_sound_models);
+
+ jobject newModuleDesc = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
+ nModules[i].handle,
+ implementor, description, uuid,
+ nModules[i].properties.version,
+ nModules[i].properties.max_sound_models,
+ nModules[i].properties.max_key_phrases,
+ nModules[i].properties.max_users,
+ nModules[i].properties.recognition_modes,
+ nModules[i].properties.capture_transition,
+ nModules[i].properties.max_buffer_ms,
+ nModules[i].properties.concurrent_capture,
+ nModules[i].properties.power_consumption_mw);
+
+ env->DeleteLocalRef(implementor);
+ env->DeleteLocalRef(description);
+ env->DeleteLocalRef(uuid);
+ if (newModuleDesc == NULL) {
+ status = SOUNDTRIGGER_STATUS_ERROR;
+ goto exit;
+ }
+ env->CallBooleanMethod(jModules, gArrayListMethods.add, newModuleDesc);
+ }
+
+exit:
+ free(nModules);
+ return (jint) status;
+}
+
+static void
+android_hardware_SoundTrigger_setup(JNIEnv *env, jobject thiz, jobject weak_this)
+{
+ ALOGV("setup");
+
+ sp<JNISoundTriggerCallback> callback = new JNISoundTriggerCallback(env, thiz, weak_this);
+
+ sound_trigger_module_handle_t handle =
+ (sound_trigger_module_handle_t)env->GetIntField(thiz, gModuleFields.mId);
+
+ sp<SoundTrigger> module = SoundTrigger::attach(handle, callback);
+ if (module == 0) {
+ return;
+ }
+
+ setSoundTrigger(env, thiz, module);
+}
+
+static void
+android_hardware_SoundTrigger_detach(JNIEnv *env, jobject thiz)
+{
+ ALOGV("detach");
+ sp<SoundTrigger> module = setSoundTrigger(env, thiz, 0);
+ ALOGV("detach module %p", module.get());
+ if (module != 0) {
+ ALOGV("detach module->detach()");
+ module->detach();
+ }
+}
+
+static void
+android_hardware_SoundTrigger_finalize(JNIEnv *env, jobject thiz)
+{
+ ALOGV("finalize");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module != 0) {
+ ALOGW("SoundTrigger finalized without being detached");
+ }
+ android_hardware_SoundTrigger_detach(env, thiz);
+}
+
+static jint
+android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz,
+ jobject jSoundModel, jintArray jHandle)
+{
+ jint status = SOUNDTRIGGER_STATUS_OK;
+ char *nData = NULL;
+ struct sound_trigger_sound_model *nSoundModel;
+ jbyteArray jData;
+ sp<MemoryDealer> memoryDealer;
+ sp<IMemory> memory;
+ size_t size;
+ sound_model_handle_t handle;
+
+ ALOGV("loadSoundModel");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == NULL) {
+ return SOUNDTRIGGER_STATUS_ERROR;
+ }
+ if (jHandle == NULL) {
+ return SOUNDTRIGGER_STATUS_BAD_VALUE;
+ }
+ jsize jHandleLen = env->GetArrayLength(jHandle);
+ if (jHandleLen == 0) {
+ return SOUNDTRIGGER_STATUS_BAD_VALUE;
+ }
+ jint *nHandle = env->GetIntArrayElements(jHandle, NULL);
+ if (nHandle == NULL) {
+ return SOUNDTRIGGER_STATUS_ERROR;
+ }
+ if (!env->IsInstanceOf(jSoundModel, gSoundModelClass)) {
+ status = SOUNDTRIGGER_STATUS_BAD_VALUE;
+ goto exit;
+ }
+ size_t offset;
+ sound_trigger_sound_model_type_t type;
+ if (env->IsInstanceOf(jSoundModel, gKeyPhraseSoundModelClass)) {
+ offset = sizeof(struct sound_trigger_phrase_sound_model);
+ type = SOUND_MODEL_TYPE_KEYPHRASE;
+ } else {
+ offset = sizeof(struct sound_trigger_sound_model);
+ type = SOUND_MODEL_TYPE_UNKNOWN;
+ }
+ jData = (jbyteArray)env->GetObjectField(jSoundModel, gSoundModelFields.data);
+ if (jData == NULL) {
+ status = SOUNDTRIGGER_STATUS_BAD_VALUE;
+ goto exit;
+ }
+ size = env->GetArrayLength(jData);
+
+ nData = (char *)env->GetByteArrayElements(jData, NULL);
+ if (jData == NULL) {
+ status = SOUNDTRIGGER_STATUS_ERROR;
+ goto exit;
+ }
+
+ memoryDealer = new MemoryDealer(offset + size, "SoundTrigge-JNI::LoadModel");
+ if (memoryDealer == 0) {
+ status = SOUNDTRIGGER_STATUS_ERROR;
+ goto exit;
+ }
+ memory = memoryDealer->allocate(offset + size);
+ if (memory == 0 || memory->pointer() == NULL) {
+ status = SOUNDTRIGGER_STATUS_ERROR;
+ goto exit;
+ }
+
+ nSoundModel = (struct sound_trigger_sound_model *)memory->pointer();
+
+ nSoundModel->type = type;
+ nSoundModel->data_size = size;
+ nSoundModel->data_offset = offset;
+ memcpy((char *)nSoundModel + offset, nData, size);
+ if (type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ struct sound_trigger_phrase_sound_model *phraseModel =
+ (struct sound_trigger_phrase_sound_model *)nSoundModel;
+
+ jobjectArray jPhrases =
+ (jobjectArray)env->GetObjectField(jSoundModel, gKeyPhraseSoundModelFields.keyPhrases);
+ if (jPhrases == NULL) {
+ status = SOUNDTRIGGER_STATUS_BAD_VALUE;
+ goto exit;
+ }
+
+ size_t numPhrases = env->GetArrayLength(jPhrases);
+ phraseModel->num_phrases = numPhrases;
+ ALOGV("loadSoundModel numPhrases %d", numPhrases);
+ for (size_t i = 0; i < numPhrases; i++) {
+ jobject jPhrase = env->GetObjectArrayElement(jPhrases, i);
+ phraseModel->phrases[i].recognition_mode =
+ env->GetIntField(jPhrase,gKeyPhraseFields.recognitionModes);
+ phraseModel->phrases[i].num_users =
+ env->GetIntField(jPhrase, gKeyPhraseFields.numUsers);
+ jstring jLocale = (jstring)env->GetObjectField(jPhrase, gKeyPhraseFields.locale);
+ const char *nLocale = env->GetStringUTFChars(jLocale, NULL);
+ strncpy(phraseModel->phrases[i].locale,
+ nLocale,
+ SOUND_TRIGGER_MAX_LOCALE_LEN);
+ jstring jText = (jstring)env->GetObjectField(jPhrase, gKeyPhraseFields.text);
+ const char *nText = env->GetStringUTFChars(jText, NULL);
+ strncpy(phraseModel->phrases[i].text,
+ nText,
+ SOUND_TRIGGER_MAX_STRING_LEN);
+
+ env->ReleaseStringUTFChars(jLocale, nLocale);
+ env->DeleteLocalRef(jLocale);
+ env->ReleaseStringUTFChars(jText, nText);
+ env->DeleteLocalRef(jText);
+ ALOGV("loadSoundModel phrases %d text %s locale %s",
+ i, phraseModel->phrases[i].text, phraseModel->phrases[i].locale);
+ }
+ env->DeleteLocalRef(jPhrases);
+ }
+ status = module->loadSoundModel(memory, &handle);
+ ALOGV("loadSoundModel status %d handle %d", status, handle);
+
+exit:
+ if (nHandle != NULL) {
+ nHandle[0] = (jint)handle;
+ env->ReleaseIntArrayElements(jHandle, nHandle, NULL);
+ }
+ if (nData != NULL) {
+ env->ReleaseByteArrayElements(jData, (jbyte *)nData, NULL);
+ }
+ return status;
+}
+
+static jint
+android_hardware_SoundTrigger_unloadSoundModel(JNIEnv *env, jobject thiz,
+ jint jHandle)
+{
+ jint status = SOUNDTRIGGER_STATUS_OK;
+ ALOGV("unloadSoundModel");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == NULL) {
+ return SOUNDTRIGGER_STATUS_ERROR;
+ }
+ status = module->unloadSoundModel((sound_model_handle_t)jHandle);
+
+ return status;
+}
+
+static jint
+android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz,
+ jint jHandle, jbyteArray jData)
+{
+ jint status = SOUNDTRIGGER_STATUS_OK;
+ ALOGV("startRecognition");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == NULL) {
+ return SOUNDTRIGGER_STATUS_ERROR;
+ }
+ jsize dataSize = 0;
+ char *nData = NULL;
+ sp<IMemory> memory;
+ if (jData != NULL) {
+ dataSize = env->GetArrayLength(jData);
+ if (dataSize == 0) {
+ return SOUNDTRIGGER_STATUS_BAD_VALUE;
+ }
+ nData = (char *)env->GetByteArrayElements(jData, NULL);
+ if (nData == NULL) {
+ return SOUNDTRIGGER_STATUS_ERROR;
+ }
+ sp<MemoryDealer> memoryDealer =
+ new MemoryDealer(dataSize, "SoundTrigge-JNI::StartRecognition");
+ if (memoryDealer == 0) {
+ return SOUNDTRIGGER_STATUS_ERROR;
+ }
+ memory = memoryDealer->allocate(dataSize);
+ if (memory == 0 || memory->pointer() == NULL) {
+ return SOUNDTRIGGER_STATUS_ERROR;
+ }
+ memcpy(memory->pointer(), nData, dataSize);
+ }
+
+ status = module->startRecognition(jHandle, memory);
+ return status;
+}
+
+static jint
+android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz,
+ jint jHandle)
+{
+ jint status = SOUNDTRIGGER_STATUS_OK;
+ ALOGV("stopRecognition");
+ sp<SoundTrigger> module = getSoundTrigger(env, thiz);
+ if (module == NULL) {
+ return SOUNDTRIGGER_STATUS_ERROR;
+ }
+ status = module->stopRecognition(jHandle);
+ return status;
+}
+
+static JNINativeMethod gMethods[] = {
+ {"listModules",
+ "(Ljava/util/ArrayList;)I",
+ (void *)android_hardware_SoundTrigger_listModules},
+};
+
+
+static JNINativeMethod gModuleMethods[] = {
+ {"native_setup",
+ "(Ljava/lang/Object;)V",
+ (void *)android_hardware_SoundTrigger_setup},
+ {"native_finalize",
+ "()V",
+ (void *)android_hardware_SoundTrigger_finalize},
+ {"detach",
+ "()V",
+ (void *)android_hardware_SoundTrigger_detach},
+ {"loadSoundModel",
+ "(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;[I)I",
+ (void *)android_hardware_SoundTrigger_loadSoundModel},
+ {"unloadSoundModel",
+ "(I)I",
+ (void *)android_hardware_SoundTrigger_unloadSoundModel},
+ {"startRecognition",
+ "(I[B)I",
+ (void *)android_hardware_SoundTrigger_startRecognition},
+ {"stopRecognition",
+ "(I)I",
+ (void *)android_hardware_SoundTrigger_stopRecognition},
+};
+
+int register_android_hardware_SoundTrigger(JNIEnv *env)
+{
+ jclass arrayListClass = env->FindClass("java/util/ArrayList");
+ gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
+ gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
+
+ jclass lClass = env->FindClass(kSoundTriggerClassPathName);
+ gSoundTriggerClass = (jclass) env->NewGlobalRef(lClass);
+
+ jclass moduleClass = env->FindClass(kModuleClassPathName);
+ gModuleClass = (jclass) env->NewGlobalRef(moduleClass);
+ gPostEventFromNative = env->GetStaticMethodID(moduleClass, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ gModuleFields.mNativeContext = env->GetFieldID(moduleClass, "mNativeContext", "J");
+ gModuleFields.mId = env->GetFieldID(moduleClass, "mId", "I");
+
+
+ jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName);
+ gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass);
+ gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZI)V");
+
+ jclass soundModelClass = env->FindClass(kSoundModelClassPathName);
+ gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass);
+ gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B");
+
+ jclass keyPhraseClass = env->FindClass(kKeyPhraseClassPathName);
+ gKeyPhraseClass = (jclass) env->NewGlobalRef(keyPhraseClass);
+ gKeyPhraseFields.recognitionModes = env->GetFieldID(keyPhraseClass, "recognitionModes", "I");
+ gKeyPhraseFields.locale = env->GetFieldID(keyPhraseClass, "locale", "Ljava/lang/String;");
+ gKeyPhraseFields.text = env->GetFieldID(keyPhraseClass, "text", "Ljava/lang/String;");
+ gKeyPhraseFields.numUsers = env->GetFieldID(keyPhraseClass, "numUsers", "I");
+
+ jclass keyPhraseSoundModelClass = env->FindClass(kKeyPhraseSoundModelClassPathName);
+ gKeyPhraseSoundModelClass = (jclass) env->NewGlobalRef(keyPhraseSoundModelClass);
+ gKeyPhraseSoundModelFields.keyPhrases = env->GetFieldID(keyPhraseSoundModelClass,
+ "keyPhrases",
+ "[Landroid/hardware/soundtrigger/SoundTrigger$KeyPhrase;");
+
+
+ jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName);
+ gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass);
+ gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>",
+ "(IIZII[B)V");
+
+ jclass keyPhraseRecognitionEventClass = env->FindClass(kKeyPhraseRecognitionEventClassPathName);
+ gKeyPhraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyPhraseRecognitionEventClass);
+ gKeyPhraseRecognitionEventCstor = env->GetMethodID(keyPhraseRecognitionEventClass, "<init>",
+ "(IIZII[BZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyPhraseRecognitionExtra;)V");
+
+
+ jclass keyPhraseRecognitionExtraClass = env->FindClass(kKeyPhraseRecognitionExtraClassPathName);
+ gKeyPhraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyPhraseRecognitionExtraClass);
+ gKeyPhraseRecognitionExtraCstor = env->GetMethodID(keyPhraseRecognitionExtraClass, "<init>",
+ "([II)V");
+
+ int status = AndroidRuntime::registerNativeMethods(env,
+ kSoundTriggerClassPathName, gMethods, NELEM(gMethods));
+
+ if (status == 0) {
+ status = AndroidRuntime::registerNativeMethods(env,
+ kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods));
+ }
+
+ return status;
+}