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