diff options
Diffstat (limited to 'core/jni/android_view_MotionEvent.cpp')
-rw-r--r-- | core/jni/android_view_MotionEvent.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp new file mode 100644 index 0000000..629c8fe --- /dev/null +++ b/core/jni/android_view_MotionEvent.cpp @@ -0,0 +1,310 @@ +/* + * 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 4 + +namespace android { + +// ---------------------------------------------------------------------------- + +static struct { + jclass clazz; + + jmethodID obtain; + jmethodID recycle; + + jfieldID mDownTime; + jfieldID mEventTimeNano; + jfieldID mAction; + jfieldID mRawX; + jfieldID mRawY; + jfieldID mXPrecision; + jfieldID mYPrecision; + jfieldID mDeviceId; + jfieldID mEdgeFlags; + jfieldID mMetaState; + jfieldID mNumPointers; + jfieldID mNumSamples; + jfieldID mPointerIdentifiers; + jfieldID mDataSamples; + jfieldID mTimeSamples; +} 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; + } + + // MotionEvent.mEventTimeNano is the time of the oldest sample because + // MotionEvent.addBatch does not update it as successive samples are added. + jlong eventTimeNano = numHistoricalSamples != 0 + ? event->getHistoricalEventTime(0) + : event->getEventTime(); + + env->SetLongField(eventObj, gMotionEventClassInfo.mDownTime, + nanoseconds_to_milliseconds(event->getDownTime())); + env->SetLongField(eventObj, gMotionEventClassInfo.mEventTimeNano, + eventTimeNano); + env->SetIntField(eventObj, gMotionEventClassInfo.mAction, + event->getAction()); + env->SetFloatField(eventObj, gMotionEventClassInfo.mRawX, + event->getRawX()); + env->SetFloatField(eventObj, gMotionEventClassInfo.mRawY, + event->getRawY()); + env->SetFloatField(eventObj, gMotionEventClassInfo.mXPrecision, + event->getXPrecision()); + env->SetFloatField(eventObj, gMotionEventClassInfo.mYPrecision, + event->getYPrecision()); + env->SetIntField(eventObj, gMotionEventClassInfo.mDeviceId, + event->getDeviceId()); + env->SetIntField(eventObj, gMotionEventClassInfo.mEdgeFlags, + event->getEdgeFlags()); + env->SetIntField(eventObj, gMotionEventClassInfo.mMetaState, + event->getMetaState()); + env->SetIntField(eventObj, gMotionEventClassInfo.mNumPointers, + numPointers); + env->SetIntField(eventObj, gMotionEventClassInfo.mNumSamples, + numSamples); + + jintArray pointerIdentifierArray = jintArray(env->GetObjectField(eventObj, + gMotionEventClassInfo.mPointerIdentifiers)); + jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj, + gMotionEventClassInfo.mDataSamples)); + jlongArray timeSampleArray = jlongArray(env->GetObjectField(eventObj, + gMotionEventClassInfo.mTimeSamples)); + + jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL); + jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL); + jlong* timeSamples = (jlong*)env->GetPrimitiveArrayCritical(timeSampleArray, NULL); + + for (jint i = 0; i < numPointers; i++) { + pointerIdentifiers[i] = event->getPointerId(i); + } + + // Most recent data is in first slot of the DVM array, followed by the oldest, + // and then all others are in order. + + jfloat* currentDataSample = dataSamples; + jlong* currentTimeSample = timeSamples; + + *(currentTimeSample++) = nanoseconds_to_milliseconds(event->getEventTime()); + for (jint j = 0; j < numPointers; j++) { + *(currentDataSample++) = event->getX(j); + *(currentDataSample++) = event->getY(j); + *(currentDataSample++) = event->getPressure(j); + *(currentDataSample++) = event->getSize(j); + } + + for (jint i = 0; i < numHistoricalSamples; i++) { + *(currentTimeSample++) = nanoseconds_to_milliseconds(event->getHistoricalEventTime(i)); + for (jint j = 0; j < numPointers; j++) { + *(currentDataSample++) = event->getHistoricalX(j, i); + *(currentDataSample++) = event->getHistoricalY(j, i); + *(currentDataSample++) = event->getHistoricalPressure(j, i); + *(currentDataSample++) = event->getHistoricalSize(j, i); + } + } + + env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, 0); + env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, 0); + env->ReleasePrimitiveArrayCritical(timeSampleArray, timeSamples, 0); + + env->DeleteLocalRef(pointerIdentifierArray); + env->DeleteLocalRef(dataSampleArray); + env->DeleteLocalRef(timeSampleArray); + return eventObj; +} + +void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, int32_t nature, + MotionEvent* event) { + // MotionEvent.mEventTimeNano is the time of the oldest sample because + // MotionEvent.addBatch does not update it as successive samples are added. + jlong downTime = env->GetLongField(eventObj, gMotionEventClassInfo.mDownTime); + jlong eventTimeNano = env->GetLongField(eventObj, gMotionEventClassInfo.mEventTimeNano); + jint action = env->GetIntField(eventObj, gMotionEventClassInfo.mAction); + jfloat rawX = env->GetFloatField(eventObj, gMotionEventClassInfo.mRawX); + jfloat rawY = env->GetFloatField(eventObj, gMotionEventClassInfo.mRawY); + jfloat xPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mXPrecision); + jfloat yPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mYPrecision); + jint deviceId = env->GetIntField(eventObj, gMotionEventClassInfo.mDeviceId); + jint edgeFlags = env->GetIntField(eventObj, gMotionEventClassInfo.mEdgeFlags); + jint metaState = env->GetIntField(eventObj, gMotionEventClassInfo.mMetaState); + 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 timeSampleArray = jlongArray(env->GetObjectField(eventObj, + gMotionEventClassInfo.mTimeSamples)); + + 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* timeSamples = (jlong*)env->GetPrimitiveArrayCritical(timeSampleArray, NULL); + + // Most recent data is in first slot of the DVM array, followed by the oldest, + // and then all others are in order. eventTimeNano is the time of the oldest sample + // since MotionEvent.addBatch does not update it. + + jint numHistoricalSamples = numSamples - 1; + jint dataSampleStride = numPointers * NUM_SAMPLE_DATA; + + const jfloat* currentDataSample; + const jlong* currentTimeSample; + if (numHistoricalSamples == 0) { + currentDataSample = dataSamples; + currentTimeSample = timeSamples; + } else { + currentDataSample = dataSamples + dataSampleStride; + currentTimeSample = timeSamples + 1; + } + + PointerCoords pointerCoords[MAX_POINTERS]; + for (jint j = 0; j < numPointers; j++) { + pointerCoords[j].x = *(currentDataSample++); + pointerCoords[j].y = *(currentDataSample++); + pointerCoords[j].pressure = *(currentDataSample++); + pointerCoords[j].size = *(currentDataSample++); + } + + event->initialize(deviceId, nature, action, edgeFlags, metaState, + rawX, rawY, xPrecision, yPrecision, + milliseconds_to_nanoseconds(downTime), eventTimeNano, + numPointers, pointerIdentifiers, pointerCoords); + + while (numHistoricalSamples > 0) { + numHistoricalSamples -= 1; + if (numHistoricalSamples == 0) { + currentDataSample = dataSamples; + currentTimeSample = timeSamples; + } + + nsecs_t sampleEventTime = milliseconds_to_nanoseconds(*(currentTimeSample++)); + + for (jint j = 0; j < numPointers; j++) { + pointerCoords[j].x = *(currentDataSample++); + pointerCoords[j].y = *(currentDataSample++); + pointerCoords[j].pressure = *(currentDataSample++); + pointerCoords[j].size = *(currentDataSample++); + } + + event->addSample(sampleEventTime, pointerCoords); + } + + env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, JNI_ABORT); + env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, JNI_ABORT); + env->ReleasePrimitiveArrayCritical(timeSampleArray, timeSamples, JNI_ABORT); + + env->DeleteLocalRef(pointerIdentifierArray); + env->DeleteLocalRef(dataSampleArray); + env->DeleteLocalRef(timeSampleArray); +} + +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.mDownTime, gMotionEventClassInfo.clazz, + "mDownTime", "J"); + GET_FIELD_ID(gMotionEventClassInfo.mEventTimeNano, gMotionEventClassInfo.clazz, + "mEventTimeNano", "J"); + GET_FIELD_ID(gMotionEventClassInfo.mAction, gMotionEventClassInfo.clazz, + "mAction", "I"); + GET_FIELD_ID(gMotionEventClassInfo.mRawX, gMotionEventClassInfo.clazz, + "mRawX", "F"); + GET_FIELD_ID(gMotionEventClassInfo.mRawY, gMotionEventClassInfo.clazz, + "mRawY", "F"); + GET_FIELD_ID(gMotionEventClassInfo.mXPrecision, gMotionEventClassInfo.clazz, + "mXPrecision", "F"); + GET_FIELD_ID(gMotionEventClassInfo.mYPrecision, gMotionEventClassInfo.clazz, + "mYPrecision", "F"); + GET_FIELD_ID(gMotionEventClassInfo.mDeviceId, gMotionEventClassInfo.clazz, + "mDeviceId", "I"); + GET_FIELD_ID(gMotionEventClassInfo.mEdgeFlags, gMotionEventClassInfo.clazz, + "mEdgeFlags", "I"); + GET_FIELD_ID(gMotionEventClassInfo.mMetaState, gMotionEventClassInfo.clazz, + "mMetaState", "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.mTimeSamples, gMotionEventClassInfo.clazz, + "mTimeSamples", "[J"); + + return 0; +} + +} // namespace android |