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