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 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->GetLongField(eventObj, gMotionEventClassInfo.mNativePtr));
     72 }
     73 
     74 static void android_view_MotionEvent_setNativePtr(JNIEnv* env, jobject eventObj,
     75         MotionEvent* event) {
     76     env->SetLongField(eventObj, gMotionEventClassInfo.mNativePtr,
     77             reinterpret_cast<jlong>(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     BitSet64 bits =
    215             BitSet64(env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits));
    216     if (!bits.isEmpty()) {
    217         jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj,
    218                 gPointerCoordsClassInfo.mPackedAxisValues));
    219         if (valuesArray) {
    220             jfloat* values = static_cast<jfloat*>(
    221                     env->GetPrimitiveArrayCritical(valuesArray, NULL));
    222 
    223             uint32_t index = 0;
    224             do {
    225                 uint32_t axis = bits.clearFirstMarkedBit();
    226                 outRawPointerCoords->setAxisValue(axis, values[index++]);
    227             } while (!bits.isEmpty());
    228 
    229             env->ReleasePrimitiveArrayCritical(valuesArray, values, JNI_ABORT);
    230             env->DeleteLocalRef(valuesArray);
    231         }
    232     }
    233 }
    234 
    235 static jfloatArray obtainPackedAxisValuesArray(JNIEnv* env, uint32_t minSize,
    236         jobject outPointerCoordsObj) {
    237     jfloatArray outValuesArray = jfloatArray(env->GetObjectField(outPointerCoordsObj,
    238             gPointerCoordsClassInfo.mPackedAxisValues));
    239     if (outValuesArray) {
    240         uint32_t size = env->GetArrayLength(outValuesArray);
    241         if (minSize <= size) {
    242             return outValuesArray;
    243         }
    244         env->DeleteLocalRef(outValuesArray);
    245     }
    246     uint32_t size = 8;
    247     while (size < minSize) {
    248         size *= 2;
    249     }
    250     outValuesArray = env->NewFloatArray(size);
    251     env->SetObjectField(outPointerCoordsObj,
    252             gPointerCoordsClassInfo.mPackedAxisValues, outValuesArray);
    253     return outValuesArray;
    254 }
    255 
    256 static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointerCoords,
    257         float xOffset, float yOffset, jobject outPointerCoordsObj) {
    258     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.x,
    259             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset);
    260     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.y,
    261             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset);
    262     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.pressure,
    263             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
    264     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.size,
    265             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_SIZE));
    266     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.touchMajor,
    267             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR));
    268     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.touchMinor,
    269             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR));
    270     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.toolMajor,
    271             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR));
    272     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.toolMinor,
    273             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR));
    274     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.orientation,
    275             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
    276 
    277     uint64_t outBits = 0;
    278     BitSet64 bits = BitSet64(rawPointerCoords->bits);
    279     bits.clearBit(AMOTION_EVENT_AXIS_X);
    280     bits.clearBit(AMOTION_EVENT_AXIS_Y);
    281     bits.clearBit(AMOTION_EVENT_AXIS_PRESSURE);
    282     bits.clearBit(AMOTION_EVENT_AXIS_SIZE);
    283     bits.clearBit(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
    284     bits.clearBit(AMOTION_EVENT_AXIS_TOUCH_MINOR);
    285     bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MAJOR);
    286     bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MINOR);
    287     bits.clearBit(AMOTION_EVENT_AXIS_ORIENTATION);
    288     if (!bits.isEmpty()) {
    289         uint32_t packedAxesCount = bits.count();
    290         jfloatArray outValuesArray = obtainPackedAxisValuesArray(env, packedAxesCount,
    291                 outPointerCoordsObj);
    292         if (!outValuesArray) {
    293             return; // OOM
    294         }
    295 
    296         jfloat* outValues = static_cast<jfloat*>(env->GetPrimitiveArrayCritical(
    297                 outValuesArray, NULL));
    298 
    299         const float* values = rawPointerCoords->values;
    300         uint32_t index = 0;
    301         do {
    302             uint32_t axis = bits.clearFirstMarkedBit();
    303             outBits |= BitSet64::valueForBit(axis);
    304             outValues[index++] = rawPointerCoords->getAxisValue(axis);
    305         } while (!bits.isEmpty());
    306 
    307         env->ReleasePrimitiveArrayCritical(outValuesArray, outValues, 0);
    308         env->DeleteLocalRef(outValuesArray);
    309     }
    310     env->SetLongField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits);
    311 }
    312 
    313 static void pointerPropertiesToNative(JNIEnv* env, jobject pointerPropertiesObj,
    314         PointerProperties* outPointerProperties) {
    315     outPointerProperties->clear();
    316     outPointerProperties->id = env->GetIntField(pointerPropertiesObj,
    317             gPointerPropertiesClassInfo.id);
    318     outPointerProperties->toolType = env->GetIntField(pointerPropertiesObj,
    319             gPointerPropertiesClassInfo.toolType);
    320 }
    321 
    322 static void pointerPropertiesFromNative(JNIEnv* env, const PointerProperties* pointerProperties,
    323         jobject outPointerPropertiesObj) {
    324     env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.id,
    325             pointerProperties->id);
    326     env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.toolType,
    327             pointerProperties->toolType);
    328 }
    329 
    330 
    331 // ----------------------------------------------------------------------------
    332 
    333 static jlong android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz,
    334         jlong nativePtr,
    335         jint deviceId, jint source, jint action, jint flags, jint edgeFlags,
    336         jint metaState, jint buttonState,
    337         jfloat xOffset, jfloat yOffset, jfloat xPrecision, jfloat yPrecision,
    338         jlong downTimeNanos, jlong eventTimeNanos,
    339         jint pointerCount, jobjectArray pointerPropertiesObjArray,
    340         jobjectArray pointerCoordsObjArray) {
    341     if (!validatePointerCount(env, pointerCount)
    342             || !validatePointerPropertiesArray(env, pointerPropertiesObjArray, pointerCount)
    343             || !validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) {
    344         return 0;
    345     }
    346 
    347     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    348     if (!event) {
    349         event = new MotionEvent();
    350     }
    351 
    352     PointerProperties pointerProperties[pointerCount];
    353     PointerCoords rawPointerCoords[pointerCount];
    354 
    355     for (jint i = 0; i < pointerCount; i++) {
    356         jobject pointerPropertiesObj = env->GetObjectArrayElement(pointerPropertiesObjArray, i);
    357         if (!pointerPropertiesObj) {
    358             goto Error;
    359         }
    360         pointerPropertiesToNative(env, pointerPropertiesObj, &pointerProperties[i]);
    361         env->DeleteLocalRef(pointerPropertiesObj);
    362 
    363         jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
    364         if (!pointerCoordsObj) {
    365             jniThrowNullPointerException(env, "pointerCoords");
    366             goto Error;
    367         }
    368         pointerCoordsToNative(env, pointerCoordsObj, xOffset, yOffset, &rawPointerCoords[i]);
    369         env->DeleteLocalRef(pointerCoordsObj);
    370     }
    371 
    372     event->initialize(deviceId, source, action, flags, edgeFlags, metaState, buttonState,
    373             xOffset, yOffset, xPrecision, yPrecision,
    374             downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords);
    375 
    376     return reinterpret_cast<jlong>(event);
    377 
    378 Error:
    379     if (!nativePtr) {
    380         delete event;
    381     }
    382     return 0;
    383 }
    384 
    385 static jlong android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz,
    386         jlong destNativePtr, jlong sourceNativePtr, jboolean keepHistory) {
    387     MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
    388     if (!destEvent) {
    389         destEvent = new MotionEvent();
    390     }
    391     MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
    392     destEvent->copyFrom(sourceEvent, keepHistory);
    393     return reinterpret_cast<jlong>(destEvent);
    394 }
    395 
    396 static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
    397         jlong nativePtr) {
    398     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    399     delete event;
    400 }
    401 
    402 static void android_view_MotionEvent_nativeAddBatch(JNIEnv* env, jclass clazz,
    403         jlong nativePtr, jlong eventTimeNanos, jobjectArray pointerCoordsObjArray,
    404         jint metaState) {
    405     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    406     size_t pointerCount = event->getPointerCount();
    407     if (!validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) {
    408         return;
    409     }
    410 
    411     PointerCoords rawPointerCoords[pointerCount];
    412 
    413     for (size_t i = 0; i < pointerCount; i++) {
    414         jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
    415         if (!pointerCoordsObj) {
    416             jniThrowNullPointerException(env, "pointerCoords");
    417             return;
    418         }
    419         pointerCoordsToNative(env, pointerCoordsObj,
    420                 event->getXOffset(), event->getYOffset(), &rawPointerCoords[i]);
    421         env->DeleteLocalRef(pointerCoordsObj);
    422     }
    423 
    424     event->addSample(eventTimeNanos, rawPointerCoords);
    425     event->setMetaState(event->getMetaState() | metaState);
    426 }
    427 
    428 static jint android_view_MotionEvent_nativeGetDeviceId(JNIEnv* env, jclass clazz,
    429         jlong nativePtr) {
    430     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    431     return event->getDeviceId();
    432 }
    433 
    434 static jint android_view_MotionEvent_nativeGetSource(JNIEnv* env, jclass clazz,
    435         jlong nativePtr) {
    436     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    437     return event->getSource();
    438 }
    439 
    440 static void android_view_MotionEvent_nativeSetSource(JNIEnv* env, jclass clazz,
    441         jlong nativePtr, jint source) {
    442     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    443     event->setSource(source);
    444 }
    445 
    446 static jint android_view_MotionEvent_nativeGetAction(JNIEnv* env, jclass clazz,
    447         jlong nativePtr) {
    448     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    449     return event->getAction();
    450 }
    451 
    452 static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz,
    453         jlong nativePtr, jint action) {
    454     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    455     event->setAction(action);
    456 }
    457 
    458 static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz,
    459         jlong nativePtr) {
    460     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    461     return event->isTouchEvent();
    462 }
    463 
    464 static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz,
    465         jlong nativePtr) {
    466     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    467     return event->getFlags();
    468 }
    469 
    470 static void android_view_MotionEvent_nativeSetFlags(JNIEnv* env, jclass clazz,
    471         jlong nativePtr, jint flags) {
    472     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    473     event->setFlags(flags);
    474 }
    475 
    476 static jint android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv* env, jclass clazz,
    477         jlong nativePtr) {
    478     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    479     return event->getEdgeFlags();
    480 }
    481 
    482 static void android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv* env, jclass clazz,
    483         jlong nativePtr, jint edgeFlags) {
    484     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    485     event->setEdgeFlags(edgeFlags);
    486 }
    487 
    488 static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass clazz,
    489         jlong nativePtr) {
    490     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    491     return event->getMetaState();
    492 }
    493 
    494 static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz,
    495         jlong nativePtr) {
    496     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    497     return event->getButtonState();
    498 }
    499 
    500 static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz,
    501         jlong nativePtr, jfloat deltaX, jfloat deltaY) {
    502     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    503     return event->offsetLocation(deltaX, deltaY);
    504 }
    505 
    506 static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz,
    507         jlong nativePtr) {
    508     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    509     return event->getXOffset();
    510 }
    511 
    512 static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz,
    513         jlong nativePtr) {
    514     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    515     return event->getYOffset();
    516 }
    517 
    518 static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz,
    519         jlong nativePtr) {
    520     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    521     return event->getXPrecision();
    522 }
    523 
    524 static jfloat android_view_MotionEvent_nativeGetYPrecision(JNIEnv* env, jclass clazz,
    525         jlong nativePtr) {
    526     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    527     return event->getYPrecision();
    528 }
    529 
    530 static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass clazz,
    531         jlong nativePtr) {
    532     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    533     return event->getDownTime();
    534 }
    535 
    536 static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz,
    537         jlong nativePtr, jlong downTimeNanos) {
    538     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    539     event->setDownTime(downTimeNanos);
    540 }
    541 
    542 static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz,
    543         jlong nativePtr) {
    544     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    545     return jint(event->getPointerCount());
    546 }
    547 
    548 static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
    549         jlong nativePtr, jint pointerIndex) {
    550     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    551     size_t pointerCount = event->getPointerCount();
    552     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    553         return -1;
    554     }
    555     return event->getPointerId(pointerIndex);
    556 }
    557 
    558 static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
    559         jlong nativePtr, jint pointerIndex) {
    560     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    561     size_t pointerCount = event->getPointerCount();
    562     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    563         return -1;
    564     }
    565     return event->getToolType(pointerIndex);
    566 }
    567 
    568 static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz,
    569         jlong nativePtr, jint pointerId) {
    570     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    571     return jint(event->findPointerIndex(pointerId));
    572 }
    573 
    574 static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz,
    575         jlong nativePtr) {
    576     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    577     return jint(event->getHistorySize());
    578 }
    579 
    580 static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
    581         jlong nativePtr, jint historyPos) {
    582     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    583     if (historyPos == HISTORY_CURRENT) {
    584         return event->getEventTime();
    585     } else {
    586         size_t historySize = event->getHistorySize();
    587         if (!validateHistoryPos(env, historyPos, historySize)) {
    588             return 0;
    589         }
    590         return event->getHistoricalEventTime(historyPos);
    591     }
    592 }
    593 
    594 static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
    595         jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
    596     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    597     size_t pointerCount = event->getPointerCount();
    598     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    599         return 0;
    600     }
    601 
    602     if (historyPos == HISTORY_CURRENT) {
    603         return event->getRawAxisValue(axis, pointerIndex);
    604     } else {
    605         size_t historySize = event->getHistorySize();
    606         if (!validateHistoryPos(env, historyPos, historySize)) {
    607             return 0;
    608         }
    609         return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
    610     }
    611 }
    612 
    613 static jfloat android_view_MotionEvent_nativeGetAxisValue(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->getAxisValue(axis, pointerIndex);
    623     } else {
    624         size_t historySize = event->getHistorySize();
    625         if (!validateHistoryPos(env, historyPos, historySize)) {
    626             return 0;
    627         }
    628         return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
    629     }
    630 }
    631 
    632 static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz,
    633         jlong nativePtr, jint pointerIndex, jint historyPos, jobject outPointerCoordsObj) {
    634     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    635     size_t pointerCount = event->getPointerCount();
    636     if (!validatePointerIndex(env, pointerIndex, pointerCount)
    637             || !validatePointerCoords(env, outPointerCoordsObj)) {
    638         return;
    639     }
    640 
    641     const PointerCoords* rawPointerCoords;
    642     if (historyPos == HISTORY_CURRENT) {
    643         rawPointerCoords = event->getRawPointerCoords(pointerIndex);
    644     } else {
    645         size_t historySize = event->getHistorySize();
    646         if (!validateHistoryPos(env, historyPos, historySize)) {
    647             return;
    648         }
    649         rawPointerCoords = event->getHistoricalRawPointerCoords(pointerIndex, historyPos);
    650     }
    651     pointerCoordsFromNative(env, rawPointerCoords, event->getXOffset(), event->getYOffset(),
    652             outPointerCoordsObj);
    653 }
    654 
    655 static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz,
    656         jlong nativePtr, jint pointerIndex, jobject outPointerPropertiesObj) {
    657     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    658     size_t pointerCount = event->getPointerCount();
    659     if (!validatePointerIndex(env, pointerIndex, pointerCount)
    660             || !validatePointerProperties(env, outPointerPropertiesObj)) {
    661         return;
    662     }
    663 
    664     const PointerProperties* pointerProperties = event->getPointerProperties(pointerIndex);
    665     pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj);
    666 }
    667 
    668 static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz,
    669         jlong nativePtr, jfloat scale) {
    670     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    671     event->scale(scale);
    672 }
    673 
    674 static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz,
    675         jlong nativePtr, jobject matrixObj) {
    676     SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
    677     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    678 
    679     float m[9];
    680     m[0] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleX));
    681     m[1] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewX));
    682     m[2] = SkScalarToFloat(matrix->get(SkMatrix::kMTransX));
    683     m[3] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewY));
    684     m[4] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleY));
    685     m[5] = SkScalarToFloat(matrix->get(SkMatrix::kMTransY));
    686     m[6] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp0));
    687     m[7] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp1));
    688     m[8] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp2));
    689     event->transform(m);
    690 }
    691 
    692 static jlong android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
    693         jlong nativePtr, jobject parcelObj) {
    694     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    695     if (!event) {
    696         event = new MotionEvent();
    697     }
    698 
    699     Parcel* parcel = parcelForJavaObject(env, parcelObj);
    700 
    701     status_t status = event->readFromParcel(parcel);
    702     if (status) {
    703         if (!nativePtr) {
    704             delete event;
    705         }
    706         jniThrowRuntimeException(env, "Failed to read MotionEvent parcel.");
    707         return 0;
    708     }
    709     return reinterpret_cast<jlong>(event);
    710 }
    711 
    712 static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass clazz,
    713         jlong nativePtr, jobject parcelObj) {
    714     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    715     Parcel* parcel = parcelForJavaObject(env, parcelObj);
    716 
    717     status_t status = event->writeToParcel(parcel);
    718     if (status) {
    719         jniThrowRuntimeException(env, "Failed to write MotionEvent parcel.");
    720     }
    721 }
    722 
    723 static jstring android_view_MotionEvent_nativeAxisToString(JNIEnv* env, jclass clazz,
    724         jint axis) {
    725     return env->NewStringUTF(MotionEvent::getLabel(static_cast<int32_t>(axis)));
    726 }
    727 
    728 static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass clazz,
    729         jstring label) {
    730     ScopedUtfChars axisLabel(env, label);
    731     return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str()));
    732 }
    733 
    734 // ----------------------------------------------------------------------------
    735 
    736 static JNINativeMethod gMotionEventMethods[] = {
    737     /* name, signature, funcPtr */
    738     { "nativeInitialize",
    739             "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
    740                     "[Landroid/view/MotionEvent$PointerCoords;)J",
    741             (void*)android_view_MotionEvent_nativeInitialize },
    742     { "nativeCopy",
    743             "(JJZ)J",
    744             (void*)android_view_MotionEvent_nativeCopy },
    745     { "nativeDispose",
    746             "(J)V",
    747             (void*)android_view_MotionEvent_nativeDispose },
    748     { "nativeAddBatch",
    749             "(JJ[Landroid/view/MotionEvent$PointerCoords;I)V",
    750             (void*)android_view_MotionEvent_nativeAddBatch },
    751     { "nativeGetDeviceId",
    752             "(J)I",
    753             (void*)android_view_MotionEvent_nativeGetDeviceId },
    754     { "nativeGetSource",
    755             "(J)I",
    756             (void*)android_view_MotionEvent_nativeGetSource },
    757     { "nativeSetSource",
    758             "(JI)I",
    759             (void*)android_view_MotionEvent_nativeSetSource },
    760     { "nativeGetAction",
    761             "(J)I",
    762             (void*)android_view_MotionEvent_nativeGetAction },
    763     { "nativeSetAction",
    764             "(JI)V",
    765             (void*)android_view_MotionEvent_nativeSetAction },
    766     { "nativeIsTouchEvent",
    767             "(J)Z",
    768             (void*)android_view_MotionEvent_nativeIsTouchEvent },
    769     { "nativeGetFlags",
    770             "(J)I",
    771             (void*)android_view_MotionEvent_nativeGetFlags },
    772     { "nativeSetFlags",
    773             "(JI)V",
    774             (void*)android_view_MotionEvent_nativeSetFlags },
    775     { "nativeGetEdgeFlags",
    776             "(J)I",
    777             (void*)android_view_MotionEvent_nativeGetEdgeFlags },
    778     { "nativeSetEdgeFlags",
    779             "(JI)V",
    780             (void*)android_view_MotionEvent_nativeSetEdgeFlags },
    781     { "nativeGetMetaState",
    782             "(J)I",
    783             (void*)android_view_MotionEvent_nativeGetMetaState },
    784     { "nativeGetButtonState",
    785             "(J)I",
    786             (void*)android_view_MotionEvent_nativeGetButtonState },
    787     { "nativeOffsetLocation",
    788             "(JFF)V",
    789             (void*)android_view_MotionEvent_nativeOffsetLocation },
    790     { "nativeGetXOffset",
    791             "(J)F",
    792             (void*)android_view_MotionEvent_nativeGetXOffset },
    793     { "nativeGetYOffset",
    794             "(J)F",
    795             (void*)android_view_MotionEvent_nativeGetYOffset },
    796     { "nativeGetXPrecision",
    797             "(J)F",
    798             (void*)android_view_MotionEvent_nativeGetXPrecision },
    799     { "nativeGetYPrecision",
    800             "(J)F",
    801             (void*)android_view_MotionEvent_nativeGetYPrecision },
    802     { "nativeGetDownTimeNanos",
    803             "(J)J",
    804             (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
    805     { "nativeSetDownTimeNanos",
    806             "(JJ)V",
    807             (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
    808     { "nativeGetPointerCount",
    809             "(J)I",
    810             (void*)android_view_MotionEvent_nativeGetPointerCount },
    811     { "nativeGetPointerId",
    812             "(JI)I",
    813             (void*)android_view_MotionEvent_nativeGetPointerId },
    814     { "nativeGetToolType",
    815             "(JI)I",
    816             (void*)android_view_MotionEvent_nativeGetToolType },
    817     { "nativeFindPointerIndex",
    818             "(JI)I",
    819             (void*)android_view_MotionEvent_nativeFindPointerIndex },
    820     { "nativeGetHistorySize",
    821             "(J)I",
    822             (void*)android_view_MotionEvent_nativeGetHistorySize },
    823     { "nativeGetEventTimeNanos",
    824             "(JI)J",
    825             (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
    826     { "nativeGetRawAxisValue",
    827             "(JIII)F",
    828             (void*)android_view_MotionEvent_nativeGetRawAxisValue },
    829     { "nativeGetAxisValue",
    830             "(JIII)F",
    831             (void*)android_view_MotionEvent_nativeGetAxisValue },
    832     { "nativeGetPointerCoords",
    833             "(JIILandroid/view/MotionEvent$PointerCoords;)V",
    834             (void*)android_view_MotionEvent_nativeGetPointerCoords },
    835     { "nativeGetPointerProperties",
    836             "(JILandroid/view/MotionEvent$PointerProperties;)V",
    837             (void*)android_view_MotionEvent_nativeGetPointerProperties },
    838     { "nativeScale",
    839             "(JF)V",
    840             (void*)android_view_MotionEvent_nativeScale },
    841     { "nativeTransform",
    842             "(JLandroid/graphics/Matrix;)V",
    843             (void*)android_view_MotionEvent_nativeTransform },
    844     { "nativeReadFromParcel",
    845             "(JLandroid/os/Parcel;)J",
    846             (void*)android_view_MotionEvent_nativeReadFromParcel },
    847     { "nativeWriteToParcel",
    848             "(JLandroid/os/Parcel;)V",
    849             (void*)android_view_MotionEvent_nativeWriteToParcel },
    850     { "nativeAxisToString", "(I)Ljava/lang/String;",
    851             (void*)android_view_MotionEvent_nativeAxisToString },
    852     { "nativeAxisFromString", "(Ljava/lang/String;)I",
    853             (void*)android_view_MotionEvent_nativeAxisFromString },
    854 };
    855 
    856 #define FIND_CLASS(var, className) \
    857         var = env->FindClass(className); \
    858         LOG_FATAL_IF(! var, "Unable to find class " className);
    859 
    860 #define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
    861         var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
    862         LOG_FATAL_IF(! var, "Unable to find static method" methodName);
    863 
    864 #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
    865         var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
    866         LOG_FATAL_IF(! var, "Unable to find method" methodName);
    867 
    868 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
    869         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
    870         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
    871 
    872 int register_android_view_MotionEvent(JNIEnv* env) {
    873     int res = jniRegisterNativeMethods(env, "android/view/MotionEvent",
    874             gMotionEventMethods, NELEM(gMotionEventMethods));
    875     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
    876 
    877     FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
    878     gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
    879 
    880     GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz,
    881             "obtain", "()Landroid/view/MotionEvent;");
    882     GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
    883             "recycle", "()V");
    884     GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz,
    885             "mNativePtr", "J");
    886 
    887     jclass clazz;
    888     FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords");
    889 
    890     GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz,
    891             "mPackedAxisBits", "J");
    892     GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz,
    893             "mPackedAxisValues", "[F");
    894     GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz,
    895             "x", "F");
    896     GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz,
    897             "y", "F");
    898     GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz,
    899             "pressure", "F");
    900     GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz,
    901             "size", "F");
    902     GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz,
    903             "touchMajor", "F");
    904     GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz,
    905             "touchMinor", "F");
    906     GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz,
    907             "toolMajor", "F");
    908     GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz,
    909             "toolMinor", "F");
    910     GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz,
    911             "orientation", "F");
    912 
    913     FIND_CLASS(clazz, "android/view/MotionEvent$PointerProperties");
    914 
    915     GET_FIELD_ID(gPointerPropertiesClassInfo.id, clazz,
    916             "id", "I");
    917     GET_FIELD_ID(gPointerPropertiesClassInfo.toolType, clazz,
    918             "toolType", "I");
    919 
    920     return 0;
    921 }
    922 
    923 } // namespace android
    924