Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "MotionEvent-JNI"
     18 
     19 #include "JNIHelp.h"
     20 
     21 #include <android_runtime/AndroidRuntime.h>
     22 #include <utils/Log.h>
     23 #include <androidfw/Input.h>
     24 #include "android_os_Parcel.h"
     25 #include "android_view_MotionEvent.h"
     26 #include "android_util_Binder.h"
     27 #include "android/graphics/Matrix.h"
     28 
     29 #include "SkMatrix.h"
     30 
     31 
     32 namespace android {
     33 
     34 // ----------------------------------------------------------------------------
     35 
     36 static struct {
     37     jclass clazz;
     38 
     39     jmethodID obtain;
     40     jmethodID recycle;
     41 
     42     jfieldID mNativePtr;
     43 } gMotionEventClassInfo;
     44 
     45 static struct {
     46     jfieldID mPackedAxisBits;
     47     jfieldID mPackedAxisValues;
     48     jfieldID x;
     49     jfieldID y;
     50     jfieldID pressure;
     51     jfieldID size;
     52     jfieldID touchMajor;
     53     jfieldID touchMinor;
     54     jfieldID toolMajor;
     55     jfieldID toolMinor;
     56     jfieldID orientation;
     57 } gPointerCoordsClassInfo;
     58 
     59 static struct {
     60     jfieldID id;
     61     jfieldID toolType;
     62 } gPointerPropertiesClassInfo;
     63 
     64 // ----------------------------------------------------------------------------
     65 
     66 MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) {
     67     if (!eventObj) {
     68         return NULL;
     69     }
     70     return reinterpret_cast<MotionEvent*>(
     71             env->GetIntField(eventObj, gMotionEventClassInfo.mNativePtr));
     72 }
     73 
     74 static void android_view_MotionEvent_setNativePtr(JNIEnv* env, jobject eventObj,
     75         MotionEvent* event) {
     76     env->SetIntField(eventObj, gMotionEventClassInfo.mNativePtr,
     77             reinterpret_cast<int>(event));
     78 }
     79 
     80 jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent* event) {
     81     jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,
     82             gMotionEventClassInfo.obtain);
     83     if (env->ExceptionCheck() || !eventObj) {
     84         ALOGE("An exception occurred while obtaining a motion event.");
     85         LOGE_EX(env);
     86         env->ExceptionClear();
     87         return NULL;
     88     }
     89 
     90     MotionEvent* destEvent = android_view_MotionEvent_getNativePtr(env, eventObj);
     91     if (!destEvent) {
     92         destEvent = new MotionEvent();
     93         android_view_MotionEvent_setNativePtr(env, eventObj, destEvent);
     94     }
     95 
     96     destEvent->copyFrom(event, true);
     97     return eventObj;
     98 }
     99 
    100 status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
    101     env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle);
    102     if (env->ExceptionCheck()) {
    103         ALOGW("An exception occurred while recycling a motion event.");
    104         LOGW_EX(env);
    105         env->ExceptionClear();
    106         return UNKNOWN_ERROR;
    107     }
    108     return OK;
    109 }
    110 
    111 // ----------------------------------------------------------------------------
    112 
    113 static const jint HISTORY_CURRENT = -0x80000000;
    114 
    115 static bool validatePointerCount(JNIEnv* env, jint pointerCount) {
    116     if (pointerCount < 1) {
    117         jniThrowException(env, "java/lang/IllegalArgumentException",
    118                 "pointerCount must be at least 1");
    119         return false;
    120     }
    121     return true;
    122 }
    123 
    124 static bool validatePointerPropertiesArray(JNIEnv* env, jobjectArray pointerPropertiesObjArray,
    125         size_t pointerCount) {
    126     if (!pointerPropertiesObjArray) {
    127         jniThrowException(env, "java/lang/IllegalArgumentException",
    128                 "pointerProperties array must not be null");
    129         return false;
    130     }
    131     size_t length = size_t(env->GetArrayLength(pointerPropertiesObjArray));
    132     if (length < pointerCount) {
    133         jniThrowException(env, "java/lang/IllegalArgumentException",
    134                 "pointerProperties array must be large enough to hold all pointers");
    135         return false;
    136     }
    137     return true;
    138 }
    139 
    140 static bool validatePointerCoordsObjArray(JNIEnv* env, jobjectArray pointerCoordsObjArray,
    141         size_t pointerCount) {
    142     if (!pointerCoordsObjArray) {
    143         jniThrowException(env, "java/lang/IllegalArgumentException",
    144                 "pointerCoords array must not be null");
    145         return false;
    146     }
    147     size_t length = size_t(env->GetArrayLength(pointerCoordsObjArray));
    148     if (length < pointerCount) {
    149         jniThrowException(env, "java/lang/IllegalArgumentException",
    150                 "pointerCoords array must be large enough to hold all pointers");
    151         return false;
    152     }
    153     return true;
    154 }
    155 
    156 static bool validatePointerIndex(JNIEnv* env, jint pointerIndex, size_t pointerCount) {
    157     if (pointerIndex < 0 || size_t(pointerIndex) >= pointerCount) {
    158         jniThrowException(env, "java/lang/IllegalArgumentException",
    159                 "pointerIndex out of range");
    160         return false;
    161     }
    162     return true;
    163 }
    164 
    165 static bool validateHistoryPos(JNIEnv* env, jint historyPos, size_t historySize) {
    166     if (historyPos < 0 || size_t(historyPos) >= historySize) {
    167         jniThrowException(env, "java/lang/IllegalArgumentException",
    168                 "historyPos out of range");
    169         return false;
    170     }
    171     return true;
    172 }
    173 
    174 static bool validatePointerCoords(JNIEnv* env, jobject pointerCoordsObj) {
    175     if (!pointerCoordsObj) {
    176         jniThrowException(env, "java/lang/IllegalArgumentException",
    177                 "pointerCoords must not be null");
    178         return false;
    179     }
    180     return true;
    181 }
    182 
    183 static bool validatePointerProperties(JNIEnv* env, jobject pointerPropertiesObj) {
    184     if (!pointerPropertiesObj) {
    185         jniThrowException(env, "java/lang/IllegalArgumentException",
    186                 "pointerProperties must not be null");
    187         return false;
    188     }
    189     return true;
    190 }
    191 
    192 static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj,
    193         float xOffset, float yOffset, PointerCoords* outRawPointerCoords) {
    194     outRawPointerCoords->clear();
    195     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_X,
    196             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.x) - xOffset);
    197     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_Y,
    198             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.y) - yOffset);
    199     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
    200             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.pressure));
    201     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_SIZE,
    202             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.size));
    203     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
    204             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMajor));
    205     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR,
    206             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMinor));
    207     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR,
    208             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMajor));
    209     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR,
    210             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor));
    211     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
    212             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));
    213 
    214     uint64_t bits = env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits);
    215     if (bits) {
    216         jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj,
    217                 gPointerCoordsClassInfo.mPackedAxisValues));
    218         if (valuesArray) {
    219             jfloat* values = static_cast<jfloat*>(
    220                     env->GetPrimitiveArrayCritical(valuesArray, NULL));
    221 
    222             uint32_t index = 0;
    223             do {
    224                 uint32_t axis = __builtin_ctzll(bits);
    225                 uint64_t axisBit = 1LL << axis;
    226                 bits &= ~axisBit;
    227                 outRawPointerCoords->setAxisValue(axis, values[index++]);
    228             } while (bits);
    229 
    230             env->ReleasePrimitiveArrayCritical(valuesArray, values, JNI_ABORT);
    231             env->DeleteLocalRef(valuesArray);
    232         }
    233     }
    234 }
    235 
    236 static jfloatArray obtainPackedAxisValuesArray(JNIEnv* env, uint32_t minSize,
    237         jobject outPointerCoordsObj) {
    238     jfloatArray outValuesArray = jfloatArray(env->GetObjectField(outPointerCoordsObj,
    239             gPointerCoordsClassInfo.mPackedAxisValues));
    240     if (outValuesArray) {
    241         uint32_t size = env->GetArrayLength(outValuesArray);
    242         if (minSize <= size) {
    243             return outValuesArray;
    244         }
    245         env->DeleteLocalRef(outValuesArray);
    246     }
    247     uint32_t size = 8;
    248     while (size < minSize) {
    249         size *= 2;
    250     }
    251     outValuesArray = env->NewFloatArray(size);
    252     env->SetObjectField(outPointerCoordsObj,
    253             gPointerCoordsClassInfo.mPackedAxisValues, outValuesArray);
    254     return outValuesArray;
    255 }
    256 
    257 static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointerCoords,
    258         float xOffset, float yOffset, jobject outPointerCoordsObj) {
    259     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.x,
    260             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset);
    261     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.y,
    262             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset);
    263     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.pressure,
    264             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
    265     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.size,
    266             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_SIZE));
    267     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.touchMajor,
    268             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR));
    269     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.touchMinor,
    270             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR));
    271     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.toolMajor,
    272             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR));
    273     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.toolMinor,
    274             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR));
    275     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.orientation,
    276             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
    277 
    278     const uint64_t unpackedAxisBits = 0
    279             | (1LL << AMOTION_EVENT_AXIS_X)
    280             | (1LL << AMOTION_EVENT_AXIS_Y)
    281             | (1LL << AMOTION_EVENT_AXIS_PRESSURE)
    282             | (1LL << AMOTION_EVENT_AXIS_SIZE)
    283             | (1LL << AMOTION_EVENT_AXIS_TOUCH_MAJOR)
    284             | (1LL << AMOTION_EVENT_AXIS_TOUCH_MINOR)
    285             | (1LL << AMOTION_EVENT_AXIS_TOOL_MAJOR)
    286             | (1LL << AMOTION_EVENT_AXIS_TOOL_MINOR)
    287             | (1LL << AMOTION_EVENT_AXIS_ORIENTATION);
    288 
    289     uint64_t outBits = 0;
    290     uint64_t remainingBits = rawPointerCoords->bits & ~unpackedAxisBits;
    291     if (remainingBits) {
    292         uint32_t packedAxesCount = __builtin_popcountll(remainingBits);
    293         jfloatArray outValuesArray = obtainPackedAxisValuesArray(env, packedAxesCount,
    294                 outPointerCoordsObj);
    295         if (!outValuesArray) {
    296             return; // OOM
    297         }
    298 
    299         jfloat* outValues = static_cast<jfloat*>(env->GetPrimitiveArrayCritical(
    300                 outValuesArray, NULL));
    301 
    302         const float* values = rawPointerCoords->values;
    303         uint32_t index = 0;
    304         do {
    305             uint32_t axis = __builtin_ctzll(remainingBits);
    306             uint64_t axisBit = 1LL << axis;
    307             remainingBits &= ~axisBit;
    308             outBits |= axisBit;
    309             outValues[index++] = rawPointerCoords->getAxisValue(axis);
    310         } while (remainingBits);
    311 
    312         env->ReleasePrimitiveArrayCritical(outValuesArray, outValues, 0);
    313         env->DeleteLocalRef(outValuesArray);
    314     }
    315     env->SetLongField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits);
    316 }
    317 
    318 static void pointerPropertiesToNative(JNIEnv* env, jobject pointerPropertiesObj,
    319         PointerProperties* outPointerProperties) {
    320     outPointerProperties->clear();
    321     outPointerProperties->id = env->GetIntField(pointerPropertiesObj,
    322             gPointerPropertiesClassInfo.id);
    323     outPointerProperties->toolType = env->GetIntField(pointerPropertiesObj,
    324             gPointerPropertiesClassInfo.toolType);
    325 }
    326 
    327 static void pointerPropertiesFromNative(JNIEnv* env, const PointerProperties* pointerProperties,
    328         jobject outPointerPropertiesObj) {
    329     env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.id,
    330             pointerProperties->id);
    331     env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.toolType,
    332             pointerProperties->toolType);
    333 }
    334 
    335 
    336 // ----------------------------------------------------------------------------
    337 
    338 static jint android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz,
    339         jint nativePtr,
    340         jint deviceId, jint source, jint action, jint flags, jint edgeFlags,
    341         jint metaState, jint buttonState,
    342         jfloat xOffset, jfloat yOffset, jfloat xPrecision, jfloat yPrecision,
    343         jlong downTimeNanos, jlong eventTimeNanos,
    344         jint pointerCount, jobjectArray pointerPropertiesObjArray,
    345         jobjectArray pointerCoordsObjArray) {
    346     if (!validatePointerCount(env, pointerCount)
    347             || !validatePointerPropertiesArray(env, pointerPropertiesObjArray, pointerCount)
    348             || !validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) {
    349         return 0;
    350     }
    351 
    352     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    353     if (!event) {
    354         event = new MotionEvent();
    355     }
    356 
    357     PointerProperties pointerProperties[pointerCount];
    358     PointerCoords rawPointerCoords[pointerCount];
    359 
    360     for (jint i = 0; i < pointerCount; i++) {
    361         jobject pointerPropertiesObj = env->GetObjectArrayElement(pointerPropertiesObjArray, i);
    362         if (!pointerPropertiesObj) {
    363             goto Error;
    364         }
    365         pointerPropertiesToNative(env, pointerPropertiesObj, &pointerProperties[i]);
    366         env->DeleteLocalRef(pointerPropertiesObj);
    367 
    368         jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
    369         if (!pointerCoordsObj) {
    370             jniThrowNullPointerException(env, "pointerCoords");
    371             goto Error;
    372         }
    373         pointerCoordsToNative(env, pointerCoordsObj, xOffset, yOffset, &rawPointerCoords[i]);
    374         env->DeleteLocalRef(pointerCoordsObj);
    375     }
    376 
    377     event->initialize(deviceId, source, action, flags, edgeFlags, metaState, buttonState,
    378             xOffset, yOffset, xPrecision, yPrecision,
    379             downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords);
    380 
    381     return reinterpret_cast<jint>(event);
    382 
    383 Error:
    384     if (!nativePtr) {
    385         delete event;
    386     }
    387     return 0;
    388 }
    389 
    390 static jint android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz,
    391         jint destNativePtr, jint sourceNativePtr, jboolean keepHistory) {
    392     MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
    393     if (!destEvent) {
    394         destEvent = new MotionEvent();
    395     }
    396     MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
    397     destEvent->copyFrom(sourceEvent, keepHistory);
    398     return reinterpret_cast<jint>(destEvent);
    399 }
    400 
    401 static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
    402         jint nativePtr) {
    403     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    404     delete event;
    405 }
    406 
    407 static void android_view_MotionEvent_nativeAddBatch(JNIEnv* env, jclass clazz,
    408         jint nativePtr, jlong eventTimeNanos, jobjectArray pointerCoordsObjArray,
    409         jint metaState) {
    410     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    411     size_t pointerCount = event->getPointerCount();
    412     if (!validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) {
    413         return;
    414     }
    415 
    416     PointerCoords rawPointerCoords[pointerCount];
    417 
    418     for (size_t i = 0; i < pointerCount; i++) {
    419         jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
    420         if (!pointerCoordsObj) {
    421             jniThrowNullPointerException(env, "pointerCoords");
    422             return;
    423         }
    424         pointerCoordsToNative(env, pointerCoordsObj,
    425                 event->getXOffset(), event->getYOffset(), &rawPointerCoords[i]);
    426         env->DeleteLocalRef(pointerCoordsObj);
    427     }
    428 
    429     event->addSample(eventTimeNanos, rawPointerCoords);
    430     event->setMetaState(event->getMetaState() | metaState);
    431 }
    432 
    433 static jint android_view_MotionEvent_nativeGetDeviceId(JNIEnv* env, jclass clazz,
    434         jint nativePtr) {
    435     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    436     return event->getDeviceId();
    437 }
    438 
    439 static jint android_view_MotionEvent_nativeGetSource(JNIEnv* env, jclass clazz,
    440         jint nativePtr) {
    441     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    442     return event->getSource();
    443 }
    444 
    445 static void android_view_MotionEvent_nativeSetSource(JNIEnv* env, jclass clazz,
    446         jint nativePtr, jint source) {
    447     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    448     event->setSource(source);
    449 }
    450 
    451 static jint android_view_MotionEvent_nativeGetAction(JNIEnv* env, jclass clazz,
    452         jint nativePtr) {
    453     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    454     return event->getAction();
    455 }
    456 
    457 static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz,
    458         jint nativePtr, jint action) {
    459     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    460     event->setAction(action);
    461 }
    462 
    463 static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz,
    464         jint nativePtr) {
    465     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    466     return event->isTouchEvent();
    467 }
    468 
    469 static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz,
    470         jint nativePtr) {
    471     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    472     return event->getFlags();
    473 }
    474 
    475 static void android_view_MotionEvent_nativeSetFlags(JNIEnv* env, jclass clazz,
    476         jint nativePtr, jint flags) {
    477     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    478     event->setFlags(flags);
    479 }
    480 
    481 static jint android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv* env, jclass clazz,
    482         jint nativePtr) {
    483     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    484     return event->getEdgeFlags();
    485 }
    486 
    487 static void android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv* env, jclass clazz,
    488         jint nativePtr, jint edgeFlags) {
    489     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    490     event->setEdgeFlags(edgeFlags);
    491 }
    492 
    493 static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass clazz,
    494         jint nativePtr) {
    495     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    496     return event->getMetaState();
    497 }
    498 
    499 static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz,
    500         jint nativePtr) {
    501     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    502     return event->getButtonState();
    503 }
    504 
    505 static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz,
    506         jint nativePtr, jfloat deltaX, jfloat deltaY) {
    507     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    508     return event->offsetLocation(deltaX, deltaY);
    509 }
    510 
    511 static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz,
    512         jint nativePtr) {
    513     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    514     return event->getXOffset();
    515 }
    516 
    517 static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz,
    518         jint nativePtr) {
    519     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    520     return event->getYOffset();
    521 }
    522 
    523 static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz,
    524         jint nativePtr) {
    525     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    526     return event->getXPrecision();
    527 }
    528 
    529 static jfloat android_view_MotionEvent_nativeGetYPrecision(JNIEnv* env, jclass clazz,
    530         jint nativePtr) {
    531     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    532     return event->getYPrecision();
    533 }
    534 
    535 static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass clazz,
    536         jint nativePtr) {
    537     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    538     return event->getDownTime();
    539 }
    540 
    541 static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz,
    542         jint nativePtr, jlong downTimeNanos) {
    543     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    544     event->setDownTime(downTimeNanos);
    545 }
    546 
    547 static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz,
    548         jint nativePtr) {
    549     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    550     return jint(event->getPointerCount());
    551 }
    552 
    553 static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
    554         jint nativePtr, jint pointerIndex) {
    555     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    556     size_t pointerCount = event->getPointerCount();
    557     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    558         return -1;
    559     }
    560     return event->getPointerId(pointerIndex);
    561 }
    562 
    563 static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
    564         jint nativePtr, jint pointerIndex) {
    565     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    566     size_t pointerCount = event->getPointerCount();
    567     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    568         return -1;
    569     }
    570     return event->getToolType(pointerIndex);
    571 }
    572 
    573 static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz,
    574         jint nativePtr, jint pointerId) {
    575     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    576     return jint(event->findPointerIndex(pointerId));
    577 }
    578 
    579 static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz,
    580         jint nativePtr) {
    581     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    582     return jint(event->getHistorySize());
    583 }
    584 
    585 static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
    586         jint nativePtr, jint historyPos) {
    587     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    588     if (historyPos == HISTORY_CURRENT) {
    589         return event->getEventTime();
    590     } else {
    591         size_t historySize = event->getHistorySize();
    592         if (!validateHistoryPos(env, historyPos, historySize)) {
    593             return 0;
    594         }
    595         return event->getHistoricalEventTime(historyPos);
    596     }
    597 }
    598 
    599 static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
    600         jint nativePtr, jint axis, jint pointerIndex, jint historyPos) {
    601     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    602     size_t pointerCount = event->getPointerCount();
    603     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    604         return 0;
    605     }
    606 
    607     if (historyPos == HISTORY_CURRENT) {
    608         return event->getRawAxisValue(axis, pointerIndex);
    609     } else {
    610         size_t historySize = event->getHistorySize();
    611         if (!validateHistoryPos(env, historyPos, historySize)) {
    612             return 0;
    613         }
    614         return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
    615     }
    616 }
    617 
    618 static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
    619         jint nativePtr, jint axis, jint pointerIndex, jint historyPos) {
    620     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    621     size_t pointerCount = event->getPointerCount();
    622     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    623         return 0;
    624     }
    625 
    626     if (historyPos == HISTORY_CURRENT) {
    627         return event->getAxisValue(axis, pointerIndex);
    628     } else {
    629         size_t historySize = event->getHistorySize();
    630         if (!validateHistoryPos(env, historyPos, historySize)) {
    631             return 0;
    632         }
    633         return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
    634     }
    635 }
    636 
    637 static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz,
    638         jint nativePtr, jint pointerIndex, jint historyPos, jobject outPointerCoordsObj) {
    639     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    640     size_t pointerCount = event->getPointerCount();
    641     if (!validatePointerIndex(env, pointerIndex, pointerCount)
    642             || !validatePointerCoords(env, outPointerCoordsObj)) {
    643         return;
    644     }
    645 
    646     const PointerCoords* rawPointerCoords;
    647     if (historyPos == HISTORY_CURRENT) {
    648         rawPointerCoords = event->getRawPointerCoords(pointerIndex);
    649     } else {
    650         size_t historySize = event->getHistorySize();
    651         if (!validateHistoryPos(env, historyPos, historySize)) {
    652             return;
    653         }
    654         rawPointerCoords = event->getHistoricalRawPointerCoords(pointerIndex, historyPos);
    655     }
    656     pointerCoordsFromNative(env, rawPointerCoords, event->getXOffset(), event->getYOffset(),
    657             outPointerCoordsObj);
    658 }
    659 
    660 static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz,
    661         jint nativePtr, jint pointerIndex, jobject outPointerPropertiesObj) {
    662     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    663     size_t pointerCount = event->getPointerCount();
    664     if (!validatePointerIndex(env, pointerIndex, pointerCount)
    665             || !validatePointerProperties(env, outPointerPropertiesObj)) {
    666         return;
    667     }
    668 
    669     const PointerProperties* pointerProperties = event->getPointerProperties(pointerIndex);
    670     pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj);
    671 }
    672 
    673 static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz,
    674         jint nativePtr, jfloat scale) {
    675     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    676     event->scale(scale);
    677 }
    678 
    679 static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz,
    680         jint nativePtr, jobject matrixObj) {
    681     SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
    682     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    683     event->transform(matrix);
    684 }
    685 
    686 static jint android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
    687         jint nativePtr, jobject parcelObj) {
    688     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    689     if (!event) {
    690         event = new MotionEvent();
    691     }
    692 
    693     Parcel* parcel = parcelForJavaObject(env, parcelObj);
    694 
    695     status_t status = event->readFromParcel(parcel);
    696     if (status) {
    697         if (!nativePtr) {
    698             delete event;
    699         }
    700         jniThrowRuntimeException(env, "Failed to read MotionEvent parcel.");
    701         return 0;
    702     }
    703     return reinterpret_cast<jint>(event);
    704 }
    705 
    706 static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass clazz,
    707         jint nativePtr, jobject parcelObj) {
    708     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    709     Parcel* parcel = parcelForJavaObject(env, parcelObj);
    710 
    711     status_t status = event->writeToParcel(parcel);
    712     if (status) {
    713         jniThrowRuntimeException(env, "Failed to write MotionEvent parcel.");
    714     }
    715 }
    716 
    717 // ----------------------------------------------------------------------------
    718 
    719 static JNINativeMethod gMotionEventMethods[] = {
    720     /* name, signature, funcPtr */
    721     { "nativeInitialize",
    722             "(IIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
    723                     "[Landroid/view/MotionEvent$PointerCoords;)I",
    724             (void*)android_view_MotionEvent_nativeInitialize },
    725     { "nativeCopy",
    726             "(IIZ)I",
    727             (void*)android_view_MotionEvent_nativeCopy },
    728     { "nativeDispose",
    729             "(I)V",
    730             (void*)android_view_MotionEvent_nativeDispose },
    731     { "nativeAddBatch",
    732             "(IJ[Landroid/view/MotionEvent$PointerCoords;I)V",
    733             (void*)android_view_MotionEvent_nativeAddBatch },
    734     { "nativeGetDeviceId",
    735             "(I)I",
    736             (void*)android_view_MotionEvent_nativeGetDeviceId },
    737     { "nativeGetSource",
    738             "(I)I",
    739             (void*)android_view_MotionEvent_nativeGetSource },
    740     { "nativeSetSource",
    741             "(II)I",
    742             (void*)android_view_MotionEvent_nativeSetSource },
    743     { "nativeGetAction",
    744             "(I)I",
    745             (void*)android_view_MotionEvent_nativeGetAction },
    746     { "nativeSetAction",
    747             "(II)V",
    748             (void*)android_view_MotionEvent_nativeSetAction },
    749     { "nativeIsTouchEvent",
    750             "(I)Z",
    751             (void*)android_view_MotionEvent_nativeIsTouchEvent },
    752     { "nativeGetFlags",
    753             "(I)I",
    754             (void*)android_view_MotionEvent_nativeGetFlags },
    755     { "nativeSetFlags",
    756             "(II)V",
    757             (void*)android_view_MotionEvent_nativeSetFlags },
    758     { "nativeGetEdgeFlags",
    759             "(I)I",
    760             (void*)android_view_MotionEvent_nativeGetEdgeFlags },
    761     { "nativeSetEdgeFlags",
    762             "(II)V",
    763             (void*)android_view_MotionEvent_nativeSetEdgeFlags },
    764     { "nativeGetMetaState",
    765             "(I)I",
    766             (void*)android_view_MotionEvent_nativeGetMetaState },
    767     { "nativeGetButtonState",
    768             "(I)I",
    769             (void*)android_view_MotionEvent_nativeGetButtonState },
    770     { "nativeOffsetLocation",
    771             "(IFF)V",
    772             (void*)android_view_MotionEvent_nativeOffsetLocation },
    773     { "nativeGetXOffset",
    774             "(I)F",
    775             (void*)android_view_MotionEvent_nativeGetXOffset },
    776     { "nativeGetYOffset",
    777             "(I)F",
    778             (void*)android_view_MotionEvent_nativeGetYOffset },
    779     { "nativeGetXPrecision",
    780             "(I)F",
    781             (void*)android_view_MotionEvent_nativeGetXPrecision },
    782     { "nativeGetYPrecision",
    783             "(I)F",
    784             (void*)android_view_MotionEvent_nativeGetYPrecision },
    785     { "nativeGetDownTimeNanos",
    786             "(I)J",
    787             (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
    788     { "nativeSetDownTimeNanos",
    789             "(IJ)V",
    790             (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
    791     { "nativeGetPointerCount",
    792             "(I)I",
    793             (void*)android_view_MotionEvent_nativeGetPointerCount },
    794     { "nativeGetPointerId",
    795             "(II)I",
    796             (void*)android_view_MotionEvent_nativeGetPointerId },
    797     { "nativeGetToolType",
    798             "(II)I",
    799             (void*)android_view_MotionEvent_nativeGetToolType },
    800     { "nativeFindPointerIndex",
    801             "(II)I",
    802             (void*)android_view_MotionEvent_nativeFindPointerIndex },
    803     { "nativeGetHistorySize",
    804             "(I)I",
    805             (void*)android_view_MotionEvent_nativeGetHistorySize },
    806     { "nativeGetEventTimeNanos",
    807             "(II)J",
    808             (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
    809     { "nativeGetRawAxisValue",
    810             "(IIII)F",
    811             (void*)android_view_MotionEvent_nativeGetRawAxisValue },
    812     { "nativeGetAxisValue",
    813             "(IIII)F",
    814             (void*)android_view_MotionEvent_nativeGetAxisValue },
    815     { "nativeGetPointerCoords",
    816             "(IIILandroid/view/MotionEvent$PointerCoords;)V",
    817             (void*)android_view_MotionEvent_nativeGetPointerCoords },
    818     { "nativeGetPointerProperties",
    819             "(IILandroid/view/MotionEvent$PointerProperties;)V",
    820             (void*)android_view_MotionEvent_nativeGetPointerProperties },
    821     { "nativeScale",
    822             "(IF)V",
    823             (void*)android_view_MotionEvent_nativeScale },
    824     { "nativeTransform",
    825             "(ILandroid/graphics/Matrix;)V",
    826             (void*)android_view_MotionEvent_nativeTransform },
    827     { "nativeReadFromParcel",
    828             "(ILandroid/os/Parcel;)I",
    829             (void*)android_view_MotionEvent_nativeReadFromParcel },
    830     { "nativeWriteToParcel",
    831             "(ILandroid/os/Parcel;)V",
    832             (void*)android_view_MotionEvent_nativeWriteToParcel },
    833 };
    834 
    835 #define FIND_CLASS(var, className) \
    836         var = env->FindClass(className); \
    837         LOG_FATAL_IF(! var, "Unable to find class " className);
    838 
    839 #define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
    840         var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
    841         LOG_FATAL_IF(! var, "Unable to find static method" methodName);
    842 
    843 #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
    844         var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
    845         LOG_FATAL_IF(! var, "Unable to find method" methodName);
    846 
    847 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
    848         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
    849         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
    850 
    851 int register_android_view_MotionEvent(JNIEnv* env) {
    852     int res = jniRegisterNativeMethods(env, "android/view/MotionEvent",
    853             gMotionEventMethods, NELEM(gMotionEventMethods));
    854     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
    855 
    856     FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
    857     gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
    858 
    859     GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz,
    860             "obtain", "()Landroid/view/MotionEvent;");
    861     GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
    862             "recycle", "()V");
    863     GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz,
    864             "mNativePtr", "I");
    865 
    866     jclass clazz;
    867     FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords");
    868 
    869     GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz,
    870             "mPackedAxisBits", "J");
    871     GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz,
    872             "mPackedAxisValues", "[F");
    873     GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz,
    874             "x", "F");
    875     GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz,
    876             "y", "F");
    877     GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz,
    878             "pressure", "F");
    879     GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz,
    880             "size", "F");
    881     GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz,
    882             "touchMajor", "F");
    883     GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz,
    884             "touchMinor", "F");
    885     GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz,
    886             "toolMajor", "F");
    887     GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz,
    888             "toolMinor", "F");
    889     GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz,
    890             "orientation", "F");
    891 
    892     FIND_CLASS(clazz, "android/view/MotionEvent$PointerProperties");
    893 
    894     GET_FIELD_ID(gPointerPropertiesClassInfo.id, clazz,
    895             "id", "I");
    896     GET_FIELD_ID(gPointerPropertiesClassInfo.toolType, clazz,
    897             "toolType", "I");
    898 
    899     return 0;
    900 }
    901 
    902 } // namespace android
    903