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
78struct 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 */
88static void
89nativeClassInit (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
134static 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
145static jlong
146nativeCreate
147(JNIEnv *env, jclass clazz, jstring opPackageName)
148{
149    ScopedUtfChars opPackageNameUtf(env, opPackageName);
150    return (jlong) &SensorManager::getInstanceForPackage(String16(opPackageNameUtf.c_str()));
151}
152
153static jobject
154translateNativeSensorToJavaSensor(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
198static jboolean
199nativeGetSensorAtIndex(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
212static void
213nativeGetDynamicSensors(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
230static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
231    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
232    return mgr->isDataInjectionEnabled();
233}
234
235static 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
260static void nativeDestroyDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
261        jint channelHandle) {
262    SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
263    mgr->destroyDirectChannel(channelHandle);
264}
265
266static 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
272static jint nativeSetOperationParameter(JNIEnv *_env, jclass _this, jlong sensorManager,
273        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(type, floatVector, int32Vector);
289}
290
291//----------------------------------------------------------------------------
292
293class Receiver : public LooperCallback {
294    sp<SensorEventQueue> mSensorQueue;
295    sp<MessageQueue> mMessageQueue;
296    jobject mReceiverWeakGlobal;
297    jfloatArray mFloatScratch;
298    jintArray   mIntScratch;
299public:
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
325private:
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
423static 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
446static 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
453static 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
458static 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
464static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
465    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
466    return receiver->getSensorEventQueue()->flush();
467}
468
469static 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
482static 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            "(JI[F[I)I",
516            (void*)nativeSetOperationParameter },
517};
518
519static 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
547int 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