Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2008, 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 #define LOG_TAG "SensorManager"
     17 
     18 #include <nativehelper/JNIHelp.h>
     19 #include "android_os_MessageQueue.h"
     20 #include "core_jni_helpers.h"
     21 #include "jni.h"
     22 
     23 #include <nativehelper/ScopedUtfChars.h>
     24 #include <nativehelper/ScopedLocalRef.h>
     25 #include <android_runtime/AndroidRuntime.h>
     26 #include <android_runtime/android_hardware_HardwareBuffer.h>
     27 #include <vndk/hardware_buffer.h>
     28 #include <sensor/Sensor.h>
     29 #include <sensor/SensorEventQueue.h>
     30 #include <sensor/SensorManager.h>
     31 #include <cutils/native_handle.h>
     32 #include <utils/Log.h>
     33 #include <utils/Looper.h>
     34 #include <utils/Vector.h>
     35 
     36 #include <map>
     37 
     38 namespace {
     39 
     40 using namespace android;
     41 
     42 struct {
     43     jclass clazz;
     44     jmethodID dispatchSensorEvent;
     45     jmethodID dispatchFlushCompleteEvent;
     46     jmethodID dispatchAdditionalInfoEvent;
     47 } gBaseEventQueueClassInfo;
     48 
     49 struct SensorOffsets
     50 {
     51     jclass      clazz;
     52     //fields
     53     jfieldID    name;
     54     jfieldID    vendor;
     55     jfieldID    version;
     56     jfieldID    handle;
     57     jfieldID    range;
     58     jfieldID    resolution;
     59     jfieldID    power;
     60     jfieldID    minDelay;
     61     jfieldID    fifoReservedEventCount;
     62     jfieldID    fifoMaxEventCount;
     63     jfieldID    stringType;
     64     jfieldID    requiredPermission;
     65     jfieldID    maxDelay;
     66     jfieldID    flags;
     67     //methods
     68     jmethodID   setType;
     69     jmethodID   setUuid;
     70     jmethodID   init;
     71 } gSensorOffsets;
     72 
     73 struct ListOffsets {
     74     jclass      clazz;
     75     jmethodID   add;
     76 } gListOffsets;
     77 
     78 struct StringOffsets {
     79     jclass      clazz;
     80     jmethodID   intern;
     81     jstring     emptyString;
     82 } gStringOffsets;
     83 
     84 /*
     85  * nativeClassInit is not inteneded to be thread-safe. It should be called before other native...
     86  * functions (except nativeCreate).
     87  */
     88 static void
     89 nativeClassInit (JNIEnv *_env, jclass _this)
     90 {
     91     //android.hardware.Sensor
     92     SensorOffsets& sensorOffsets = gSensorOffsets;
     93     jclass sensorClass = (jclass)
     94             MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "android/hardware/Sensor"));
     95     sensorOffsets.clazz = sensorClass;
     96     sensorOffsets.name = GetFieldIDOrDie(_env, sensorClass, "mName", "Ljava/lang/String;");
     97     sensorOffsets.vendor = GetFieldIDOrDie(_env, sensorClass, "mVendor", "Ljava/lang/String;");
     98     sensorOffsets.version = GetFieldIDOrDie(_env, sensorClass, "mVersion", "I");
     99     sensorOffsets.handle = GetFieldIDOrDie(_env, sensorClass, "mHandle", "I");
    100     sensorOffsets.range = GetFieldIDOrDie(_env, sensorClass, "mMaxRange", "F");
    101     sensorOffsets.resolution = GetFieldIDOrDie(_env, sensorClass, "mResolution","F");
    102     sensorOffsets.power = GetFieldIDOrDie(_env, sensorClass, "mPower", "F");
    103     sensorOffsets.minDelay = GetFieldIDOrDie(_env, sensorClass, "mMinDelay", "I");
    104     sensorOffsets.fifoReservedEventCount =
    105             GetFieldIDOrDie(_env,sensorClass, "mFifoReservedEventCount", "I");
    106     sensorOffsets.fifoMaxEventCount = GetFieldIDOrDie(_env,sensorClass, "mFifoMaxEventCount", "I");
    107     sensorOffsets.stringType =
    108             GetFieldIDOrDie(_env,sensorClass, "mStringType", "Ljava/lang/String;");
    109     sensorOffsets.requiredPermission =
    110             GetFieldIDOrDie(_env,sensorClass, "mRequiredPermission", "Ljava/lang/String;");
    111     sensorOffsets.maxDelay = GetFieldIDOrDie(_env,sensorClass, "mMaxDelay", "I");
    112     sensorOffsets.flags = GetFieldIDOrDie(_env,sensorClass, "mFlags", "I");
    113 
    114     sensorOffsets.setType = GetMethodIDOrDie(_env,sensorClass, "setType", "(I)Z");
    115     sensorOffsets.setUuid = GetMethodIDOrDie(_env,sensorClass, "setUuid", "(JJ)V");
    116     sensorOffsets.init = GetMethodIDOrDie(_env,sensorClass, "<init>", "()V");
    117 
    118     // java.util.List;
    119     ListOffsets& listOffsets = gListOffsets;
    120     jclass listClass = (jclass) MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "java/util/List"));
    121     listOffsets.clazz = listClass;
    122     listOffsets.add = GetMethodIDOrDie(_env,listClass, "add", "(Ljava/lang/Object;)Z");
    123 
    124     // initialize java.lang.String and empty string intern
    125     StringOffsets& stringOffsets = gStringOffsets;
    126     stringOffsets.clazz = MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "java/lang/String"));
    127     stringOffsets.intern =
    128             GetMethodIDOrDie(_env, stringOffsets.clazz, "intern", "()Ljava/lang/String;");
    129     ScopedLocalRef<jstring> empty(_env, _env->NewStringUTF(""));
    130     stringOffsets.emptyString = (jstring)
    131             MakeGlobalRefOrDie(_env, _env->CallObjectMethod(empty.get(), stringOffsets.intern));
    132 }
    133 
    134 static jstring getJavaInternedString(JNIEnv *env, const String8 &string) {
    135     if (string == "") {
    136         return gStringOffsets.emptyString;
    137     }
    138 
    139     ScopedLocalRef<jstring> javaString(env, env->NewStringUTF(string.string()));
    140     jstring internedString = (jstring)
    141             env->CallObjectMethod(javaString.get(), gStringOffsets.intern);
    142     return internedString;
    143 }
    144 
    145 static jlong
    146 nativeCreate
    147 (JNIEnv *env, jclass clazz, jstring opPackageName)
    148 {
    149     ScopedUtfChars opPackageNameUtf(env, opPackageName);
    150     return (jlong) &SensorManager::getInstanceForPackage(String16(opPackageNameUtf.c_str()));
    151 }
    152 
    153 static jobject
    154 translateNativeSensorToJavaSensor(JNIEnv *env, jobject sensor, const Sensor& nativeSensor) {
    155     const SensorOffsets& sensorOffsets(gSensorOffsets);
    156 
    157     if (sensor == NULL) {
    158         // Sensor sensor = new Sensor();
    159         sensor = env->NewObject(sensorOffsets.clazz, sensorOffsets.init, "");
    160     }
    161 
    162     if (sensor != NULL) {
    163         jstring name = getJavaInternedString(env, nativeSensor.getName());
    164         jstring vendor = getJavaInternedString(env, nativeSensor.getVendor());
    165         jstring requiredPermission =
    166                 getJavaInternedString(env, nativeSensor.getRequiredPermission());
    167 
    168         env->SetObjectField(sensor, sensorOffsets.name,      name);
    169         env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
    170         env->SetIntField(sensor, sensorOffsets.version,      nativeSensor.getVersion());
    171         env->SetIntField(sensor, sensorOffsets.handle,       nativeSensor.getHandle());
    172         env->SetFloatField(sensor, sensorOffsets.range,      nativeSensor.getMaxValue());
    173         env->SetFloatField(sensor, sensorOffsets.resolution, nativeSensor.getResolution());
    174         env->SetFloatField(sensor, sensorOffsets.power,      nativeSensor.getPowerUsage());
    175         env->SetIntField(sensor, sensorOffsets.minDelay,     nativeSensor.getMinDelay());
    176         env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
    177                          nativeSensor.getFifoReservedEventCount());
    178         env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
    179                          nativeSensor.getFifoMaxEventCount());
    180         env->SetObjectField(sensor, sensorOffsets.requiredPermission,
    181                             requiredPermission);
    182         env->SetIntField(sensor, sensorOffsets.maxDelay, nativeSensor.getMaxDelay());
    183         env->SetIntField(sensor, sensorOffsets.flags, nativeSensor.getFlags());
    184 
    185         if (env->CallBooleanMethod(sensor, sensorOffsets.setType, nativeSensor.getType())
    186                 == JNI_FALSE) {
    187             jstring stringType = getJavaInternedString(env, nativeSensor.getStringType());
    188             env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
    189         }
    190 
    191         // TODO(b/29547335): Rename "setUuid" method to "setId".
    192         int64_t id = nativeSensor.getId();
    193         env->CallVoidMethod(sensor, sensorOffsets.setUuid, id, 0);
    194     }
    195     return sensor;
    196 }
    197 
    198 static jboolean
    199 nativeGetSensorAtIndex(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensor, jint index)
    200 {
    201     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
    202 
    203     Sensor const* const* sensorList;
    204     ssize_t count = mgr->getSensorList(&sensorList);
    205     if (ssize_t(index) >= count) {
    206         return false;
    207     }
    208 
    209     return translateNativeSensorToJavaSensor(env, sensor, *sensorList[index]) != NULL;
    210 }
    211 
    212 static void
    213 nativeGetDynamicSensors(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensorList) {
    214 
    215     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
    216     const ListOffsets& listOffsets(gListOffsets);
    217 
    218     Vector<Sensor> nativeList;
    219 
    220     mgr->getDynamicSensorList(nativeList);
    221 
    222     ALOGI("DYNS native SensorManager.getDynamicSensorList return %zu sensors", nativeList.size());
    223     for (size_t i = 0; i < nativeList.size(); ++i) {
    224         jobject sensor = translateNativeSensorToJavaSensor(env, NULL, nativeList[i]);
    225         // add to list
    226         env->CallBooleanMethod(sensorList, listOffsets.add, sensor);
    227     }
    228 }
    229 
    230 static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
    231     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
    232     return mgr->isDataInjectionEnabled();
    233 }
    234 
    235 static jint nativeCreateDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
    236         jlong size, jint channelType, jint fd, jobject hardwareBufferObj) {
    237     const native_handle_t *nativeHandle = nullptr;
    238     NATIVE_HANDLE_DECLARE_STORAGE(ashmemHandle, 1, 0);
    239 
    240     if (channelType == SENSOR_DIRECT_MEM_TYPE_ASHMEM) {
    241         native_handle_t *handle = native_handle_init(ashmemHandle, 1, 0);
    242         handle->data[0] = fd;
    243         nativeHandle = handle;
    244     } else if (channelType == SENSOR_DIRECT_MEM_TYPE_GRALLOC) {
    245         AHardwareBuffer *hardwareBuffer =
    246                 android_hardware_HardwareBuffer_getNativeHardwareBuffer(_env, hardwareBufferObj);
    247         if (hardwareBuffer != nullptr) {
    248             nativeHandle = AHardwareBuffer_getNativeHandle(hardwareBuffer);
    249         }
    250     }
    251 
    252     if (nativeHandle == nullptr) {
    253         return BAD_VALUE;
    254     }
    255 
    256     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
    257     return mgr->createDirectChannel(size, channelType, nativeHandle);
    258 }
    259 
    260 static void nativeDestroyDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
    261         jint channelHandle) {
    262     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
    263     mgr->destroyDirectChannel(channelHandle);
    264 }
    265 
    266 static jint nativeConfigDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
    267         jint channelHandle, jint sensorHandle, jint rate) {
    268     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
    269     return mgr->configureDirectChannel(channelHandle, sensorHandle, rate);
    270 }
    271 
    272 static jint nativeSetOperationParameter(JNIEnv *_env, jclass _this, jlong sensorManager,
    273         jint handle, jint type, jfloatArray floats, jintArray ints) {
    274     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
    275     Vector<float> floatVector;
    276     Vector<int32_t> int32Vector;
    277 
    278     if (floats != nullptr) {
    279         floatVector.resize(_env->GetArrayLength(floats));
    280         _env->GetFloatArrayRegion(floats, 0, _env->GetArrayLength(floats), floatVector.editArray());
    281     }
    282 
    283     if (ints != nullptr) {
    284         int32Vector.resize(_env->GetArrayLength(ints));
    285         _env->GetIntArrayRegion(ints, 0, _env->GetArrayLength(ints), int32Vector.editArray());
    286     }
    287 
    288     return mgr->setOperationParameter(handle, type, floatVector, int32Vector);
    289 }
    290 
    291 //----------------------------------------------------------------------------
    292 
    293 class Receiver : public LooperCallback {
    294     sp<SensorEventQueue> mSensorQueue;
    295     sp<MessageQueue> mMessageQueue;
    296     jobject mReceiverWeakGlobal;
    297     jfloatArray mFloatScratch;
    298     jintArray   mIntScratch;
    299 public:
    300     Receiver(const sp<SensorEventQueue>& sensorQueue,
    301             const sp<MessageQueue>& messageQueue,
    302             jobject receiverWeak) {
    303         JNIEnv* env = AndroidRuntime::getJNIEnv();
    304         mSensorQueue = sensorQueue;
    305         mMessageQueue = messageQueue;
    306         mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);
    307 
    308         mIntScratch = (jintArray) env->NewGlobalRef(env->NewIntArray(16));
    309         mFloatScratch = (jfloatArray) env->NewGlobalRef(env->NewFloatArray(16));
    310     }
    311     ~Receiver() {
    312         JNIEnv* env = AndroidRuntime::getJNIEnv();
    313         env->DeleteGlobalRef(mReceiverWeakGlobal);
    314         env->DeleteGlobalRef(mFloatScratch);
    315         env->DeleteGlobalRef(mIntScratch);
    316     }
    317     sp<SensorEventQueue> getSensorEventQueue() const {
    318         return mSensorQueue;
    319     }
    320 
    321     void destroy() {
    322         mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
    323     }
    324 
    325 private:
    326     virtual void onFirstRef() {
    327         LooperCallback::onFirstRef();
    328         mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
    329                 ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
    330     }
    331 
    332     virtual int handleEvent(int fd, int events, void* data) {
    333         JNIEnv* env = AndroidRuntime::getJNIEnv();
    334         sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data);
    335         ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
    336 
    337         ssize_t n;
    338         ASensorEvent buffer[16];
    339         while ((n = q->read(buffer, 16)) > 0) {
    340             for (int i=0 ; i<n ; i++) {
    341                 if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
    342                     // step-counter returns a uint64, but the java API only deals with floats
    343                     float value = float(buffer[i].u64.step_counter);
    344                     env->SetFloatArrayRegion(mFloatScratch, 0, 1, &value);
    345                 } else if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
    346                     float value[2];
    347                     value[0] = buffer[i].dynamic_sensor_meta.connected ? 1.f: 0.f;
    348                     value[1] = float(buffer[i].dynamic_sensor_meta.handle);
    349                     env->SetFloatArrayRegion(mFloatScratch, 0, 2, value);
    350                 } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
    351                     env->SetIntArrayRegion(mIntScratch, 0, 14,
    352                                            buffer[i].additional_info.data_int32);
    353                     env->SetFloatArrayRegion(mFloatScratch, 0, 14,
    354                                              buffer[i].additional_info.data_float);
    355                 } else {
    356                     env->SetFloatArrayRegion(mFloatScratch, 0, 16, buffer[i].data);
    357                 }
    358 
    359                 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
    360                     // This is a flush complete sensor event. Call dispatchFlushCompleteEvent
    361                     // method.
    362                     if (receiverObj.get()) {
    363                         env->CallVoidMethod(receiverObj.get(),
    364                                             gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
    365                                             buffer[i].meta_data.sensor);
    366                     }
    367                 } else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
    368                     // This is a flush complete sensor event. Call dispatchAdditionalInfoEvent
    369                     // method.
    370                     if (receiverObj.get()) {
    371                         int type = buffer[i].additional_info.type;
    372                         int serial = buffer[i].additional_info.serial;
    373                         env->CallVoidMethod(receiverObj.get(),
    374                                             gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent,
    375                                             buffer[i].sensor,
    376                                             type, serial,
    377                                             mFloatScratch,
    378                                             mIntScratch,
    379                                             buffer[i].timestamp);
    380                     }
    381                 }else {
    382                     int8_t status;
    383                     switch (buffer[i].type) {
    384                     case SENSOR_TYPE_ORIENTATION:
    385                     case SENSOR_TYPE_MAGNETIC_FIELD:
    386                     case SENSOR_TYPE_ACCELEROMETER:
    387                     case SENSOR_TYPE_GYROSCOPE:
    388                     case SENSOR_TYPE_GRAVITY:
    389                     case SENSOR_TYPE_LINEAR_ACCELERATION:
    390                         status = buffer[i].vector.status;
    391                         break;
    392                     case SENSOR_TYPE_HEART_RATE:
    393                         status = buffer[i].heart_rate.status;
    394                         break;
    395                     default:
    396                         status = SENSOR_STATUS_ACCURACY_HIGH;
    397                         break;
    398                     }
    399                     if (receiverObj.get()) {
    400                         env->CallVoidMethod(receiverObj.get(),
    401                                             gBaseEventQueueClassInfo.dispatchSensorEvent,
    402                                             buffer[i].sensor,
    403                                             mFloatScratch,
    404                                             status,
    405                                             buffer[i].timestamp);
    406                     }
    407                 }
    408                 if (env->ExceptionCheck()) {
    409                     mSensorQueue->sendAck(buffer, n);
    410                     ALOGE("Exception dispatching input event.");
    411                     return 1;
    412                 }
    413             }
    414             mSensorQueue->sendAck(buffer, n);
    415         }
    416         if (n<0 && n != -EAGAIN) {
    417             // FIXME: error receiving events, what to do in this case?
    418         }
    419         return 1;
    420     }
    421 };
    422 
    423 static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
    424         jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {
    425     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
    426     ScopedUtfChars packageUtf(env, packageName);
    427     String8 clientName(packageUtf.c_str());
    428     sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode));
    429 
    430     if (queue == NULL) {
    431         jniThrowRuntimeException(env, "Cannot construct native SensorEventQueue.");
    432         return 0;
    433     }
    434 
    435     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
    436     if (messageQueue == NULL) {
    437         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
    438         return 0;
    439     }
    440 
    441     sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak);
    442     receiver->incStrong((void*)nativeInitSensorEventQueue);
    443     return jlong(receiver.get());
    444 }
    445 
    446 static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
    447                                jint maxBatchReportLatency) {
    448     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    449     return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
    450                                                          0);
    451 }
    452 
    453 static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
    454     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    455     return receiver->getSensorEventQueue()->disableSensor(handle);
    456 }
    457 
    458 static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ) {
    459     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    460     receiver->destroy();
    461     receiver->decStrong((void*)nativeInitSensorEventQueue);
    462 }
    463 
    464 static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
    465     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    466     return receiver->getSensorEventQueue()->flush();
    467 }
    468 
    469 static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint handle,
    470         jfloatArray values, jint accuracy, jlong timestamp) {
    471     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    472     // Create a sensor_event from the above data which can be injected into the HAL.
    473     ASensorEvent sensor_event;
    474     memset(&sensor_event, 0, sizeof(sensor_event));
    475     sensor_event.sensor = handle;
    476     sensor_event.timestamp = timestamp;
    477     env->GetFloatArrayRegion(values, 0, env->GetArrayLength(values), sensor_event.data);
    478     return receiver->getSensorEventQueue()->injectSensorEvent(sensor_event);
    479 }
    480 //----------------------------------------------------------------------------
    481 
    482 static const JNINativeMethod gSystemSensorManagerMethods[] = {
    483     {"nativeClassInit",
    484             "()V",
    485             (void*)nativeClassInit },
    486     {"nativeCreate",
    487              "(Ljava/lang/String;)J",
    488              (void*)nativeCreate },
    489 
    490     {"nativeGetSensorAtIndex",
    491             "(JLandroid/hardware/Sensor;I)Z",
    492             (void*)nativeGetSensorAtIndex },
    493 
    494     {"nativeGetDynamicSensors",
    495             "(JLjava/util/List;)V",
    496             (void*)nativeGetDynamicSensors },
    497 
    498     {"nativeIsDataInjectionEnabled",
    499             "(J)Z",
    500             (void*)nativeIsDataInjectionEnabled },
    501 
    502     {"nativeCreateDirectChannel",
    503             "(JJIILandroid/hardware/HardwareBuffer;)I",
    504             (void*)nativeCreateDirectChannel },
    505 
    506     {"nativeDestroyDirectChannel",
    507             "(JI)V",
    508             (void*)nativeDestroyDirectChannel },
    509 
    510     {"nativeConfigDirectChannel",
    511             "(JIII)I",
    512             (void*)nativeConfigDirectChannel },
    513 
    514     {"nativeSetOperationParameter",
    515             "(JII[F[I)I",
    516             (void*)nativeSetOperationParameter },
    517 };
    518 
    519 static const JNINativeMethod gBaseEventQueueMethods[] = {
    520     {"nativeInitBaseEventQueue",
    521              "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/String;)J",
    522              (void*)nativeInitSensorEventQueue },
    523 
    524     {"nativeEnableSensor",
    525             "(JIII)I",
    526             (void*)nativeEnableSensor },
    527 
    528     {"nativeDisableSensor",
    529             "(JI)I",
    530             (void*)nativeDisableSensor },
    531 
    532     {"nativeDestroySensorEventQueue",
    533             "(J)V",
    534             (void*)nativeDestroySensorEventQueue },
    535 
    536     {"nativeFlushSensor",
    537             "(J)I",
    538             (void*)nativeFlushSensor },
    539 
    540     {"nativeInjectSensorData",
    541             "(JI[FIJ)I",
    542             (void*)nativeInjectSensorData },
    543 };
    544 
    545 } //unnamed namespace
    546 
    547 int register_android_hardware_SensorManager(JNIEnv *env)
    548 {
    549     RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",
    550             gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
    551 
    552     RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager$BaseEventQueue",
    553             gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
    554 
    555     gBaseEventQueueClassInfo.clazz = FindClassOrDie(env,
    556             "android/hardware/SystemSensorManager$BaseEventQueue");
    557 
    558     gBaseEventQueueClassInfo.dispatchSensorEvent = GetMethodIDOrDie(env,
    559             gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V");
    560 
    561     gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
    562             gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
    563 
    564     gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent = GetMethodIDOrDie(env,
    565             gBaseEventQueueClassInfo.clazz, "dispatchAdditionalInfoEvent", "(III[F[I)V");
    566 
    567     return 0;
    568 }
    569