| /* |
| * 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 |