| /* |
| * 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 <SkMatrix.h> |
| #include <android_runtime/AndroidRuntime.h> |
| #include <android_runtime/Log.h> |
| #include <utils/Log.h> |
| #include <input/Input.h> |
| #include <ScopedUtfChars.h> |
| #include "android_os_Parcel.h" |
| #include "android_view_MotionEvent.h" |
| #include "android_util_Binder.h" |
| #include "android/graphics/Matrix.h" |
| |
| namespace android { |
| |
| // ---------------------------------------------------------------------------- |
| |
| static struct { |
| jclass clazz; |
| |
| jmethodID obtain; |
| jmethodID recycle; |
| |
| jfieldID mNativePtr; |
| } gMotionEventClassInfo; |
| |
| static struct { |
| jfieldID mPackedAxisBits; |
| jfieldID mPackedAxisValues; |
| jfieldID x; |
| jfieldID y; |
| jfieldID pressure; |
| jfieldID size; |
| jfieldID touchMajor; |
| jfieldID touchMinor; |
| jfieldID toolMajor; |
| jfieldID toolMinor; |
| jfieldID orientation; |
| } gPointerCoordsClassInfo; |
| |
| static struct { |
| jfieldID id; |
| jfieldID toolType; |
| } gPointerPropertiesClassInfo; |
| |
| // ---------------------------------------------------------------------------- |
| |
| MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) { |
| if (!eventObj) { |
| return NULL; |
| } |
| return reinterpret_cast<MotionEvent*>( |
| env->GetLongField(eventObj, gMotionEventClassInfo.mNativePtr)); |
| } |
| |
| static void android_view_MotionEvent_setNativePtr(JNIEnv* env, jobject eventObj, |
| MotionEvent* event) { |
| env->SetLongField(eventObj, gMotionEventClassInfo.mNativePtr, |
| reinterpret_cast<jlong>(event)); |
| } |
| |
| jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent* event) { |
| jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz, |
| gMotionEventClassInfo.obtain); |
| if (env->ExceptionCheck() || !eventObj) { |
| ALOGE("An exception occurred while obtaining a motion event."); |
| LOGE_EX(env); |
| env->ExceptionClear(); |
| return NULL; |
| } |
| |
| MotionEvent* destEvent = android_view_MotionEvent_getNativePtr(env, eventObj); |
| if (!destEvent) { |
| destEvent = new MotionEvent(); |
| android_view_MotionEvent_setNativePtr(env, eventObj, destEvent); |
| } |
| |
| destEvent->copyFrom(event, true); |
| return eventObj; |
| } |
| |
| status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) { |
| env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle); |
| if (env->ExceptionCheck()) { |
| ALOGW("An exception occurred while recycling a motion event."); |
| LOGW_EX(env); |
| env->ExceptionClear(); |
| return UNKNOWN_ERROR; |
| } |
| return OK; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| static const jint HISTORY_CURRENT = -0x80000000; |
| |
| static bool validatePointerCount(JNIEnv* env, jint pointerCount) { |
| if (pointerCount < 1) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "pointerCount must be at least 1"); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool validatePointerPropertiesArray(JNIEnv* env, jobjectArray pointerPropertiesObjArray, |
| size_t pointerCount) { |
| if (!pointerPropertiesObjArray) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "pointerProperties array must not be null"); |
| return false; |
| } |
| size_t length = size_t(env->GetArrayLength(pointerPropertiesObjArray)); |
| if (length < pointerCount) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "pointerProperties array must be large enough to hold all pointers"); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool validatePointerCoordsObjArray(JNIEnv* env, jobjectArray pointerCoordsObjArray, |
| size_t pointerCount) { |
| if (!pointerCoordsObjArray) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "pointerCoords array must not be null"); |
| return false; |
| } |
| size_t length = size_t(env->GetArrayLength(pointerCoordsObjArray)); |
| if (length < pointerCount) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "pointerCoords array must be large enough to hold all pointers"); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool validatePointerIndex(JNIEnv* env, jint pointerIndex, size_t pointerCount) { |
| if (pointerIndex < 0 || size_t(pointerIndex) >= pointerCount) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "pointerIndex out of range"); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool validateHistoryPos(JNIEnv* env, jint historyPos, size_t historySize) { |
| if (historyPos < 0 || size_t(historyPos) >= historySize) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "historyPos out of range"); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool validatePointerCoords(JNIEnv* env, jobject pointerCoordsObj) { |
| if (!pointerCoordsObj) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "pointerCoords must not be null"); |
| return false; |
| } |
| return true; |
| } |
| |
| static bool validatePointerProperties(JNIEnv* env, jobject pointerPropertiesObj) { |
| if (!pointerPropertiesObj) { |
| jniThrowException(env, "java/lang/IllegalArgumentException", |
| "pointerProperties must not be null"); |
| return false; |
| } |
| return true; |
| } |
| |
| static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj, |
| float xOffset, float yOffset, PointerCoords* outRawPointerCoords) { |
| outRawPointerCoords->clear(); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_X, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.x) - xOffset); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_Y, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.y) - yOffset); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.pressure)); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_SIZE, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.size)); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMajor)); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMinor)); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMajor)); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor)); |
| outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, |
| env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation)); |
| |
| BitSet64 bits = |
| BitSet64(env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits)); |
| if (!bits.isEmpty()) { |
| jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj, |
| gPointerCoordsClassInfo.mPackedAxisValues)); |
| if (valuesArray) { |
| jfloat* values = static_cast<jfloat*>( |
| env->GetPrimitiveArrayCritical(valuesArray, NULL)); |
| |
| uint32_t index = 0; |
| do { |
| uint32_t axis = bits.clearFirstMarkedBit(); |
| outRawPointerCoords->setAxisValue(axis, values[index++]); |
| } while (!bits.isEmpty()); |
| |
| env->ReleasePrimitiveArrayCritical(valuesArray, values, JNI_ABORT); |
| env->DeleteLocalRef(valuesArray); |
| } |
| } |
| } |
| |
| static jfloatArray obtainPackedAxisValuesArray(JNIEnv* env, uint32_t minSize, |
| jobject outPointerCoordsObj) { |
| jfloatArray outValuesArray = jfloatArray(env->GetObjectField(outPointerCoordsObj, |
| gPointerCoordsClassInfo.mPackedAxisValues)); |
| if (outValuesArray) { |
| uint32_t size = env->GetArrayLength(outValuesArray); |
| if (minSize <= size) { |
| return outValuesArray; |
| } |
| env->DeleteLocalRef(outValuesArray); |
| } |
| uint32_t size = 8; |
| while (size < minSize) { |
| size *= 2; |
| } |
| outValuesArray = env->NewFloatArray(size); |
| env->SetObjectField(outPointerCoordsObj, |
| gPointerCoordsClassInfo.mPackedAxisValues, outValuesArray); |
| return outValuesArray; |
| } |
| |
| static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointerCoords, |
| float xOffset, float yOffset, jobject outPointerCoordsObj) { |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.x, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset); |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.y, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset); |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.pressure, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.size, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_SIZE)); |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.touchMajor, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR)); |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.touchMinor, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR)); |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.toolMajor, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR)); |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.toolMinor, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR)); |
| env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.orientation, |
| rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); |
| |
| uint64_t outBits = 0; |
| BitSet64 bits = BitSet64(rawPointerCoords->bits); |
| bits.clearBit(AMOTION_EVENT_AXIS_X); |
| bits.clearBit(AMOTION_EVENT_AXIS_Y); |
| bits.clearBit(AMOTION_EVENT_AXIS_PRESSURE); |
| bits.clearBit(AMOTION_EVENT_AXIS_SIZE); |
| bits.clearBit(AMOTION_EVENT_AXIS_TOUCH_MAJOR); |
| bits.clearBit(AMOTION_EVENT_AXIS_TOUCH_MINOR); |
| bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MAJOR); |
| bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MINOR); |
| bits.clearBit(AMOTION_EVENT_AXIS_ORIENTATION); |
| if (!bits.isEmpty()) { |
| uint32_t packedAxesCount = bits.count(); |
| jfloatArray outValuesArray = obtainPackedAxisValuesArray(env, packedAxesCount, |
| outPointerCoordsObj); |
| if (!outValuesArray) { |
| return; // OOM |
| } |
| |
| jfloat* outValues = static_cast<jfloat*>(env->GetPrimitiveArrayCritical( |
| outValuesArray, NULL)); |
| |
| uint32_t index = 0; |
| do { |
| uint32_t axis = bits.clearFirstMarkedBit(); |
| outBits |= BitSet64::valueForBit(axis); |
| outValues[index++] = rawPointerCoords->getAxisValue(axis); |
| } while (!bits.isEmpty()); |
| |
| env->ReleasePrimitiveArrayCritical(outValuesArray, outValues, 0); |
| env->DeleteLocalRef(outValuesArray); |
| } |
| env->SetLongField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits); |
| } |
| |
| static void pointerPropertiesToNative(JNIEnv* env, jobject pointerPropertiesObj, |
| PointerProperties* outPointerProperties) { |
| outPointerProperties->clear(); |
| outPointerProperties->id = env->GetIntField(pointerPropertiesObj, |
| gPointerPropertiesClassInfo.id); |
| outPointerProperties->toolType = env->GetIntField(pointerPropertiesObj, |
| gPointerPropertiesClassInfo.toolType); |
| } |
| |
| static void pointerPropertiesFromNative(JNIEnv* env, const PointerProperties* pointerProperties, |
| jobject outPointerPropertiesObj) { |
| env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.id, |
| pointerProperties->id); |
| env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.toolType, |
| pointerProperties->toolType); |
| } |
| |
| |
| // ---------------------------------------------------------------------------- |
| |
| static jlong android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz, |
| jlong nativePtr, |
| jint deviceId, jint source, jint action, jint flags, jint edgeFlags, |
| jint metaState, jint buttonState, |
| jfloat xOffset, jfloat yOffset, jfloat xPrecision, jfloat yPrecision, |
| jlong downTimeNanos, jlong eventTimeNanos, |
| jint pointerCount, jobjectArray pointerPropertiesObjArray, |
| jobjectArray pointerCoordsObjArray) { |
| if (!validatePointerCount(env, pointerCount) |
| || !validatePointerPropertiesArray(env, pointerPropertiesObjArray, pointerCount) |
| || !validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) { |
| return 0; |
| } |
| |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| if (!event) { |
| event = new MotionEvent(); |
| } |
| |
| PointerProperties pointerProperties[pointerCount]; |
| PointerCoords rawPointerCoords[pointerCount]; |
| |
| for (jint i = 0; i < pointerCount; i++) { |
| jobject pointerPropertiesObj = env->GetObjectArrayElement(pointerPropertiesObjArray, i); |
| if (!pointerPropertiesObj) { |
| goto Error; |
| } |
| pointerPropertiesToNative(env, pointerPropertiesObj, &pointerProperties[i]); |
| env->DeleteLocalRef(pointerPropertiesObj); |
| |
| jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i); |
| if (!pointerCoordsObj) { |
| jniThrowNullPointerException(env, "pointerCoords"); |
| goto Error; |
| } |
| pointerCoordsToNative(env, pointerCoordsObj, xOffset, yOffset, &rawPointerCoords[i]); |
| env->DeleteLocalRef(pointerCoordsObj); |
| } |
| |
| event->initialize(deviceId, source, action, flags, edgeFlags, metaState, buttonState, |
| xOffset, yOffset, xPrecision, yPrecision, |
| downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords); |
| |
| return reinterpret_cast<jlong>(event); |
| |
| Error: |
| if (!nativePtr) { |
| delete event; |
| } |
| return 0; |
| } |
| |
| static jlong android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz, |
| jlong destNativePtr, jlong sourceNativePtr, jboolean keepHistory) { |
| MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr); |
| if (!destEvent) { |
| destEvent = new MotionEvent(); |
| } |
| MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr); |
| destEvent->copyFrom(sourceEvent, keepHistory); |
| return reinterpret_cast<jlong>(destEvent); |
| } |
| |
| static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| delete event; |
| } |
| |
| static void android_view_MotionEvent_nativeAddBatch(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jlong eventTimeNanos, jobjectArray pointerCoordsObjArray, |
| jint metaState) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| size_t pointerCount = event->getPointerCount(); |
| if (!validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) { |
| return; |
| } |
| |
| PointerCoords rawPointerCoords[pointerCount]; |
| |
| for (size_t i = 0; i < pointerCount; i++) { |
| jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i); |
| if (!pointerCoordsObj) { |
| jniThrowNullPointerException(env, "pointerCoords"); |
| return; |
| } |
| pointerCoordsToNative(env, pointerCoordsObj, |
| event->getXOffset(), event->getYOffset(), &rawPointerCoords[i]); |
| env->DeleteLocalRef(pointerCoordsObj); |
| } |
| |
| event->addSample(eventTimeNanos, rawPointerCoords); |
| event->setMetaState(event->getMetaState() | metaState); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetDeviceId(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getDeviceId(); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetSource(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getSource(); |
| } |
| |
| static void android_view_MotionEvent_nativeSetSource(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint source) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| event->setSource(source); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetAction(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getAction(); |
| } |
| |
| static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint action) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| event->setAction(action); |
| } |
| |
| static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->isTouchEvent(); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getFlags(); |
| } |
| |
| static void android_view_MotionEvent_nativeSetFlags(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint flags) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| event->setFlags(flags); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getEdgeFlags(); |
| } |
| |
| static void android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint edgeFlags) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| event->setEdgeFlags(edgeFlags); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getMetaState(); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getButtonState(); |
| } |
| |
| static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jfloat deltaX, jfloat deltaY) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->offsetLocation(deltaX, deltaY); |
| } |
| |
| static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getXOffset(); |
| } |
| |
| static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getYOffset(); |
| } |
| |
| static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getXPrecision(); |
| } |
| |
| static jfloat android_view_MotionEvent_nativeGetYPrecision(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getYPrecision(); |
| } |
| |
| static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return event->getDownTime(); |
| } |
| |
| static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jlong downTimeNanos) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| event->setDownTime(downTimeNanos); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return jint(event->getPointerCount()); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint pointerIndex) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| size_t pointerCount = event->getPointerCount(); |
| if (!validatePointerIndex(env, pointerIndex, pointerCount)) { |
| return -1; |
| } |
| return event->getPointerId(pointerIndex); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint pointerIndex) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| size_t pointerCount = event->getPointerCount(); |
| if (!validatePointerIndex(env, pointerIndex, pointerCount)) { |
| return -1; |
| } |
| return event->getToolType(pointerIndex); |
| } |
| |
| static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint pointerId) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return jint(event->findPointerIndex(pointerId)); |
| } |
| |
| static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz, |
| jlong nativePtr) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| return jint(event->getHistorySize()); |
| } |
| |
| static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint historyPos) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| if (historyPos == HISTORY_CURRENT) { |
| return event->getEventTime(); |
| } else { |
| size_t historySize = event->getHistorySize(); |
| if (!validateHistoryPos(env, historyPos, historySize)) { |
| return 0; |
| } |
| return event->getHistoricalEventTime(historyPos); |
| } |
| } |
| |
| static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| size_t pointerCount = event->getPointerCount(); |
| if (!validatePointerIndex(env, pointerIndex, pointerCount)) { |
| return 0; |
| } |
| |
| if (historyPos == HISTORY_CURRENT) { |
| return event->getRawAxisValue(axis, pointerIndex); |
| } else { |
| size_t historySize = event->getHistorySize(); |
| if (!validateHistoryPos(env, historyPos, historySize)) { |
| return 0; |
| } |
| return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos); |
| } |
| } |
| |
| static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| size_t pointerCount = event->getPointerCount(); |
| if (!validatePointerIndex(env, pointerIndex, pointerCount)) { |
| return 0; |
| } |
| |
| if (historyPos == HISTORY_CURRENT) { |
| return event->getAxisValue(axis, pointerIndex); |
| } else { |
| size_t historySize = event->getHistorySize(); |
| if (!validateHistoryPos(env, historyPos, historySize)) { |
| return 0; |
| } |
| return event->getHistoricalAxisValue(axis, pointerIndex, historyPos); |
| } |
| } |
| |
| static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint pointerIndex, jint historyPos, jobject outPointerCoordsObj) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| size_t pointerCount = event->getPointerCount(); |
| if (!validatePointerIndex(env, pointerIndex, pointerCount) |
| || !validatePointerCoords(env, outPointerCoordsObj)) { |
| return; |
| } |
| |
| const PointerCoords* rawPointerCoords; |
| if (historyPos == HISTORY_CURRENT) { |
| rawPointerCoords = event->getRawPointerCoords(pointerIndex); |
| } else { |
| size_t historySize = event->getHistorySize(); |
| if (!validateHistoryPos(env, historyPos, historySize)) { |
| return; |
| } |
| rawPointerCoords = event->getHistoricalRawPointerCoords(pointerIndex, historyPos); |
| } |
| pointerCoordsFromNative(env, rawPointerCoords, event->getXOffset(), event->getYOffset(), |
| outPointerCoordsObj); |
| } |
| |
| static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jint pointerIndex, jobject outPointerPropertiesObj) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| size_t pointerCount = event->getPointerCount(); |
| if (!validatePointerIndex(env, pointerIndex, pointerCount) |
| || !validatePointerProperties(env, outPointerPropertiesObj)) { |
| return; |
| } |
| |
| const PointerProperties* pointerProperties = event->getPointerProperties(pointerIndex); |
| pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj); |
| } |
| |
| static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jfloat scale) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| event->scale(scale); |
| } |
| |
| static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jobject matrixObj) { |
| SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj); |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| |
| float m[9]; |
| m[0] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleX)); |
| m[1] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewX)); |
| m[2] = SkScalarToFloat(matrix->get(SkMatrix::kMTransX)); |
| m[3] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewY)); |
| m[4] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleY)); |
| m[5] = SkScalarToFloat(matrix->get(SkMatrix::kMTransY)); |
| m[6] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp0)); |
| m[7] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp1)); |
| m[8] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp2)); |
| event->transform(m); |
| } |
| |
| static jlong android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jobject parcelObj) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| if (!event) { |
| event = new MotionEvent(); |
| } |
| |
| Parcel* parcel = parcelForJavaObject(env, parcelObj); |
| |
| status_t status = event->readFromParcel(parcel); |
| if (status) { |
| if (!nativePtr) { |
| delete event; |
| } |
| jniThrowRuntimeException(env, "Failed to read MotionEvent parcel."); |
| return 0; |
| } |
| return reinterpret_cast<jlong>(event); |
| } |
| |
| static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass clazz, |
| jlong nativePtr, jobject parcelObj) { |
| MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); |
| Parcel* parcel = parcelForJavaObject(env, parcelObj); |
| |
| status_t status = event->writeToParcel(parcel); |
| if (status) { |
| jniThrowRuntimeException(env, "Failed to write MotionEvent parcel."); |
| } |
| } |
| |
| static jstring android_view_MotionEvent_nativeAxisToString(JNIEnv* env, jclass clazz, |
| jint axis) { |
| return env->NewStringUTF(MotionEvent::getLabel(static_cast<int32_t>(axis))); |
| } |
| |
| static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass clazz, |
| jstring label) { |
| ScopedUtfChars axisLabel(env, label); |
| return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str())); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| static JNINativeMethod gMotionEventMethods[] = { |
| /* name, signature, funcPtr */ |
| { "nativeInitialize", |
| "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;" |
| "[Landroid/view/MotionEvent$PointerCoords;)J", |
| (void*)android_view_MotionEvent_nativeInitialize }, |
| { "nativeCopy", |
| "(JJZ)J", |
| (void*)android_view_MotionEvent_nativeCopy }, |
| { "nativeDispose", |
| "(J)V", |
| (void*)android_view_MotionEvent_nativeDispose }, |
| { "nativeAddBatch", |
| "(JJ[Landroid/view/MotionEvent$PointerCoords;I)V", |
| (void*)android_view_MotionEvent_nativeAddBatch }, |
| { "nativeGetDeviceId", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetDeviceId }, |
| { "nativeGetSource", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetSource }, |
| { "nativeSetSource", |
| "(JI)I", |
| (void*)android_view_MotionEvent_nativeSetSource }, |
| { "nativeGetAction", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetAction }, |
| { "nativeSetAction", |
| "(JI)V", |
| (void*)android_view_MotionEvent_nativeSetAction }, |
| { "nativeIsTouchEvent", |
| "(J)Z", |
| (void*)android_view_MotionEvent_nativeIsTouchEvent }, |
| { "nativeGetFlags", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetFlags }, |
| { "nativeSetFlags", |
| "(JI)V", |
| (void*)android_view_MotionEvent_nativeSetFlags }, |
| { "nativeGetEdgeFlags", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetEdgeFlags }, |
| { "nativeSetEdgeFlags", |
| "(JI)V", |
| (void*)android_view_MotionEvent_nativeSetEdgeFlags }, |
| { "nativeGetMetaState", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetMetaState }, |
| { "nativeGetButtonState", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetButtonState }, |
| { "nativeOffsetLocation", |
| "(JFF)V", |
| (void*)android_view_MotionEvent_nativeOffsetLocation }, |
| { "nativeGetXOffset", |
| "(J)F", |
| (void*)android_view_MotionEvent_nativeGetXOffset }, |
| { "nativeGetYOffset", |
| "(J)F", |
| (void*)android_view_MotionEvent_nativeGetYOffset }, |
| { "nativeGetXPrecision", |
| "(J)F", |
| (void*)android_view_MotionEvent_nativeGetXPrecision }, |
| { "nativeGetYPrecision", |
| "(J)F", |
| (void*)android_view_MotionEvent_nativeGetYPrecision }, |
| { "nativeGetDownTimeNanos", |
| "(J)J", |
| (void*)android_view_MotionEvent_nativeGetDownTimeNanos }, |
| { "nativeSetDownTimeNanos", |
| "(JJ)V", |
| (void*)android_view_MotionEvent_nativeSetDownTimeNanos }, |
| { "nativeGetPointerCount", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetPointerCount }, |
| { "nativeGetPointerId", |
| "(JI)I", |
| (void*)android_view_MotionEvent_nativeGetPointerId }, |
| { "nativeGetToolType", |
| "(JI)I", |
| (void*)android_view_MotionEvent_nativeGetToolType }, |
| { "nativeFindPointerIndex", |
| "(JI)I", |
| (void*)android_view_MotionEvent_nativeFindPointerIndex }, |
| { "nativeGetHistorySize", |
| "(J)I", |
| (void*)android_view_MotionEvent_nativeGetHistorySize }, |
| { "nativeGetEventTimeNanos", |
| "(JI)J", |
| (void*)android_view_MotionEvent_nativeGetEventTimeNanos }, |
| { "nativeGetRawAxisValue", |
| "(JIII)F", |
| (void*)android_view_MotionEvent_nativeGetRawAxisValue }, |
| { "nativeGetAxisValue", |
| "(JIII)F", |
| (void*)android_view_MotionEvent_nativeGetAxisValue }, |
| { "nativeGetPointerCoords", |
| "(JIILandroid/view/MotionEvent$PointerCoords;)V", |
| (void*)android_view_MotionEvent_nativeGetPointerCoords }, |
| { "nativeGetPointerProperties", |
| "(JILandroid/view/MotionEvent$PointerProperties;)V", |
| (void*)android_view_MotionEvent_nativeGetPointerProperties }, |
| { "nativeScale", |
| "(JF)V", |
| (void*)android_view_MotionEvent_nativeScale }, |
| { "nativeTransform", |
| "(JLandroid/graphics/Matrix;)V", |
| (void*)android_view_MotionEvent_nativeTransform }, |
| { "nativeReadFromParcel", |
| "(JLandroid/os/Parcel;)J", |
| (void*)android_view_MotionEvent_nativeReadFromParcel }, |
| { "nativeWriteToParcel", |
| "(JLandroid/os/Parcel;)V", |
| (void*)android_view_MotionEvent_nativeWriteToParcel }, |
| { "nativeAxisToString", "(I)Ljava/lang/String;", |
| (void*)android_view_MotionEvent_nativeAxisToString }, |
| { "nativeAxisFromString", "(Ljava/lang/String;)I", |
| (void*)android_view_MotionEvent_nativeAxisFromString }, |
| }; |
| |
| #define FIND_CLASS(var, className) \ |
| var = env->FindClass(className); \ |
| LOG_FATAL_IF(! var, "Unable to find class " className); |
| |
| #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) { |
| int res = jniRegisterNativeMethods(env, "android/view/MotionEvent", |
| gMotionEventMethods, NELEM(gMotionEventMethods)); |
| LOG_FATAL_IF(res < 0, "Unable to register native methods."); |
| (void)res; |
| |
| FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent"); |
| gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz)); |
| |
| GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz, |
| "obtain", "()Landroid/view/MotionEvent;"); |
| GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz, |
| "recycle", "()V"); |
| GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz, |
| "mNativePtr", "J"); |
| |
| jclass clazz; |
| FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords"); |
| |
| GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz, |
| "mPackedAxisBits", "J"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz, |
| "mPackedAxisValues", "[F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz, |
| "x", "F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz, |
| "y", "F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz, |
| "pressure", "F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz, |
| "size", "F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz, |
| "touchMajor", "F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz, |
| "touchMinor", "F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz, |
| "toolMajor", "F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz, |
| "toolMinor", "F"); |
| GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz, |
| "orientation", "F"); |
| |
| FIND_CLASS(clazz, "android/view/MotionEvent$PointerProperties"); |
| |
| GET_FIELD_ID(gPointerPropertiesClassInfo.id, clazz, |
| "id", "I"); |
| GET_FIELD_ID(gPointerPropertiesClassInfo.toolType, clazz, |
| "toolType", "I"); |
| |
| return 0; |
| } |
| |
| } // namespace android |