android_hardware_SensorManager.cpp revision 2f8b91449efafa5fb0057cd0150233681c65c9e3
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    isWakeUpSensor;
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.isWakeUpSensor = _env->GetFieldID(sensorClass, "mWakeUpSensor",  "Z");
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->SetBooleanField(sensor, sensorOffsets.isWakeUpSensor, list->isWakeUpSensor());
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                    env->CallVoidMethod(mReceiverObject,
186                                        gBaseEventQueueClassInfo.dispatchSensorEvent,
187                                        buffer[i].sensor,
188                                        mScratch,
189                                        buffer[i].vector.status,
190                                        buffer[i].timestamp);
191                }
192                if (env->ExceptionCheck()) {
193                    mSensorQueue->sendAck(buffer, n);
194                    ALOGE("Exception dispatching input event.");
195                    return 1;
196                }
197            }
198            mSensorQueue->sendAck(buffer, n);
199        }
200        if (n<0 && n != -EAGAIN) {
201            // FIXME: error receiving events, what to do in this case?
202        }
203        return 1;
204    }
205};
206
207static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ, jfloatArray scratch) {
208    SensorManager& mgr(SensorManager::getInstance());
209    sp<SensorEventQueue> queue(mgr.createEventQueue());
210
211    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
212    if (messageQueue == NULL) {
213        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
214        return 0;
215    }
216
217    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
218    receiver->incStrong((void*)nativeInitSensorEventQueue);
219    return jlong(receiver.get());
220}
221
222static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
223                               jint maxBatchReportLatency, jint reservedFlags) {
224    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
225    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
226                                                         reservedFlags);
227}
228
229static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
230    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
231    return receiver->getSensorEventQueue()->disableSensor(handle);
232}
233
234static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
235    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
236    receiver->destroy();
237    receiver->decStrong((void*)nativeInitSensorEventQueue);
238}
239
240static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
241    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
242    return receiver->getSensorEventQueue()->flush();
243}
244
245//----------------------------------------------------------------------------
246
247static JNINativeMethod gSystemSensorManagerMethods[] = {
248    {"nativeClassInit",
249            "()V",
250            (void*)nativeClassInit },
251
252    {"nativeGetNextSensor",
253            "(Landroid/hardware/Sensor;I)I",
254            (void*)nativeGetNextSensor },
255};
256
257static JNINativeMethod gBaseEventQueueMethods[] = {
258    {"nativeInitBaseEventQueue",
259            "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[F)J",
260            (void*)nativeInitSensorEventQueue },
261
262    {"nativeEnableSensor",
263            "(JIIII)I",
264            (void*)nativeEnableSensor },
265
266    {"nativeDisableSensor",
267            "(JI)I",
268            (void*)nativeDisableSensor },
269
270    {"nativeDestroySensorEventQueue",
271            "(J)V",
272            (void*)nativeDestroySensorEventQueue },
273
274    {"nativeFlushSensor",
275            "(J)I",
276            (void*)nativeFlushSensor },
277};
278
279}; // namespace android
280
281using namespace android;
282
283#define FIND_CLASS(var, className) \
284        var = env->FindClass(className); \
285        LOG_FATAL_IF(! var, "Unable to find class " className); \
286        var = jclass(env->NewGlobalRef(var));
287
288#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
289        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
290        LOG_FATAL_IF(! var, "Unable to find method " methodName);
291
292int register_android_hardware_SensorManager(JNIEnv *env)
293{
294    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
295            gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
296
297    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager$BaseEventQueue",
298            gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
299
300    FIND_CLASS(gBaseEventQueueClassInfo.clazz, "android/hardware/SystemSensorManager$BaseEventQueue");
301
302    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchSensorEvent,
303            gBaseEventQueueClassInfo.clazz,
304            "dispatchSensorEvent", "(I[FIJ)V");
305
306    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
307                  gBaseEventQueueClassInfo.clazz,
308                  "dispatchFlushCompleteEvent", "(I)V");
309
310    return 0;
311}
312