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