blob: ae0113b3541f17f7cd7ba671eaa8f5f2accf953b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Mike Lockwood270e87f2009-05-22 10:02:14 -040017#define LOG_TAG "SensorManager"
18
Mathias Agopiandb772d82013-01-31 19:31:12 -080019#include <utils/Log.h>
20#include <utils/Looper.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021
Mathias Agopian1bf79782010-07-14 23:41:37 -070022#include <gui/Sensor.h>
23#include <gui/SensorManager.h>
24#include <gui/SensorEventQueue.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
26#include "jni.h"
27#include "JNIHelp.h"
Mathias Agopiandb772d82013-01-31 19:31:12 -080028#include "android_os_MessageQueue.h"
29#include <android_runtime/AndroidRuntime.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
Mathias Agopiandb772d82013-01-31 19:31:12 -080031static struct {
32 jclass clazz;
33 jmethodID dispatchSensorEvent;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080034} gBaseEventQueueClassInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035
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;
Mathias Agopian050b5622010-07-29 16:51:38 -070048 jfieldID minDelay;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049} gSensorOffsets;
50
Mathias Agopiandb772d82013-01-31 19:31:12 -080051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052/*
53 * The method below are not thread-safe and not intended to be
54 */
55
Mathias Agopiandb772d82013-01-31 19:31:12 -080056static void
57nativeClassInit (JNIEnv *_env, jclass _this)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058{
Mathias Agopiandb772d82013-01-31 19:31:12 -080059 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");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070}
71
72static jint
Mathias Agopiandb772d82013-01-31 19:31:12 -080073nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074{
Mathias Agopian1bf79782010-07-14 23:41:37 -070075 SensorManager& mgr(SensorManager::getInstance());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076
Mathias Agopian1bf79782010-07-14 23:41:37 -070077 Sensor const* const* sensorList;
78 size_t count = mgr.getSensorList(&sensorList);
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070079 if (size_t(next) >= count)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 return -1;
81
Mathias Agopian1bf79782010-07-14 23:41:37 -070082 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());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 env->SetObjectField(sensor, sensorOffsets.name, name);
87 env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
Mathias Agopian277d1b22012-05-04 15:51:29 -070088 env->SetIntField(sensor, sensorOffsets.version, list->getVersion());
Mathias Agopian1bf79782010-07-14 23:41:37 -070089 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());
Mathias Agopian050b5622010-07-29 16:51:38 -070094 env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
96 next++;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -070097 return size_t(next) < count ? next : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098}
99
100//----------------------------------------------------------------------------
Mathias Agopiandb772d82013-01-31 19:31:12 -0800101
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
Mathias Agopianb25c0ef2013-07-03 15:38:29 -0700145 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 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800152
153 env->CallVoidMethod(mReceiverObject,
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800154 gBaseEventQueueClassInfo.dispatchSensorEvent,
Mathias Agopiandb772d82013-01-31 19:31:12 -0800155 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) {
Mathias Agopian1bf79782010-07-14 23:41:37 -0700175 SensorManager& mgr(SensorManager::getInstance());
176 sp<SensorEventQueue> queue(mgr.createEventQueue());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
Mathias Agopiandb772d82013-01-31 19:31:12 -0800178 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
179 if (messageQueue == NULL) {
180 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
181 return 0;
Mathias Agopian0b6d77b2012-05-07 18:27:06 -0700182 }
Mathias Agopian1bf79782010-07-14 23:41:37 -0700183
Mathias Agopiandb772d82013-01-31 19:31:12 -0800184 sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800185 receiver->incStrong((void*)nativeInitSensorEventQueue);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800186 return jint(receiver.get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187}
188
Mathias Agopiandb772d82013-01-31 19:31:12 -0800189static 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192}
193
Mathias Agopiandb772d82013-01-31 19:31:12 -0800194static 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}
Mathias Agopian1bf79782010-07-14 23:41:37 -0700198
Mathias Agopiandb772d82013-01-31 19:31:12 -0800199static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
200 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
201 receiver->destroy();
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800202 receiver->decStrong((void*)nativeInitSensorEventQueue);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800203}
Mathias Agopian1bf79782010-07-14 23:41:37 -0700204
Mathias Agopiandb772d82013-01-31 19:31:12 -0800205
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
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800218static JNINativeMethod gBaseEventQueueMethods[] = {
219 {"nativeInitBaseEventQueue",
220 "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[F)I",
Mathias Agopiandb772d82013-01-31 19:31:12 -0800221 (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 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234};
235
236}; // namespace android
237
238using namespace android;
239
Mathias Agopiandb772d82013-01-31 19:31:12 -0800240#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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249int register_android_hardware_SensorManager(JNIEnv *env)
250{
Mathias Agopiandb772d82013-01-31 19:31:12 -0800251 jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
252 gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
253
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800254 jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager$BaseEventQueue",
255 gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
Mathias Agopiandb772d82013-01-31 19:31:12 -0800256
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800257 FIND_CLASS(gBaseEventQueueClassInfo.clazz, "android/hardware/SystemSensorManager$BaseEventQueue");
Mathias Agopiandb772d82013-01-31 19:31:12 -0800258
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800259 GET_METHOD_ID(gBaseEventQueueClassInfo.dispatchSensorEvent,
260 gBaseEventQueueClassInfo.clazz,
Mathias Agopiandb772d82013-01-31 19:31:12 -0800261 "dispatchSensorEvent", "(I[FIJ)V");
262
263 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264}