blob: 93fd54fedddae026ff793bd171380f8157f2c8a2 [file] [log] [blame]
/*
* Copyright (C) 2010 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 "MotionEvent-JNI"
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
#include <ui/Input.h>
#include "android_view_MotionEvent.h"
// Number of float items per entry in a DVM sample data array
#define NUM_SAMPLE_DATA 9
namespace android {
// ----------------------------------------------------------------------------
static struct {
jclass clazz;
jmethodID obtain;
jmethodID recycle;
jfieldID mDeviceId;
jfieldID mSource;
jfieldID mDownTimeNano;
jfieldID mAction;
jfieldID mXOffset;
jfieldID mYOffset;
jfieldID mXPrecision;
jfieldID mYPrecision;
jfieldID mEdgeFlags;
jfieldID mMetaState;
jfieldID mFlags;
jfieldID mNumPointers;
jfieldID mNumSamples;
jfieldID mPointerIdentifiers;
jfieldID mDataSamples;
jfieldID mEventTimeNanoSamples;
jfieldID mLastDataSampleIndex;
jfieldID mLastEventTimeNanoSampleIndex;
} gMotionEventClassInfo;
// ----------------------------------------------------------------------------
jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* event) {
jint numPointers = jint(event->getPointerCount());
jint numHistoricalSamples = jint(event->getHistorySize());
jint numSamples = numHistoricalSamples + 1;
jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,
gMotionEventClassInfo.obtain, numPointers, numSamples);
if (env->ExceptionCheck()) {
LOGE("An exception occurred while obtaining a motion event.");
LOGE_EX(env);
env->ExceptionClear();
return NULL;
}
env->SetIntField(eventObj, gMotionEventClassInfo.mDeviceId,
event->getDeviceId());
env->SetIntField(eventObj, gMotionEventClassInfo.mSource,
event->getSource());
env->SetLongField(eventObj, gMotionEventClassInfo.mDownTimeNano,
event->getDownTime());
env->SetIntField(eventObj, gMotionEventClassInfo.mAction,
event->getAction());
env->SetFloatField(eventObj, gMotionEventClassInfo.mXOffset,
event->getXOffset());
env->SetFloatField(eventObj, gMotionEventClassInfo.mYOffset,
event->getYOffset());
env->SetFloatField(eventObj, gMotionEventClassInfo.mXPrecision,
event->getXPrecision());
env->SetFloatField(eventObj, gMotionEventClassInfo.mYPrecision,
event->getYPrecision());
env->SetIntField(eventObj, gMotionEventClassInfo.mEdgeFlags,
event->getEdgeFlags());
env->SetIntField(eventObj, gMotionEventClassInfo.mMetaState,
event->getMetaState());
env->SetIntField(eventObj, gMotionEventClassInfo.mFlags,
event->getFlags());
env->SetIntField(eventObj, gMotionEventClassInfo.mNumPointers,
numPointers);
env->SetIntField(eventObj, gMotionEventClassInfo.mNumSamples,
numSamples);
env->SetIntField(eventObj, gMotionEventClassInfo.mLastDataSampleIndex,
(numSamples - 1) * numPointers * NUM_SAMPLE_DATA);
env->SetIntField(eventObj, gMotionEventClassInfo.mLastEventTimeNanoSampleIndex,
numSamples - 1);
jintArray pointerIdentifierArray = jintArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mPointerIdentifiers));
jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mDataSamples));
jlongArray eventTimeNanoSampleArray = jlongArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mEventTimeNanoSamples));
jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL);
jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL);
jlong* eventTimeNanoSamples = (jlong*)env->GetPrimitiveArrayCritical(
eventTimeNanoSampleArray, NULL);
const int32_t* srcPointerIdentifiers = event->getPointerIds();
jint* destPointerIdentifiers = pointerIdentifiers;
for (jint i = 0; i < numPointers; i++) {
*(destPointerIdentifiers++) = *(srcPointerIdentifiers++);
}
const nsecs_t* srcSampleEventTimes = event->getSampleEventTimes();
jlong* destEventTimeNanoSamples = eventTimeNanoSamples;
for (jint i = 0; i < numSamples; i++) {
*(destEventTimeNanoSamples++) = *(srcSampleEventTimes++);
}
const PointerCoords* srcSamplePointerCoords = event->getSamplePointerCoords();
jfloat* destDataSamples = dataSamples;
jint numItems = numSamples * numPointers;
for (jint i = 0; i < numItems; i++) {
*(destDataSamples++) = srcSamplePointerCoords->x;
*(destDataSamples++) = srcSamplePointerCoords->y;
*(destDataSamples++) = srcSamplePointerCoords->pressure;
*(destDataSamples++) = srcSamplePointerCoords->size;
*(destDataSamples++) = srcSamplePointerCoords->touchMajor;
*(destDataSamples++) = srcSamplePointerCoords->touchMinor;
*(destDataSamples++) = srcSamplePointerCoords->toolMajor;
*(destDataSamples++) = srcSamplePointerCoords->toolMinor;
*(destDataSamples++) = srcSamplePointerCoords->orientation;
srcSamplePointerCoords += 1;
}
env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, 0);
env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, 0);
env->ReleasePrimitiveArrayCritical(eventTimeNanoSampleArray, eventTimeNanoSamples, 0);
env->DeleteLocalRef(pointerIdentifierArray);
env->DeleteLocalRef(dataSampleArray);
env->DeleteLocalRef(eventTimeNanoSampleArray);
return eventObj;
}
void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
MotionEvent* event) {
jint deviceId = env->GetIntField(eventObj, gMotionEventClassInfo.mDeviceId);
jint source = env->GetIntField(eventObj, gMotionEventClassInfo.mSource);
jlong downTimeNano = env->GetLongField(eventObj, gMotionEventClassInfo.mDownTimeNano);
jint action = env->GetIntField(eventObj, gMotionEventClassInfo.mAction);
jfloat xOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mXOffset);
jfloat yOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mYOffset);
jfloat xPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mXPrecision);
jfloat yPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mYPrecision);
jint edgeFlags = env->GetIntField(eventObj, gMotionEventClassInfo.mEdgeFlags);
jint metaState = env->GetIntField(eventObj, gMotionEventClassInfo.mMetaState);
jint flags = env->GetIntField(eventObj, gMotionEventClassInfo.mFlags);
jint numPointers = env->GetIntField(eventObj, gMotionEventClassInfo.mNumPointers);
jint numSamples = env->GetIntField(eventObj, gMotionEventClassInfo.mNumSamples);
jintArray pointerIdentifierArray = jintArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mPointerIdentifiers));
jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mDataSamples));
jlongArray eventTimeNanoSampleArray = jlongArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mEventTimeNanoSamples));
LOG_FATAL_IF(numPointers == 0, "numPointers was zero");
LOG_FATAL_IF(numSamples == 0, "numSamples was zero");
jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL);
jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL);
jlong* eventTimeNanoSamples = (jlong*)env->GetPrimitiveArrayCritical(
eventTimeNanoSampleArray, NULL);
jfloat* srcDataSamples = dataSamples;
jlong* srcEventTimeNanoSamples = eventTimeNanoSamples;
jlong sampleEventTime = *(srcEventTimeNanoSamples++);
PointerCoords samplePointerCoords[MAX_POINTERS];
for (jint j = 0; j < numPointers; j++) {
samplePointerCoords[j].x = *(srcDataSamples++);
samplePointerCoords[j].y = *(srcDataSamples++);
samplePointerCoords[j].pressure = *(srcDataSamples++);
samplePointerCoords[j].size = *(srcDataSamples++);
samplePointerCoords[j].touchMajor = *(srcDataSamples++);
samplePointerCoords[j].touchMinor = *(srcDataSamples++);
samplePointerCoords[j].toolMajor = *(srcDataSamples++);
samplePointerCoords[j].toolMinor = *(srcDataSamples++);
samplePointerCoords[j].orientation = *(srcDataSamples++);
}
event->initialize(deviceId, source, action, flags, edgeFlags, metaState,
xOffset, yOffset, xPrecision, yPrecision, downTimeNano, sampleEventTime,
numPointers, pointerIdentifiers, samplePointerCoords);
for (jint i = 1; i < numSamples; i++) {
sampleEventTime = *(srcEventTimeNanoSamples++);
for (jint j = 0; j < numPointers; j++) {
samplePointerCoords[j].x = *(srcDataSamples++);
samplePointerCoords[j].y = *(srcDataSamples++);
samplePointerCoords[j].pressure = *(srcDataSamples++);
samplePointerCoords[j].size = *(srcDataSamples++);
samplePointerCoords[j].touchMajor = *(srcDataSamples++);
samplePointerCoords[j].touchMinor = *(srcDataSamples++);
samplePointerCoords[j].toolMajor = *(srcDataSamples++);
samplePointerCoords[j].toolMinor = *(srcDataSamples++);
samplePointerCoords[j].orientation = *(srcDataSamples++);
}
event->addSample(sampleEventTime, samplePointerCoords);
}
env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, JNI_ABORT);
env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, JNI_ABORT);
env->ReleasePrimitiveArrayCritical(eventTimeNanoSampleArray, eventTimeNanoSamples, JNI_ABORT);
env->DeleteLocalRef(pointerIdentifierArray);
env->DeleteLocalRef(dataSampleArray);
env->DeleteLocalRef(eventTimeNanoSampleArray);
}
void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle);
if (env->ExceptionCheck()) {
LOGW("An exception occurred while recycling a motion event.");
LOGW_EX(env);
env->ExceptionClear();
}
}
// ----------------------------------------------------------------------------
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className); \
var = jclass(env->NewGlobalRef(var));
#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find static method" methodName);
#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find method" methodName);
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
int register_android_view_MotionEvent(JNIEnv* env) {
FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz,
"obtain", "(II)Landroid/view/MotionEvent;");
GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
"recycle", "()V");
GET_FIELD_ID(gMotionEventClassInfo.mDeviceId, gMotionEventClassInfo.clazz,
"mDeviceId", "I");
GET_FIELD_ID(gMotionEventClassInfo.mSource, gMotionEventClassInfo.clazz,
"mSource", "I");
GET_FIELD_ID(gMotionEventClassInfo.mDownTimeNano, gMotionEventClassInfo.clazz,
"mDownTimeNano", "J");
GET_FIELD_ID(gMotionEventClassInfo.mAction, gMotionEventClassInfo.clazz,
"mAction", "I");
GET_FIELD_ID(gMotionEventClassInfo.mXOffset, gMotionEventClassInfo.clazz,
"mXOffset", "F");
GET_FIELD_ID(gMotionEventClassInfo.mYOffset, gMotionEventClassInfo.clazz,
"mYOffset", "F");
GET_FIELD_ID(gMotionEventClassInfo.mXPrecision, gMotionEventClassInfo.clazz,
"mXPrecision", "F");
GET_FIELD_ID(gMotionEventClassInfo.mYPrecision, gMotionEventClassInfo.clazz,
"mYPrecision", "F");
GET_FIELD_ID(gMotionEventClassInfo.mEdgeFlags, gMotionEventClassInfo.clazz,
"mEdgeFlags", "I");
GET_FIELD_ID(gMotionEventClassInfo.mMetaState, gMotionEventClassInfo.clazz,
"mMetaState", "I");
GET_FIELD_ID(gMotionEventClassInfo.mFlags, gMotionEventClassInfo.clazz,
"mFlags", "I");
GET_FIELD_ID(gMotionEventClassInfo.mNumPointers, gMotionEventClassInfo.clazz,
"mNumPointers", "I");
GET_FIELD_ID(gMotionEventClassInfo.mNumSamples, gMotionEventClassInfo.clazz,
"mNumSamples", "I");
GET_FIELD_ID(gMotionEventClassInfo.mPointerIdentifiers, gMotionEventClassInfo.clazz,
"mPointerIdentifiers", "[I");
GET_FIELD_ID(gMotionEventClassInfo.mDataSamples, gMotionEventClassInfo.clazz,
"mDataSamples", "[F");
GET_FIELD_ID(gMotionEventClassInfo.mEventTimeNanoSamples, gMotionEventClassInfo.clazz,
"mEventTimeNanoSamples", "[J");
GET_FIELD_ID(gMotionEventClassInfo.mLastDataSampleIndex, gMotionEventClassInfo.clazz,
"mLastDataSampleIndex", "I");
GET_FIELD_ID(gMotionEventClassInfo.mLastEventTimeNanoSampleIndex, gMotionEventClassInfo.clazz,
"mLastEventTimeNanoSampleIndex", "I");
return 0;
}
} // namespace android