blob: 7d122303e1fa6d09caf75a16617a9071927afe03 [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
destradaa9ba7c1c2015-02-10 15:04:43 -080019#include <map>
20
Aravind Akella88445992015-02-26 17:05:28 -080021#include <ScopedUtfChars.h>
22
Mathias Agopiandb772d82013-01-31 19:31:12 -080023#include <utils/Log.h>
24#include <utils/Looper.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
Mathias Agopian1bf79782010-07-14 23:41:37 -070026#include <gui/Sensor.h>
27#include <gui/SensorManager.h>
28#include <gui/SensorEventQueue.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
30#include "jni.h"
31#include "JNIHelp.h"
Mathias Agopiandb772d82013-01-31 19:31:12 -080032#include "android_os_MessageQueue.h"
33#include <android_runtime/AndroidRuntime.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
Andreas Gampe987f79f2014-11-18 17:29:46 -080035#include "core_jni_helpers.h"
36
Mathias Agopiandb772d82013-01-31 19:31:12 -080037static struct {
38 jclass clazz;
39 jmethodID dispatchSensorEvent;
Aravind Akellab4c76b12013-06-27 12:04:16 -070040 jmethodID dispatchFlushCompleteEvent;
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -080041} gBaseEventQueueClassInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042
43namespace android {
44
45struct SensorOffsets
46{
47 jfieldID name;
48 jfieldID vendor;
49 jfieldID version;
50 jfieldID handle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 jfieldID range;
52 jfieldID resolution;
53 jfieldID power;
Mathias Agopian050b5622010-07-29 16:51:38 -070054 jfieldID minDelay;
Aravind Akellab4c76b12013-06-27 12:04:16 -070055 jfieldID fifoReservedEventCount;
56 jfieldID fifoMaxEventCount;
Aravind Akellacd9a7bb2014-04-07 22:55:21 +000057 jfieldID stringType;
58 jfieldID requiredPermission;
Aravind Akella2f8b9142014-05-12 14:39:29 -070059 jfieldID maxDelay;
Aravind Akella27900352014-06-03 19:20:42 -070060 jfieldID flags;
destradaa9ba7c1c2015-02-10 15:04:43 -080061 jmethodID setType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062} gSensorOffsets;
63
Mathias Agopiandb772d82013-01-31 19:31:12 -080064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065/*
66 * The method below are not thread-safe and not intended to be
67 */
68
Mathias Agopiandb772d82013-01-31 19:31:12 -080069static void
70nativeClassInit (JNIEnv *_env, jclass _this)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071{
Mathias Agopiandb772d82013-01-31 19:31:12 -080072 jclass sensorClass = _env->FindClass("android/hardware/Sensor");
73 SensorOffsets& sensorOffsets = gSensorOffsets;
74 sensorOffsets.name = _env->GetFieldID(sensorClass, "mName", "Ljava/lang/String;");
75 sensorOffsets.vendor = _env->GetFieldID(sensorClass, "mVendor", "Ljava/lang/String;");
76 sensorOffsets.version = _env->GetFieldID(sensorClass, "mVersion", "I");
77 sensorOffsets.handle = _env->GetFieldID(sensorClass, "mHandle", "I");
Mathias Agopiandb772d82013-01-31 19:31:12 -080078 sensorOffsets.range = _env->GetFieldID(sensorClass, "mMaxRange", "F");
79 sensorOffsets.resolution = _env->GetFieldID(sensorClass, "mResolution","F");
80 sensorOffsets.power = _env->GetFieldID(sensorClass, "mPower", "F");
81 sensorOffsets.minDelay = _env->GetFieldID(sensorClass, "mMinDelay", "I");
Aravind Akellab4c76b12013-06-27 12:04:16 -070082 sensorOffsets.fifoReservedEventCount =
83 _env->GetFieldID(sensorClass, "mFifoReservedEventCount", "I");
84 sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount", "I");
Aravind Akellacd9a7bb2014-04-07 22:55:21 +000085 sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
86 sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
87 "Ljava/lang/String;");
Aravind Akella2f8b9142014-05-12 14:39:29 -070088 sensorOffsets.maxDelay = _env->GetFieldID(sensorClass, "mMaxDelay", "I");
Aravind Akella27900352014-06-03 19:20:42 -070089 sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags", "I");
destradaa9ba7c1c2015-02-10 15:04:43 -080090 sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
91}
92
93/**
94 * A key comparator predicate.
95 * It is used to intern strings associated with Sensor data.
96 * It defines a 'Strict weak ordering' for the interned strings.
97 */
98class InternedStringCompare {
99public:
100 bool operator()(const String8* string1, const String8* string2) const {
101 if (string1 == NULL) {
102 return string2 != NULL;
103 }
Aravind Akella88445992015-02-26 17:05:28 -0800104 if (string2 == NULL) {
105 return false;
106 }
destradaa9ba7c1c2015-02-10 15:04:43 -0800107 return string1->compare(*string2) < 0;
108 }
109};
110
111/**
112 * A localized interning mechanism for Sensor strings.
113 * We implement our own interning to avoid the overhead of using java.lang.String#intern().
114 * It is common that Vendor, StringType, and RequirePermission data is common between many of the
115 * Sensors, by interning the memory usage to represent Sensors is optimized.
116 */
117static jstring
118getInternedString(JNIEnv *env, const String8* string) {
119 static std::map<const String8*, jstring, InternedStringCompare> internedStrings;
120
121 jstring internedString;
122 std::map<const String8*, jstring>::iterator iterator = internedStrings.find(string);
123 if (iterator != internedStrings.end()) {
124 internedString = iterator->second;
125 } else {
126 jstring localString = env->NewStringUTF(string->string());
127 // we are implementing our own interning so expect these strings to be backed by global refs
128 internedString = (jstring) env->NewGlobalRef(localString);
129 internedStrings.insert(std::make_pair(string, internedString));
130 env->DeleteLocalRef(localString);
131 }
132
133 return internedString;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134}
135
136static jint
Mathias Agopiandb772d82013-01-31 19:31:12 -0800137nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138{
Mathias Agopian1bf79782010-07-14 23:41:37 -0700139 SensorManager& mgr(SensorManager::getInstance());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140
Mathias Agopian1bf79782010-07-14 23:41:37 -0700141 Sensor const* const* sensorList;
142 size_t count = mgr.getSensorList(&sensorList);
destradaa9ba7c1c2015-02-10 15:04:43 -0800143 if (size_t(next) >= count) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 return -1;
destradaa9ba7c1c2015-02-10 15:04:43 -0800145 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700146
Mathias Agopian1bf79782010-07-14 23:41:37 -0700147 Sensor const* const list = sensorList[next];
148 const SensorOffsets& sensorOffsets(gSensorOffsets);
destradaa9ba7c1c2015-02-10 15:04:43 -0800149 jstring name = getInternedString(env, &list->getName());
150 jstring vendor = getInternedString(env, &list->getVendor());
151 jstring requiredPermission = getInternedString(env, &list->getRequiredPermission());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 env->SetObjectField(sensor, sensorOffsets.name, name);
153 env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
Mathias Agopian277d1b22012-05-04 15:51:29 -0700154 env->SetIntField(sensor, sensorOffsets.version, list->getVersion());
Mathias Agopian1bf79782010-07-14 23:41:37 -0700155 env->SetIntField(sensor, sensorOffsets.handle, list->getHandle());
Mathias Agopian1bf79782010-07-14 23:41:37 -0700156 env->SetFloatField(sensor, sensorOffsets.range, list->getMaxValue());
157 env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
158 env->SetFloatField(sensor, sensorOffsets.power, list->getPowerUsage());
Mathias Agopian050b5622010-07-29 16:51:38 -0700159 env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay());
Aravind Akellab4c76b12013-06-27 12:04:16 -0700160 env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
161 list->getFifoReservedEventCount());
Aravind Akellacd9a7bb2014-04-07 22:55:21 +0000162 env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
163 list->getFifoMaxEventCount());
Aravind Akellacd9a7bb2014-04-07 22:55:21 +0000164 env->SetObjectField(sensor, sensorOffsets.requiredPermission,
165 requiredPermission);
Aravind Akella2f8b9142014-05-12 14:39:29 -0700166 env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
Aravind Akella27900352014-06-03 19:20:42 -0700167 env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
destradaa9ba7c1c2015-02-10 15:04:43 -0800168 if (env->CallBooleanMethod(sensor, sensorOffsets.setType, list->getType()) == JNI_FALSE) {
169 jstring stringType = getInternedString(env, &list->getStringType());
170 env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 next++;
Jeff Brown4fe6c3e2010-09-13 23:17:30 -0700173 return size_t(next) < count ? next : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174}
175
176//----------------------------------------------------------------------------
Mathias Agopiandb772d82013-01-31 19:31:12 -0800177
178class Receiver : public LooperCallback {
179 sp<SensorEventQueue> mSensorQueue;
180 sp<MessageQueue> mMessageQueue;
181 jobject mReceiverObject;
182 jfloatArray mScratch;
183public:
184 Receiver(const sp<SensorEventQueue>& sensorQueue,
185 const sp<MessageQueue>& messageQueue,
186 jobject receiverObject, jfloatArray scratch) {
187 JNIEnv* env = AndroidRuntime::getJNIEnv();
188 mSensorQueue = sensorQueue;
189 mMessageQueue = messageQueue;
190 mReceiverObject = env->NewGlobalRef(receiverObject);
191 mScratch = (jfloatArray)env->NewGlobalRef(scratch);
192 }
193 ~Receiver() {
194 JNIEnv* env = AndroidRuntime::getJNIEnv();
195 env->DeleteGlobalRef(mReceiverObject);
196 env->DeleteGlobalRef(mScratch);
197 }
198 sp<SensorEventQueue> getSensorEventQueue() const {
199 return mSensorQueue;
200 }
201
202 void destroy() {
203 mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
204 }
205
206private:
207 virtual void onFirstRef() {
208 LooperCallback::onFirstRef();
209 mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
210 ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
211 }
212
213 virtual int handleEvent(int fd, int events, void* data) {
214 JNIEnv* env = AndroidRuntime::getJNIEnv();
215 sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data);
216 ssize_t n;
217 ASensorEvent buffer[16];
218 while ((n = q->read(buffer, 16)) > 0) {
219 for (int i=0 ; i<n ; i++) {
Aravind Akella0288ca62014-07-28 14:53:44 -0700220 if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
Jean-Baptiste Queru3c9c0912013-08-05 11:03:28 -0700221 // step-counter returns a uint64, but the java API only deals with floats
222 float value = float(buffer[i].u64.step_counter);
223 env->SetFloatArrayRegion(mScratch, 0, 1, &value);
224 } else {
225 env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data);
226 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800227
Aravind Akellab4c76b12013-06-27 12:04:16 -0700228 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
229 // This is a flush complete sensor event. Call dispatchFlushCompleteEvent
230 // method.
231 env->CallVoidMethod(mReceiverObject,
232 gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
233 buffer[i].meta_data.sensor);
234 } else {
Etienne Le Grandaf805102014-05-16 12:21:41 -0700235 int8_t status;
236 switch (buffer[i].type) {
237 case SENSOR_TYPE_ORIENTATION:
238 case SENSOR_TYPE_MAGNETIC_FIELD:
239 case SENSOR_TYPE_ACCELEROMETER:
240 case SENSOR_TYPE_GYROSCOPE:
241 status = buffer[i].vector.status;
242 break;
243 case SENSOR_TYPE_HEART_RATE:
244 status = buffer[i].heart_rate.status;
245 break;
246 default:
247 status = SENSOR_STATUS_ACCURACY_HIGH;
248 break;
249 }
Aravind Akellab4c76b12013-06-27 12:04:16 -0700250 env->CallVoidMethod(mReceiverObject,
251 gBaseEventQueueClassInfo.dispatchSensorEvent,
252 buffer[i].sensor,
253 mScratch,
Etienne Le Grandaf805102014-05-16 12:21:41 -0700254 status,
Aravind Akellab4c76b12013-06-27 12:04:16 -0700255 buffer[i].timestamp);
256 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800257 if (env->ExceptionCheck()) {
Aravind Akella35187bd2014-02-11 18:44:42 -0800258 mSensorQueue->sendAck(buffer, n);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800259 ALOGE("Exception dispatching input event.");
260 return 1;
261 }
262 }
Aravind Akella35187bd2014-02-11 18:44:42 -0800263 mSensorQueue->sendAck(buffer, n);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800264 }
265 if (n<0 && n != -EAGAIN) {
266 // FIXME: error receiving events, what to do in this case?
267 }
Mathias Agopiandb772d82013-01-31 19:31:12 -0800268 return 1;
269 }
270};
271
Aravind Akella88445992015-02-26 17:05:28 -0800272static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ,
273 jfloatArray scratch, jstring packageName) {
Mathias Agopian1bf79782010-07-14 23:41:37 -0700274 SensorManager& mgr(SensorManager::getInstance());
Aravind Akella88445992015-02-26 17:05:28 -0800275 ScopedUtfChars packageUtf(env, packageName);
276 String8 clientName(packageUtf.c_str());
277 sp<SensorEventQueue> queue(mgr.createEventQueue(clientName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
Mathias Agopiandb772d82013-01-31 19:31:12 -0800279 sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
280 if (messageQueue == NULL) {
281 jniThrowRuntimeException(env, "MessageQueue is not initialized.");
282 return 0;
Mathias Agopian0b6d77b2012-05-07 18:27:06 -0700283 }
Mathias Agopian1bf79782010-07-14 23:41:37 -0700284
Mathias Agopiandb772d82013-01-31 19:31:12 -0800285 sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800286 receiver->incStrong((void*)nativeInitSensorEventQueue);
Ashok Bhat4838e332014-01-03 14:37:19 +0000287 return jlong(receiver.get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288}
289
Ashok Bhat4838e332014-01-03 14:37:19 +0000290static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
Aravind Akella88445992015-02-26 17:05:28 -0800291 jint maxBatchReportLatency) {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800292 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
Aravind Akella88445992015-02-26 17:05:28 -0800293
Aravind Akellab4c76b12013-06-27 12:04:16 -0700294 return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
Aravind Akella88445992015-02-26 17:05:28 -0800295 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296}
297
Ashok Bhat4838e332014-01-03 14:37:19 +0000298static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800299 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
300 return receiver->getSensorEventQueue()->disableSensor(handle);
301}
Mathias Agopian1bf79782010-07-14 23:41:37 -0700302
Ashok Bhat4838e332014-01-03 14:37:19 +0000303static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
Mathias Agopiandb772d82013-01-31 19:31:12 -0800304 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
305 receiver->destroy();
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800306 receiver->decStrong((void*)nativeInitSensorEventQueue);
Mathias Agopiandb772d82013-01-31 19:31:12 -0800307}
Mathias Agopian1bf79782010-07-14 23:41:37 -0700308
Ashok Bhat4838e332014-01-03 14:37:19 +0000309static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
Aravind Akellab4c76b12013-06-27 12:04:16 -0700310 sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
Aravind Akella4bdc37d2013-10-01 17:58:35 -0700311 return receiver->getSensorEventQueue()->flush();
Aravind Akellab4c76b12013-06-27 12:04:16 -0700312}
Mathias Agopiandb772d82013-01-31 19:31:12 -0800313
314//----------------------------------------------------------------------------
315
316static JNINativeMethod gSystemSensorManagerMethods[] = {
317 {"nativeClassInit",
318 "()V",
319 (void*)nativeClassInit },
320
321 {"nativeGetNextSensor",
322 "(Landroid/hardware/Sensor;I)I",
323 (void*)nativeGetNextSensor },
324};
325
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800326static JNINativeMethod gBaseEventQueueMethods[] = {
327 {"nativeInitBaseEventQueue",
Aravind Akella88445992015-02-26 17:05:28 -0800328 "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[FLjava/lang/String;)J",
329 (void*)nativeInitSensorEventQueue },
Mathias Agopiandb772d82013-01-31 19:31:12 -0800330
331 {"nativeEnableSensor",
Aravind Akella88445992015-02-26 17:05:28 -0800332 "(JIII)I",
Mathias Agopiandb772d82013-01-31 19:31:12 -0800333 (void*)nativeEnableSensor },
334
335 {"nativeDisableSensor",
Ashok Bhat4838e332014-01-03 14:37:19 +0000336 "(JI)I",
Mathias Agopiandb772d82013-01-31 19:31:12 -0800337 (void*)nativeDisableSensor },
338
339 {"nativeDestroySensorEventQueue",
Ashok Bhat4838e332014-01-03 14:37:19 +0000340 "(J)V",
Mathias Agopiandb772d82013-01-31 19:31:12 -0800341 (void*)nativeDestroySensorEventQueue },
Aravind Akellab4c76b12013-06-27 12:04:16 -0700342
343 {"nativeFlushSensor",
Ashok Bhat4838e332014-01-03 14:37:19 +0000344 "(J)I",
Aravind Akellab4c76b12013-06-27 12:04:16 -0700345 (void*)nativeFlushSensor },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346};
347
348}; // namespace android
349
350using namespace android;
351
352int register_android_hardware_SensorManager(JNIEnv *env)
353{
Andreas Gampe987f79f2014-11-18 17:29:46 -0800354 RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",
Mathias Agopiandb772d82013-01-31 19:31:12 -0800355 gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
356
Andreas Gampe987f79f2014-11-18 17:29:46 -0800357 RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager$BaseEventQueue",
Jaikumar Ganesh9a8df4d2013-02-12 16:31:32 -0800358 gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
Mathias Agopiandb772d82013-01-31 19:31:12 -0800359
Andreas Gampe987f79f2014-11-18 17:29:46 -0800360 gBaseEventQueueClassInfo.clazz = FindClassOrDie(env,
361 "android/hardware/SystemSensorManager$BaseEventQueue");
Mathias Agopiandb772d82013-01-31 19:31:12 -0800362
Andreas Gampe987f79f2014-11-18 17:29:46 -0800363 gBaseEventQueueClassInfo.dispatchSensorEvent = GetMethodIDOrDie(env,
364 gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V");
Mathias Agopiandb772d82013-01-31 19:31:12 -0800365
Andreas Gampe987f79f2014-11-18 17:29:46 -0800366 gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
367 gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
Aravind Akellab4c76b12013-06-27 12:04:16 -0700368
Mathias Agopiandb772d82013-01-31 19:31:12 -0800369 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370}