android_hardware_SensorManager.cpp revision 80ba0a6baec17d5ac5a1e6f9e4b84f7d013d07e6
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} gBaseEventQueueClassInfo;
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                if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
146                    // step-counter returns a uint64, but the java API only deals with floats
147                    float value = float(buffer[i].u64.step_counter);
148                    env->SetFloatArrayRegion(mScratch, 0, 1, &value);
149                } else {
150                    env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
151                }
152
153                env->CallVoidMethod(mReceiverObject,
154                        gBaseEventQueueClassInfo.dispatchSensorEvent,
155                        buffer[i].sensor,
156                        mScratch,
157                        buffer[i].vector.status,
158                        buffer[i].timestamp);
159
160                if (env->ExceptionCheck()) {
161                    ALOGE("Exception dispatching input event.");
162                    return 1;
163                }
164            }
165        }
166        if (n<0 && n != -EAGAIN) {
167            // FIXME: error receiving events, what to do in this case?
168        }
169
170        return 1;
171    }
172};
173
174static jint nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ, jfloatArray scratch) {
175    SensorManager& mgr(SensorManager::getInstance());
176    sp<SensorEventQueue> queue(mgr.createEventQueue());
177
178    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
179    if (messageQueue == NULL) {
180        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
181        return 0;
182    }
183
184    sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
185    receiver->incStrong((void*)nativeInitSensorEventQueue);
186    return jint(receiver.get());
187}
188
189static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle, jint us) {
190    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
191    return receiver->getSensorEventQueue()->enableSensor(handle, us);
192}
193
194static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
195    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
196    return receiver->getSensorEventQueue()->disableSensor(handle);
197}
198
199static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
200    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
201    receiver->destroy();
202    receiver->decStrong((void*)nativeInitSensorEventQueue);
203}
204
205
206//----------------------------------------------------------------------------
207
208static JNINativeMethod gSystemSensorManagerMethods[] = {
209    {"nativeClassInit",
210            "()V",
211            (void*)nativeClassInit },
212
213    {"nativeGetNextSensor",
214            "(Landroid/hardware/Sensor;I)I",
215            (void*)nativeGetNextSensor },
216};
217
218static JNINativeMethod gBaseEventQueueMethods[] = {
219    {"nativeInitBaseEventQueue",
220            "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[F)I",
221            (void*)nativeInitSensorEventQueue },
222
223    {"nativeEnableSensor",
224            "(III)I",
225            (void*)nativeEnableSensor },
226
227    {"nativeDisableSensor",
228            "(II)I",
229            (void*)nativeDisableSensor },
230
231    {"nativeDestroySensorEventQueue",
232            "(I)V",
233            (void*)nativeDestroySensorEventQueue },
234};
235
236}; // namespace android
237
238using namespace android;
239
240#define FIND_CLASS(var, className) \
241        var = env->FindClass(className); \
242        LOG_FATAL_IF(! var, "Unable to find class " className); \
243        var = jclass(env->NewGlobalRef(var));
244
245#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
246        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
247        LOG_FATAL_IF(! var, "Unable to find method " methodName);
248
249int register_android_hardware_SensorManager(JNIEnv *env)
250{
251    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
252            gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
253
254    jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager$BaseEventQueue",
255            gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
256
257    FIND_CLASS(gBaseEventQueueClassInfo.clazz, "android/hardware/SystemSensorManager$BaseEventQueue");
258
259    GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchSensorEvent,
260            gBaseEventQueueClassInfo.clazz,
261            "dispatchSensorEvent", "(I[FIJ)V");
262
263    return 0;
264}
265