android_hardware_SensorManager.cpp revision 1aab1dbca5cf7386797ce609c768249247233186
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} gSensorEventQueueClassInfo;
35
36namespace android {
37
38struct SensorOffsets
39{
40    jfieldID    name;
41    jfieldID    vendor;
42    jfieldID    version;
43    jfieldID    handle;
44    jfieldID    type;
45    jfieldID    range;
46    jfieldID    resolution;
47    jfieldID    power;
48    jfieldID    minDelay;
49} gSensorOffsets;
50
51
52/*
53 * The method below are not thread-safe and not intended to be
54 */
55
56static void
57nativeClassInit (JNIEnv *_env, jclass _this)
58{
59    jclass sensorClass = _env->FindClass("android/hardware/Sensor");
60    SensorOffsets& sensorOffsets = gSensorOffsets;
61    sensorOffsets.name        = _env->GetFieldID(sensorClass, "mName",      "Ljava/lang/String;");
62    sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
63    sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
64    sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
65    sensorOffsets.type        = _env->GetFieldID(sensorClass, "mType",      "I");
66    sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
67    sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
68    sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
69    sensorOffsets.minDelay    = _env->GetFieldID(sensorClass, "mMinDelay",  "I");
70}
71
72static jint
73nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
74{
75    SensorManager& mgr(SensorManager::getInstance());
76
77    Sensor const* const* sensorList;
78    size_t count = mgr.getSensorList(&sensorList);
79    if (size_t(next) >= count)
80        return -1;
81
82    Sensor const* const list = sensorList[next];
83    const SensorOffsets& sensorOffsets(gSensorOffsets);
84    jstring name = env->NewStringUTF(list->getName().string());
85    jstring vendor = env->NewStringUTF(list->getVendor().string());
86    env->SetObjectField(sensor, sensorOffsets.name,      name);
87    env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
88    env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
89    env->SetIntField(sensor, sensorOffsets.handle,       list->getHandle());
90    env->SetIntField(sensor, sensorOffsets.type,         list->getType());
91    env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
92    env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
93    env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
94    env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
95
96    next++;
97    return size_t(next) < count ? next : 0;
98}
99
100//----------------------------------------------------------------------------
101
102class Receiver : public LooperCallback {
103    sp<SensorEventQueue> mSensorQueue;
104    sp<MessageQueue> mMessageQueue;
105    jobject mReceiverObject;
106    jfloatArray mScratch;
107public:
108    Receiver(const sp<SensorEventQueue>& sensorQueue,
109            const sp<MessageQueue>& messageQueue,
110            jobject receiverObject, jfloatArray scratch) {
111        JNIEnv* env = AndroidRuntime::getJNIEnv();
112        mSensorQueue = sensorQueue;
113        mMessageQueue = messageQueue;
114        mReceiverObject = env->NewGlobalRef(receiverObject);
115        mScratch = (jfloatArray)env->NewGlobalRef(scratch);
116    }
117    ~Receiver() {
118        JNIEnv* env = AndroidRuntime::getJNIEnv();
119        env->DeleteGlobalRef(mReceiverObject);
120        env->DeleteGlobalRef(mScratch);
121    }
122    sp<SensorEventQueue> getSensorEventQueue() const {
123        return mSensorQueue;
124    }
125
126    void destroy() {
127        mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
128    }
129
130private:
131    virtual void onFirstRef() {
132        LooperCallback::onFirstRef();
133        mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
134                ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
135    }
136
137    virtual int handleEvent(int fd, int events, void* data) {
138        JNIEnv* env = AndroidRuntime::getJNIEnv();
139        sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data);
140        ssize_t n;
141        ASensorEvent buffer[16];
142        while ((n = q->read(buffer, 16)) > 0) {
143            for (int i=0 ; i<n ; i++) {
144
145                env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
146
147                env->CallVoidMethod(mReceiverObject,
148                        gSensorEventQueueClassInfo.dispatchSensorEvent,
149                        buffer[i].sensor,
150                        mScratch,
151                        buffer[i].vector.status,
152                        buffer[i].timestamp);
153
154                if (env->ExceptionCheck()) {
155                    ALOGE("Exception dispatching input event.");
156                    return 1;
157                }
158            }
159        }
160        if (n<0 && n != -EAGAIN) {
161            // FIXME: error receiving events, what to do in this case?
162        }
163
164        return 1;
165    }
166};
167
168static jint nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ, jfloatArray scratch) {
169    SensorManager& mgr(SensorManager::getInstance());
170    sp<SensorEventQueue> queue(mgr.createEventQueue());
171
172    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
173    if (messageQueue == NULL) {
174        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
175        return 0;
176    }
177
178    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
179    receiver->incStrong((void*)nativeInitSensorEventQueue);
180    return jint(receiver.get());
181}
182
183static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle, jint us) {
184    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
185    return receiver->getSensorEventQueue()->enableSensor(handle, us);
186}
187
188static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
189    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
190    return receiver->getSensorEventQueue()->disableSensor(handle);
191}
192
193static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
194    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
195    receiver->destroy();
196    receiver->decStrong((void*)nativeInitSensorEventQueue);
197}
198
199
200//----------------------------------------------------------------------------
201
202static JNINativeMethod gSystemSensorManagerMethods[] = {
203    {"nativeClassInit",
204            "()V",
205            (void*)nativeClassInit },
206
207    {"nativeGetNextSensor",
208            "(Landroid/hardware/Sensor;I)I",
209            (void*)nativeGetNextSensor },
210};
211
212static JNINativeMethod gSensorEventQueueMethods[] = {
213    {"nativeInitSensorEventQueue",
214            "(Landroid/hardware/SystemSensorManager$SensorEventQueue;Landroid/os/MessageQueue;[F)I",
215            (void*)nativeInitSensorEventQueue },
216
217    {"nativeEnableSensor",
218            "(III)I",
219            (void*)nativeEnableSensor },
220
221    {"nativeDisableSensor",
222            "(II)I",
223            (void*)nativeDisableSensor },
224
225    {"nativeDestroySensorEventQueue",
226            "(I)V",
227            (void*)nativeDestroySensorEventQueue },
228};
229
230}; // namespace android
231
232using namespace android;
233
234#define FIND_CLASS(var, className) \
235        var = env->FindClass(className); \
236        LOG_FATAL_IF(! var, "Unable to find class " className); \
237        var = jclass(env->NewGlobalRef(var));
238
239#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
240        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
241        LOG_FATAL_IF(! var, "Unable to find method " methodName);
242
243int register_android_hardware_SensorManager(JNIEnv *env)
244{
245    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
246            gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
247
248    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager$SensorEventQueue",
249            gSensorEventQueueMethods, NELEM(gSensorEventQueueMethods));
250
251    FIND_CLASS(gSensorEventQueueClassInfo.clazz, "android/hardware/SystemSensorManager$SensorEventQueue");
252
253    GET_METHOD_ID(gSensorEventQueueClassInfo.dispatchSensorEvent,
254            gSensorEventQueueClassInfo.clazz,
255            "dispatchSensorEvent", "(I[FIJ)V");
256
257    return 0;
258}
259