android_hardware_SensorManager.cpp revision 0288ca63e3f0aee05ad2ede23564e04e53aca950
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
17#define LOG_TAG "SensorManager"
18
19#include <utils/Log.h>
20#include <utils/Looper.h>
21
22#include <gui/Sensor.h>
23#include <gui/SensorManager.h>
24#include <gui/SensorEventQueue.h>
25
26#include "jni.h"
27#include "JNIHelp.h"
28#include "android_os_MessageQueue.h"
29#include <android_runtime/AndroidRuntime.h>
30
31static struct {
32    jclass clazz;
33    jmethodID dispatchSensorEvent;
34    jmethodID dispatchFlushCompleteEvent;
35} gBaseEventQueueClassInfo;
36
37namespace android {
38
39struct SensorOffsets
40{
41    jfieldID    name;
42    jfieldID    vendor;
43    jfieldID    version;
44    jfieldID    handle;
45    jfieldID    type;
46    jfieldID    range;
47    jfieldID    resolution;
48    jfieldID    power;
49    jfieldID    minDelay;
50    jfieldID    fifoReservedEventCount;
51    jfieldID    fifoMaxEventCount;
52    jfieldID    stringType;
53    jfieldID    requiredPermission;
54    jfieldID    maxDelay;
55    jfieldID    flags;
56} gSensorOffsets;
57
58
59/*
60 * The method below are not thread-safe and not intended to be
61 */
62
63static void
64nativeClassInit (JNIEnv *_env, jclass _this)
65{
66    jclass sensorClass = _env->FindClass("android/hardware/Sensor");
67    SensorOffsets& sensorOffsets = gSensorOffsets;
68    sensorOffsets.name        = _env->GetFieldID(sensorClass, "mName",      "Ljava/lang/String;");
69    sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
70    sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
71    sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
72    sensorOffsets.type        = _env->GetFieldID(sensorClass, "mType",      "I");
73    sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
74    sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
75    sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
76    sensorOffsets.minDelay    = _env->GetFieldID(sensorClass, "mMinDelay",  "I");
77    sensorOffsets.fifoReservedEventCount =
78            _env->GetFieldID(sensorClass, "mFifoReservedEventCount",  "I");
79    sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount",  "I");
80    sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
81    sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
82                                                        "Ljava/lang/String;");
83    sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
84    sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags",  "I");
85}
86
87static jint
88nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
89{
90    SensorManager& mgr(SensorManager::getInstance());
91
92    Sensor const* const* sensorList;
93    size_t count = mgr.getSensorList(&sensorList);
94    if (size_t(next) >= count)
95        return -1;
96
97    Sensor const* const list = sensorList[next];
98    const SensorOffsets& sensorOffsets(gSensorOffsets);
99    jstring name = env->NewStringUTF(list->getName().string());
100    jstring vendor = env->NewStringUTF(list->getVendor().string());
101    jstring stringType = env->NewStringUTF(list->getStringType().string());
102    jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
103    env->SetObjectField(sensor, sensorOffsets.name,      name);
104    env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
105    env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
106    env->SetIntField(sensor, sensorOffsets.handle,       list->getHandle());
107    env->SetIntField(sensor, sensorOffsets.type,         list->getType());
108    env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
109    env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
110    env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
111    env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
112    env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
113                     list->getFifoReservedEventCount());
114    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
115                     list->getFifoMaxEventCount());
116    env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
117    env->SetObjectField(sensor, sensorOffsets.requiredPermission,
118                        requiredPermission);
119    env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
120    env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
121    next++;
122    return size_t(next) < count ? next : 0;
123}
124
125//----------------------------------------------------------------------------
126
127class Receiver : public LooperCallback {
128    sp<SensorEventQueue> mSensorQueue;
129    sp<MessageQueue> mMessageQueue;
130    jobject mReceiverObject;
131    jfloatArray mScratch;
132public:
133    Receiver(const sp<SensorEventQueue>& sensorQueue,
134            const sp<MessageQueue>& messageQueue,
135            jobject receiverObject, jfloatArray scratch) {
136        JNIEnv* env = AndroidRuntime::getJNIEnv();
137        mSensorQueue = sensorQueue;
138        mMessageQueue = messageQueue;
139        mReceiverObject = env->NewGlobalRef(receiverObject);
140        mScratch = (jfloatArray)env->NewGlobalRef(scratch);
141    }
142    ~Receiver() {
143        JNIEnv* env = AndroidRuntime::getJNIEnv();
144        env->DeleteGlobalRef(mReceiverObject);
145        env->DeleteGlobalRef(mScratch);
146    }
147    sp<SensorEventQueue> getSensorEventQueue() const {
148        return mSensorQueue;
149    }
150
151    void destroy() {
152        mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
153    }
154
155private:
156    virtual void onFirstRef() {
157        LooperCallback::onFirstRef();
158        mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
159                ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
160    }
161
162    virtual int handleEvent(int fd, int events, void* data) {
163        JNIEnv* env = AndroidRuntime::getJNIEnv();
164        sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data);
165        ssize_t n;
166        ASensorEvent buffer[16];
167        while ((n = q->read(buffer, 16)) > 0) {
168            for (int i=0 ; i<n ; i++) {
169                if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
170                    // step-counter returns a uint64, but the java API only deals with floats
171                    float value = float(buffer[i].u64.step_counter);
172                    env->SetFloatArrayRegion(mScratch, 0, 1, &value);
173                } else {
174                    env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
175                }
176
177                if (buffer[i].type == SENSOR_TYPE_META_DATA) {
178                    // This is a flush complete sensor event. Call dispatchFlushCompleteEvent
179                    // method.
180                    env->CallVoidMethod(mReceiverObject,
181                                        gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
182                                        buffer[i].meta_data.sensor);
183                } else {
184                    int8_t status;
185                    switch (buffer[i].type) {
186                    case SENSOR_TYPE_ORIENTATION:
187                    case SENSOR_TYPE_MAGNETIC_FIELD:
188                    case SENSOR_TYPE_ACCELEROMETER:
189                    case SENSOR_TYPE_GYROSCOPE:
190                        status = buffer[i].vector.status;
191                        break;
192                    case SENSOR_TYPE_HEART_RATE:
193                        status = buffer[i].heart_rate.status;
194                        break;
195                    default:
196                        status = SENSOR_STATUS_ACCURACY_HIGH;
197                        break;
198                    }
199                    env->CallVoidMethod(mReceiverObject,
200                                        gBaseEventQueueClassInfo.dispatchSensorEvent,
201                                        buffer[i].sensor,
202                                        mScratch,
203                                        status,
204                                        buffer[i].timestamp);
205                }
206                if (env->ExceptionCheck()) {
207                    mSensorQueue->sendAck(buffer, n);
208                    ALOGE("Exception dispatching input event.");
209                    return 1;
210                }
211            }
212            mSensorQueue->sendAck(buffer, n);
213        }
214        if (n<0 && n != -EAGAIN) {
215            // FIXME: error receiving events, what to do in this case?
216        }
217        return 1;
218    }
219};
220
221static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ, jfloatArray scratch) {
222    SensorManager& mgr(SensorManager::getInstance());
223    sp<SensorEventQueue> queue(mgr.createEventQueue());
224
225    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
226    if (messageQueue == NULL) {
227        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
228        return 0;
229    }
230
231    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
232    receiver->incStrong((void*)nativeInitSensorEventQueue);
233    return jlong(receiver.get());
234}
235
236static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
237                               jint maxBatchReportLatency, jint reservedFlags) {
238    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
239    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
240                                                         reservedFlags);
241}
242
243static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
244    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
245    return receiver->getSensorEventQueue()->disableSensor(handle);
246}
247
248static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
249    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
250    receiver->destroy();
251    receiver->decStrong((void*)nativeInitSensorEventQueue);
252}
253
254static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
255    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
256    return receiver->getSensorEventQueue()->flush();
257}
258
259//----------------------------------------------------------------------------
260
261static JNINativeMethod gSystemSensorManagerMethods[] = {
262    {"nativeClassInit",
263            "()V",
264            (void*)nativeClassInit },
265
266    {"nativeGetNextSensor",
267            "(Landroid/hardware/Sensor;I)I",
268            (void*)nativeGetNextSensor },
269};
270
271static JNINativeMethod gBaseEventQueueMethods[] = {
272    {"nativeInitBaseEventQueue",
273            "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[F)J",
274            (void*)nativeInitSensorEventQueue },
275
276    {"nativeEnableSensor",
277            "(JIIII)I",
278            (void*)nativeEnableSensor },
279
280    {"nativeDisableSensor",
281            "(JI)I",
282            (void*)nativeDisableSensor },
283
284    {"nativeDestroySensorEventQueue",
285            "(J)V",
286            (void*)nativeDestroySensorEventQueue },
287
288    {"nativeFlushSensor",
289            "(J)I",
290            (void*)nativeFlushSensor },
291};
292
293}; // namespace android
294
295using namespace android;
296
297#define FIND_CLASS(var, className) \
298        var = env->FindClass(className); \
299        LOG_FATAL_IF(! var, "Unable to find class " className); \
300        var = jclass(env->NewGlobalRef(var));
301
302#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
303        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
304        LOG_FATAL_IF(! var, "Unable to find method " methodName);
305
306int register_android_hardware_SensorManager(JNIEnv *env)
307{
308    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
309            gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
310
311    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager$BaseEventQueue",
312            gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
313
314    FIND_CLASS(gBaseEventQueueClassInfo.clazz, "android/hardware/SystemSensorManager$BaseEventQueue");
315
316    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchSensorEvent,
317            gBaseEventQueueClassInfo.clazz,
318            "dispatchSensorEvent", "(I[FIJ)V");
319
320    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
321                  gBaseEventQueueClassInfo.clazz,
322                  "dispatchFlushCompleteEvent", "(I)V");
323
324    return 0;
325}
326