/*
|
* Copyright 2008, The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
#define LOG_TAG "SensorManager"
|
|
#include <nativehelper/JNIHelp.h>
|
#include "android_os_MessageQueue.h"
|
#include "core_jni_helpers.h"
|
#include "jni.h"
|
|
#include <nativehelper/ScopedUtfChars.h>
|
#include <nativehelper/ScopedLocalRef.h>
|
#include <android_runtime/AndroidRuntime.h>
|
#include <android_runtime/android_hardware_HardwareBuffer.h>
|
#include <vndk/hardware_buffer.h>
|
#include <sensor/Sensor.h>
|
#include <sensor/SensorEventQueue.h>
|
#include <sensor/SensorManager.h>
|
#include <cutils/native_handle.h>
|
#include <utils/Log.h>
|
#include <utils/Looper.h>
|
#include <utils/Vector.h>
|
|
#include <map>
|
|
namespace {
|
|
using namespace android;
|
|
struct {
|
jclass clazz;
|
jmethodID dispatchSensorEvent;
|
jmethodID dispatchFlushCompleteEvent;
|
jmethodID dispatchAdditionalInfoEvent;
|
} gBaseEventQueueClassInfo;
|
|
struct SensorOffsets
|
{
|
jclass clazz;
|
//fields
|
jfieldID name;
|
jfieldID vendor;
|
jfieldID version;
|
jfieldID handle;
|
jfieldID range;
|
jfieldID resolution;
|
jfieldID power;
|
jfieldID minDelay;
|
jfieldID fifoReservedEventCount;
|
jfieldID fifoMaxEventCount;
|
jfieldID stringType;
|
jfieldID requiredPermission;
|
jfieldID maxDelay;
|
jfieldID flags;
|
//methods
|
jmethodID setType;
|
jmethodID setUuid;
|
jmethodID init;
|
} gSensorOffsets;
|
|
struct ListOffsets {
|
jclass clazz;
|
jmethodID add;
|
} gListOffsets;
|
|
struct StringOffsets {
|
jclass clazz;
|
jmethodID intern;
|
jstring emptyString;
|
} gStringOffsets;
|
|
/*
|
* nativeClassInit is not inteneded to be thread-safe. It should be called before other native...
|
* functions (except nativeCreate).
|
*/
|
static void
|
nativeClassInit (JNIEnv *_env, jclass _this)
|
{
|
//android.hardware.Sensor
|
SensorOffsets& sensorOffsets = gSensorOffsets;
|
jclass sensorClass = (jclass)
|
MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "android/hardware/Sensor"));
|
sensorOffsets.clazz = sensorClass;
|
sensorOffsets.name = GetFieldIDOrDie(_env, sensorClass, "mName", "Ljava/lang/String;");
|
sensorOffsets.vendor = GetFieldIDOrDie(_env, sensorClass, "mVendor", "Ljava/lang/String;");
|
sensorOffsets.version = GetFieldIDOrDie(_env, sensorClass, "mVersion", "I");
|
sensorOffsets.handle = GetFieldIDOrDie(_env, sensorClass, "mHandle", "I");
|
sensorOffsets.range = GetFieldIDOrDie(_env, sensorClass, "mMaxRange", "F");
|
sensorOffsets.resolution = GetFieldIDOrDie(_env, sensorClass, "mResolution","F");
|
sensorOffsets.power = GetFieldIDOrDie(_env, sensorClass, "mPower", "F");
|
sensorOffsets.minDelay = GetFieldIDOrDie(_env, sensorClass, "mMinDelay", "I");
|
sensorOffsets.fifoReservedEventCount =
|
GetFieldIDOrDie(_env,sensorClass, "mFifoReservedEventCount", "I");
|
sensorOffsets.fifoMaxEventCount = GetFieldIDOrDie(_env,sensorClass, "mFifoMaxEventCount", "I");
|
sensorOffsets.stringType =
|
GetFieldIDOrDie(_env,sensorClass, "mStringType", "Ljava/lang/String;");
|
sensorOffsets.requiredPermission =
|
GetFieldIDOrDie(_env,sensorClass, "mRequiredPermission", "Ljava/lang/String;");
|
sensorOffsets.maxDelay = GetFieldIDOrDie(_env,sensorClass, "mMaxDelay", "I");
|
sensorOffsets.flags = GetFieldIDOrDie(_env,sensorClass, "mFlags", "I");
|
|
sensorOffsets.setType = GetMethodIDOrDie(_env,sensorClass, "setType", "(I)Z");
|
sensorOffsets.setUuid = GetMethodIDOrDie(_env,sensorClass, "setUuid", "(JJ)V");
|
sensorOffsets.init = GetMethodIDOrDie(_env,sensorClass, "<init>", "()V");
|
|
// java.util.List;
|
ListOffsets& listOffsets = gListOffsets;
|
jclass listClass = (jclass) MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "java/util/List"));
|
listOffsets.clazz = listClass;
|
listOffsets.add = GetMethodIDOrDie(_env,listClass, "add", "(Ljava/lang/Object;)Z");
|
|
// initialize java.lang.String and empty string intern
|
StringOffsets& stringOffsets = gStringOffsets;
|
stringOffsets.clazz = MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "java/lang/String"));
|
stringOffsets.intern =
|
GetMethodIDOrDie(_env, stringOffsets.clazz, "intern", "()Ljava/lang/String;");
|
ScopedLocalRef<jstring> empty(_env, _env->NewStringUTF(""));
|
stringOffsets.emptyString = (jstring)
|
MakeGlobalRefOrDie(_env, _env->CallObjectMethod(empty.get(), stringOffsets.intern));
|
}
|
|
static jstring getJavaInternedString(JNIEnv *env, const String8 &string) {
|
if (string == "") {
|
return gStringOffsets.emptyString;
|
}
|
|
ScopedLocalRef<jstring> javaString(env, env->NewStringUTF(string.string()));
|
jstring internedString = (jstring)
|
env->CallObjectMethod(javaString.get(), gStringOffsets.intern);
|
return internedString;
|
}
|
|
static jlong
|
nativeCreate
|
(JNIEnv *env, jclass clazz, jstring opPackageName)
|
{
|
ScopedUtfChars opPackageNameUtf(env, opPackageName);
|
return (jlong) &SensorManager::getInstanceForPackage(String16(opPackageNameUtf.c_str()));
|
}
|
|
static jobject
|
translateNativeSensorToJavaSensor(JNIEnv *env, jobject sensor, const Sensor& nativeSensor) {
|
const SensorOffsets& sensorOffsets(gSensorOffsets);
|
|
if (sensor == NULL) {
|
// Sensor sensor = new Sensor();
|
sensor = env->NewObject(sensorOffsets.clazz, sensorOffsets.init, "");
|
}
|
|
if (sensor != NULL) {
|
jstring name = getJavaInternedString(env, nativeSensor.getName());
|
jstring vendor = getJavaInternedString(env, nativeSensor.getVendor());
|
jstring requiredPermission =
|
getJavaInternedString(env, nativeSensor.getRequiredPermission());
|
|
env->SetObjectField(sensor, sensorOffsets.name, name);
|
env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
|
env->SetIntField(sensor, sensorOffsets.version, nativeSensor.getVersion());
|
env->SetIntField(sensor, sensorOffsets.handle, nativeSensor.getHandle());
|
env->SetFloatField(sensor, sensorOffsets.range, nativeSensor.getMaxValue());
|
env->SetFloatField(sensor, sensorOffsets.resolution, nativeSensor.getResolution());
|
env->SetFloatField(sensor, sensorOffsets.power, nativeSensor.getPowerUsage());
|
env->SetIntField(sensor, sensorOffsets.minDelay, nativeSensor.getMinDelay());
|
env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
|
nativeSensor.getFifoReservedEventCount());
|
env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
|
nativeSensor.getFifoMaxEventCount());
|
env->SetObjectField(sensor, sensorOffsets.requiredPermission,
|
requiredPermission);
|
env->SetIntField(sensor, sensorOffsets.maxDelay, nativeSensor.getMaxDelay());
|
env->SetIntField(sensor, sensorOffsets.flags, nativeSensor.getFlags());
|
|
if (env->CallBooleanMethod(sensor, sensorOffsets.setType, nativeSensor.getType())
|
== JNI_FALSE) {
|
jstring stringType = getJavaInternedString(env, nativeSensor.getStringType());
|
env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
|
}
|
|
// TODO(b/29547335): Rename "setUuid" method to "setId".
|
int64_t id = nativeSensor.getId();
|
env->CallVoidMethod(sensor, sensorOffsets.setUuid, id, 0);
|
}
|
return sensor;
|
}
|
|
static jboolean
|
nativeGetSensorAtIndex(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensor, jint index)
|
{
|
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
|
Sensor const* const* sensorList;
|
ssize_t count = mgr->getSensorList(&sensorList);
|
if (ssize_t(index) >= count) {
|
return false;
|
}
|
|
return translateNativeSensorToJavaSensor(env, sensor, *sensorList[index]) != NULL;
|
}
|
|
static void
|
nativeGetDynamicSensors(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensorList) {
|
|
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
const ListOffsets& listOffsets(gListOffsets);
|
|
Vector<Sensor> nativeList;
|
|
mgr->getDynamicSensorList(nativeList);
|
|
ALOGI("DYNS native SensorManager.getDynamicSensorList return %zu sensors", nativeList.size());
|
for (size_t i = 0; i < nativeList.size(); ++i) {
|
jobject sensor = translateNativeSensorToJavaSensor(env, NULL, nativeList[i]);
|
// add to list
|
env->CallBooleanMethod(sensorList, listOffsets.add, sensor);
|
}
|
}
|
|
static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
|
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
return mgr->isDataInjectionEnabled();
|
}
|
|
static jint nativeCreateDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
|
jlong size, jint channelType, jint fd, jobject hardwareBufferObj) {
|
const native_handle_t *nativeHandle = nullptr;
|
NATIVE_HANDLE_DECLARE_STORAGE(ashmemHandle, 1, 0);
|
|
if (channelType == SENSOR_DIRECT_MEM_TYPE_ASHMEM) {
|
native_handle_t *handle = native_handle_init(ashmemHandle, 1, 0);
|
handle->data[0] = fd;
|
nativeHandle = handle;
|
} else if (channelType == SENSOR_DIRECT_MEM_TYPE_GRALLOC) {
|
AHardwareBuffer *hardwareBuffer =
|
android_hardware_HardwareBuffer_getNativeHardwareBuffer(_env, hardwareBufferObj);
|
if (hardwareBuffer != nullptr) {
|
nativeHandle = AHardwareBuffer_getNativeHandle(hardwareBuffer);
|
}
|
}
|
|
if (nativeHandle == nullptr) {
|
return BAD_VALUE;
|
}
|
|
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
return mgr->createDirectChannel(size, channelType, nativeHandle);
|
}
|
|
static void nativeDestroyDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
|
jint channelHandle) {
|
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
mgr->destroyDirectChannel(channelHandle);
|
}
|
|
static jint nativeConfigDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
|
jint channelHandle, jint sensorHandle, jint rate) {
|
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
return mgr->configureDirectChannel(channelHandle, sensorHandle, rate);
|
}
|
|
static jint nativeSetOperationParameter(JNIEnv *_env, jclass _this, jlong sensorManager,
|
jint handle, jint type, jfloatArray floats, jintArray ints) {
|
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
Vector<float> floatVector;
|
Vector<int32_t> int32Vector;
|
|
if (floats != nullptr) {
|
floatVector.resize(_env->GetArrayLength(floats));
|
_env->GetFloatArrayRegion(floats, 0, _env->GetArrayLength(floats), floatVector.editArray());
|
}
|
|
if (ints != nullptr) {
|
int32Vector.resize(_env->GetArrayLength(ints));
|
_env->GetIntArrayRegion(ints, 0, _env->GetArrayLength(ints), int32Vector.editArray());
|
}
|
|
return mgr->setOperationParameter(handle, type, floatVector, int32Vector);
|
}
|
|
//----------------------------------------------------------------------------
|
|
class Receiver : public LooperCallback {
|
sp<SensorEventQueue> mSensorQueue;
|
sp<MessageQueue> mMessageQueue;
|
jobject mReceiverWeakGlobal;
|
jfloatArray mFloatScratch;
|
jintArray mIntScratch;
|
public:
|
Receiver(const sp<SensorEventQueue>& sensorQueue,
|
const sp<MessageQueue>& messageQueue,
|
jobject receiverWeak) {
|
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
mSensorQueue = sensorQueue;
|
mMessageQueue = messageQueue;
|
mReceiverWeakGlobal = env->NewGlobalRef(receiverWeak);
|
|
mIntScratch = (jintArray) env->NewGlobalRef(env->NewIntArray(16));
|
mFloatScratch = (jfloatArray) env->NewGlobalRef(env->NewFloatArray(16));
|
}
|
~Receiver() {
|
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
env->DeleteGlobalRef(mReceiverWeakGlobal);
|
env->DeleteGlobalRef(mFloatScratch);
|
env->DeleteGlobalRef(mIntScratch);
|
}
|
sp<SensorEventQueue> getSensorEventQueue() const {
|
return mSensorQueue;
|
}
|
|
void destroy() {
|
mMessageQueue->getLooper()->removeFd( mSensorQueue->getFd() );
|
}
|
|
private:
|
virtual void onFirstRef() {
|
LooperCallback::onFirstRef();
|
mMessageQueue->getLooper()->addFd(mSensorQueue->getFd(), 0,
|
ALOOPER_EVENT_INPUT, this, mSensorQueue.get());
|
}
|
|
virtual int handleEvent(int fd, int events, void* data) {
|
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data);
|
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
|
|
ssize_t n;
|
ASensorEvent buffer[16];
|
while ((n = q->read(buffer, 16)) > 0) {
|
for (int i=0 ; i<n ; i++) {
|
if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
|
// step-counter returns a uint64, but the java API only deals with floats
|
float value = float(buffer[i].u64.step_counter);
|
env->SetFloatArrayRegion(mFloatScratch, 0, 1, &value);
|
} else if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
|
float value[2];
|
value[0] = buffer[i].dynamic_sensor_meta.connected ? 1.f: 0.f;
|
value[1] = float(buffer[i].dynamic_sensor_meta.handle);
|
env->SetFloatArrayRegion(mFloatScratch, 0, 2, value);
|
} else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
|
env->SetIntArrayRegion(mIntScratch, 0, 14,
|
buffer[i].additional_info.data_int32);
|
env->SetFloatArrayRegion(mFloatScratch, 0, 14,
|
buffer[i].additional_info.data_float);
|
} else {
|
env->SetFloatArrayRegion(mFloatScratch, 0, 16, buffer[i].data);
|
}
|
|
if (buffer[i].type == SENSOR_TYPE_META_DATA) {
|
// This is a flush complete sensor event. Call dispatchFlushCompleteEvent
|
// method.
|
if (receiverObj.get()) {
|
env->CallVoidMethod(receiverObj.get(),
|
gBaseEventQueueClassInfo.dispatchFlushCompleteEvent,
|
buffer[i].meta_data.sensor);
|
}
|
} else if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
|
// This is a flush complete sensor event. Call dispatchAdditionalInfoEvent
|
// method.
|
if (receiverObj.get()) {
|
int type = buffer[i].additional_info.type;
|
int serial = buffer[i].additional_info.serial;
|
env->CallVoidMethod(receiverObj.get(),
|
gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent,
|
buffer[i].sensor,
|
type, serial,
|
mFloatScratch,
|
mIntScratch,
|
buffer[i].timestamp);
|
}
|
}else {
|
int8_t status;
|
switch (buffer[i].type) {
|
case SENSOR_TYPE_ORIENTATION:
|
case SENSOR_TYPE_MAGNETIC_FIELD:
|
case SENSOR_TYPE_ACCELEROMETER:
|
case SENSOR_TYPE_GYROSCOPE:
|
case SENSOR_TYPE_GRAVITY:
|
case SENSOR_TYPE_LINEAR_ACCELERATION:
|
status = buffer[i].vector.status;
|
break;
|
case SENSOR_TYPE_HEART_RATE:
|
status = buffer[i].heart_rate.status;
|
break;
|
default:
|
status = SENSOR_STATUS_ACCURACY_HIGH;
|
break;
|
}
|
if (receiverObj.get()) {
|
env->CallVoidMethod(receiverObj.get(),
|
gBaseEventQueueClassInfo.dispatchSensorEvent,
|
buffer[i].sensor,
|
mFloatScratch,
|
status,
|
buffer[i].timestamp);
|
}
|
}
|
if (env->ExceptionCheck()) {
|
mSensorQueue->sendAck(buffer, n);
|
ALOGE("Exception dispatching input event.");
|
return 1;
|
}
|
}
|
mSensorQueue->sendAck(buffer, n);
|
}
|
if (n<0 && n != -EAGAIN) {
|
// FIXME: error receiving events, what to do in this case?
|
}
|
return 1;
|
}
|
};
|
|
static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
|
jobject eventQWeak, jobject msgQ, jstring packageName, jint mode) {
|
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
|
ScopedUtfChars packageUtf(env, packageName);
|
String8 clientName(packageUtf.c_str());
|
sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode));
|
|
if (queue == NULL) {
|
jniThrowRuntimeException(env, "Cannot construct native SensorEventQueue.");
|
return 0;
|
}
|
|
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
|
if (messageQueue == NULL) {
|
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
|
return 0;
|
}
|
|
sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQWeak);
|
receiver->incStrong((void*)nativeInitSensorEventQueue);
|
return jlong(receiver.get());
|
}
|
|
static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
|
jint maxBatchReportLatency) {
|
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
|
return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
|
0);
|
}
|
|
static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
|
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
|
return receiver->getSensorEventQueue()->disableSensor(handle);
|
}
|
|
static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ) {
|
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
|
receiver->destroy();
|
receiver->decStrong((void*)nativeInitSensorEventQueue);
|
}
|
|
static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
|
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
|
return receiver->getSensorEventQueue()->flush();
|
}
|
|
static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint handle,
|
jfloatArray values, jint accuracy, jlong timestamp) {
|
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
|
// Create a sensor_event from the above data which can be injected into the HAL.
|
ASensorEvent sensor_event;
|
memset(&sensor_event, 0, sizeof(sensor_event));
|
sensor_event.sensor = handle;
|
sensor_event.timestamp = timestamp;
|
env->GetFloatArrayRegion(values, 0, env->GetArrayLength(values), sensor_event.data);
|
return receiver->getSensorEventQueue()->injectSensorEvent(sensor_event);
|
}
|
//----------------------------------------------------------------------------
|
|
static const JNINativeMethod gSystemSensorManagerMethods[] = {
|
{"nativeClassInit",
|
"()V",
|
(void*)nativeClassInit },
|
{"nativeCreate",
|
"(Ljava/lang/String;)J",
|
(void*)nativeCreate },
|
|
{"nativeGetSensorAtIndex",
|
"(JLandroid/hardware/Sensor;I)Z",
|
(void*)nativeGetSensorAtIndex },
|
|
{"nativeGetDynamicSensors",
|
"(JLjava/util/List;)V",
|
(void*)nativeGetDynamicSensors },
|
|
{"nativeIsDataInjectionEnabled",
|
"(J)Z",
|
(void*)nativeIsDataInjectionEnabled },
|
|
{"nativeCreateDirectChannel",
|
"(JJIILandroid/hardware/HardwareBuffer;)I",
|
(void*)nativeCreateDirectChannel },
|
|
{"nativeDestroyDirectChannel",
|
"(JI)V",
|
(void*)nativeDestroyDirectChannel },
|
|
{"nativeConfigDirectChannel",
|
"(JIII)I",
|
(void*)nativeConfigDirectChannel },
|
|
{"nativeSetOperationParameter",
|
"(JII[F[I)I",
|
(void*)nativeSetOperationParameter },
|
};
|
|
static const JNINativeMethod gBaseEventQueueMethods[] = {
|
{"nativeInitBaseEventQueue",
|
"(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;Ljava/lang/String;ILjava/lang/String;)J",
|
(void*)nativeInitSensorEventQueue },
|
|
{"nativeEnableSensor",
|
"(JIII)I",
|
(void*)nativeEnableSensor },
|
|
{"nativeDisableSensor",
|
"(JI)I",
|
(void*)nativeDisableSensor },
|
|
{"nativeDestroySensorEventQueue",
|
"(J)V",
|
(void*)nativeDestroySensorEventQueue },
|
|
{"nativeFlushSensor",
|
"(J)I",
|
(void*)nativeFlushSensor },
|
|
{"nativeInjectSensorData",
|
"(JI[FIJ)I",
|
(void*)nativeInjectSensorData },
|
};
|
|
} //unnamed namespace
|
|
int register_android_hardware_SensorManager(JNIEnv *env)
|
{
|
RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager",
|
gSystemSensorManagerMethods, NELEM(gSystemSensorManagerMethods));
|
|
RegisterMethodsOrDie(env, "android/hardware/SystemSensorManager$BaseEventQueue",
|
gBaseEventQueueMethods, NELEM(gBaseEventQueueMethods));
|
|
gBaseEventQueueClassInfo.clazz = FindClassOrDie(env,
|
"android/hardware/SystemSensorManager$BaseEventQueue");
|
|
gBaseEventQueueClassInfo.dispatchSensorEvent = GetMethodIDOrDie(env,
|
gBaseEventQueueClassInfo.clazz, "dispatchSensorEvent", "(I[FIJ)V");
|
|
gBaseEventQueueClassInfo.dispatchFlushCompleteEvent = GetMethodIDOrDie(env,
|
gBaseEventQueueClassInfo.clazz, "dispatchFlushCompleteEvent", "(I)V");
|
|
gBaseEventQueueClassInfo.dispatchAdditionalInfoEvent = GetMethodIDOrDie(env,
|
gBaseEventQueueClassInfo.clazz, "dispatchAdditionalInfoEvent", "(III[F[I)V");
|
|
return 0;
|
}
|