309 lines
14 KiB
C++
309 lines
14 KiB
C++
|
/*
|
||
|
* 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
|