android_hardware_SensorManager.cpp revision 27900358f2f5b89e8b01516b28a916d16c99ba9b
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                    buffer[i].type == SENSOR_TYPE_WAKE_UP_STEP_COUNTER) {
171                    // step-counter returns a uint64, but the java API only deals with floats
172                    float value = float(buffer[i].u64.step_counter);
173                    env->SetFloatArrayRegion(mScratch, 0, 1, &value);
174                } else {
175                    env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
176                }
177
178                if (buffer[i].type == SENSOR_TYPE_META_DATA) {
179                    // This is a flush complete sensor event. Call dispatchFlushCompleteEvent
180                    // method.
181                    env->CallVoidMethod(mReceiverObject,
182                                        gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
183                                        buffer[i].meta_data.sensor);
184                } else {
185                    int8_t status;
186                    switch (buffer[i].type) {
187                    case SENSOR_TYPE_ORIENTATION:
188                    case SENSOR_TYPE_MAGNETIC_FIELD:
189                    case SENSOR_TYPE_ACCELEROMETER:
190                    case SENSOR_TYPE_GYROSCOPE:
191                        status = buffer[i].vector.status;
192                        break;
193                    case SENSOR_TYPE_HEART_RATE:
194                        status = buffer[i].heart_rate.status;
195                        break;
196                    default:
197                        status = SENSOR_STATUS_ACCURACY_HIGH;
198                        break;
199                    }
200                    env->CallVoidMethod(mReceiverObject,
201                                        gBaseEventQueueClassInfo.dispatchSensorEvent,
202                                        buffer[i].sensor,
203                                        mScratch,
204                                        status,
205                                        buffer[i].timestamp);
206                }
207                if (env->ExceptionCheck()) {
208                    mSensorQueue->sendAck(buffer, n);
209                    ALOGE("Exception dispatching input event.");
210                    return 1;
211                }
212            }
213            mSensorQueue->sendAck(buffer, n);
214        }
215        if (n<0 && n != -EAGAIN) {
216            // FIXME: error receiving events, what to do in this case?
217        }
218        return 1;
219    }
220};
221
222static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ, jfloatArray scratch) {
223    SensorManager& mgr(SensorManager::getInstance());
224    sp<SensorEventQueue> queue(mgr.createEventQueue());
225
226    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
227    if (messageQueue == NULL) {
228        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
229        return 0;
230    }
231
232    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
233    receiver->incStrong((void*)nativeInitSensorEventQueue);
234    return jlong(receiver.get());
235}
236
237static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
238                               jint maxBatchReportLatency, jint reservedFlags) {
239    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
240    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
241                                                         reservedFlags);
242}
243
244static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
245    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
246    return receiver->getSensorEventQueue()->disableSensor(handle);
247}
248
249static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
250    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
251    receiver->destroy();
252    receiver->decStrong((void*)nativeInitSensorEventQueue);
253}
254
255static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
256    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
257    return receiver->getSensorEventQueue()->flush();
258}
259
260//----------------------------------------------------------------------------
261
262static JNINativeMethod gSystemSensorManagerMethods[] = {
263    {"nativeClassInit",
264            "()V",
265            (void*)nativeClassInit },
266
267    {"nativeGetNextSensor",
268            "(Landroid/hardware/Sensor;I)I",
269            (void*)nativeGetNextSensor },
270};
271
272static JNINativeMethod gBaseEventQueueMethods[] = {
273    {"nativeInitBaseEventQueue",
274            "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[F)J",
275            (void*)nativeInitSensorEventQueue },
276
277    {"nativeEnableSensor",
278            "(JIIII)I",
279            (void*)nativeEnableSensor },
280
281    {"nativeDisableSensor",
282            "(JI)I",
283            (void*)nativeDisableSensor },
284
285    {"nativeDestroySensorEventQueue",
286            "(J)V",
287            (void*)nativeDestroySensorEventQueue },
288
289    {"nativeFlushSensor",
290            "(J)I",
291            (void*)nativeFlushSensor },
292};
293
294}; // namespace android
295
296using namespace android;
297
298#define FIND_CLASS(var, className) \
299        var = env->FindClass(className); \
300        LOG_FATAL_IF(! var, "Unable to find class " className); \
301        var = jclass(env->NewGlobalRef(var));
302
303#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
304        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
305        LOG_FATAL_IF(! var, "Unable to find method " methodName);
306
307int register_android_hardware_SensorManager(JNIEnv *env)
308{
309    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
310            gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
311
312    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager$BaseEventQueue",
313            gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
314
315    FIND_CLASS(gBaseEventQueueClassInfo.clazz, "android/hardware/SystemSensorManager$BaseEventQueue");
316
317    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchSensorEvent,
318            gBaseEventQueueClassInfo.clazz,
319            "dispatchSensorEvent", "(I[FIJ)V");
320
321    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
322                  gBaseEventQueueClassInfo.clazz,
323                  "dispatchFlushCompleteEvent", "(I)V");
324
325    return 0;
326}
327