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 void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
    387         jlong nativePtr) {
    388     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    389     delete event;
    390 }
    391 
    392 static void android_view_MotionEvent_nativeAddBatch(JNIEnv* env, jclass clazz,
    393         jlong nativePtr, jlong eventTimeNanos, jobjectArray pointerCoordsObjArray,
    394         jint metaState) {
    395     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    396     size_t pointerCount = event->getPointerCount();
    397     if (!validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) {
    398         return;
    399     }
    400 
    401     PointerCoords rawPointerCoords[pointerCount];
    402 
    403     for (size_t i = 0; i < pointerCount; i++) {
    404         jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
    405         if (!pointerCoordsObj) {
    406             jniThrowNullPointerException(env, "pointerCoords");
    407             return;
    408         }
    409         pointerCoordsToNative(env, pointerCoordsObj,
    410                 event->getXOffset(), event->getYOffset(), &rawPointerCoords[i]);
    411         env->DeleteLocalRef(pointerCoordsObj);
    412     }
    413 
    414     event->addSample(eventTimeNanos, rawPointerCoords);
    415     event->setMetaState(event->getMetaState() | metaState);
    416 }
    417 
    418 static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz,
    419         jlong nativePtr, jint pointerIndex, jint historyPos, jobject outPointerCoordsObj) {
    420     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    421     size_t pointerCount = event->getPointerCount();
    422     if (!validatePointerIndex(env, pointerIndex, pointerCount)
    423             || !validatePointerCoords(env, outPointerCoordsObj)) {
    424         return;
    425     }
    426 
    427     const PointerCoords* rawPointerCoords;
    428     if (historyPos == HISTORY_CURRENT) {
    429         rawPointerCoords = event->getRawPointerCoords(pointerIndex);
    430     } else {
    431         size_t historySize = event->getHistorySize();
    432         if (!validateHistoryPos(env, historyPos, historySize)) {
    433             return;
    434         }
    435         rawPointerCoords = event->getHistoricalRawPointerCoords(pointerIndex, historyPos);
    436     }
    437     pointerCoordsFromNative(env, rawPointerCoords, event->getXOffset(), event->getYOffset(),
    438             outPointerCoordsObj);
    439 }
    440 
    441 static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz,
    442         jlong nativePtr, jint pointerIndex, jobject outPointerPropertiesObj) {
    443     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    444     size_t pointerCount = event->getPointerCount();
    445     if (!validatePointerIndex(env, pointerIndex, pointerCount)
    446             || !validatePointerProperties(env, outPointerPropertiesObj)) {
    447         return;
    448     }
    449 
    450     const PointerProperties* pointerProperties = event->getPointerProperties(pointerIndex);
    451     pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj);
    452 }
    453 
    454 static jlong android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
    455         jlong nativePtr, jobject parcelObj) {
    456     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    457     if (!event) {
    458         event = new MotionEvent();
    459     }
    460 
    461     Parcel* parcel = parcelForJavaObject(env, parcelObj);
    462 
    463     status_t status = event->readFromParcel(parcel);
    464     if (status) {
    465         if (!nativePtr) {
    466             delete event;
    467         }
    468         jniThrowRuntimeException(env, "Failed to read MotionEvent parcel.");
    469         return 0;
    470     }
    471     return reinterpret_cast<jlong>(event);
    472 }
    473 
    474 static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass clazz,
    475         jlong nativePtr, jobject parcelObj) {
    476     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    477     Parcel* parcel = parcelForJavaObject(env, parcelObj);
    478 
    479     status_t status = event->writeToParcel(parcel);
    480     if (status) {
    481         jniThrowRuntimeException(env, "Failed to write MotionEvent parcel.");
    482     }
    483 }
    484 
    485 static jstring android_view_MotionEvent_nativeAxisToString(JNIEnv* env, jclass clazz,
    486         jint axis) {
    487     return env->NewStringUTF(MotionEvent::getLabel(static_cast<int32_t>(axis)));
    488 }
    489 
    490 static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass clazz,
    491         jstring label) {
    492     ScopedUtfChars axisLabel(env, label);
    493     return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str()));
    494 }
    495 
    496 // ---------------- @FastNative ----------------------------------
    497 
    498 static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
    499         jlong nativePtr, jint pointerIndex) {
    500     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    501     size_t pointerCount = event->getPointerCount();
    502     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    503         return -1;
    504     }
    505     return event->getPointerId(pointerIndex);
    506 }
    507 
    508 static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
    509         jlong nativePtr, jint pointerIndex) {
    510     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    511     size_t pointerCount = event->getPointerCount();
    512     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    513         return -1;
    514     }
    515     return event->getToolType(pointerIndex);
    516 }
    517 
    518 static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
    519         jlong nativePtr, jint historyPos) {
    520     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    521     if (historyPos == HISTORY_CURRENT) {
    522         return event->getEventTime();
    523     } else {
    524         size_t historySize = event->getHistorySize();
    525         if (!validateHistoryPos(env, historyPos, historySize)) {
    526             return 0;
    527         }
    528         return event->getHistoricalEventTime(historyPos);
    529     }
    530 }
    531 
    532 static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
    533         jlong nativePtr, jint axis,
    534         jint pointerIndex, jint historyPos) {
    535     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    536     size_t pointerCount = event->getPointerCount();
    537     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    538         return 0;
    539     }
    540 
    541     if (historyPos == HISTORY_CURRENT) {
    542         return event->getRawAxisValue(axis, pointerIndex);
    543     } else {
    544         size_t historySize = event->getHistorySize();
    545         if (!validateHistoryPos(env, historyPos, historySize)) {
    546             return 0;
    547         }
    548         return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
    549     }
    550 }
    551 
    552 static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
    553         jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
    554     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    555     size_t pointerCount = event->getPointerCount();
    556     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
    557         return 0;
    558     }
    559 
    560     if (historyPos == HISTORY_CURRENT) {
    561         return event->getAxisValue(axis, pointerIndex);
    562     } else {
    563         size_t historySize = event->getHistorySize();
    564         if (!validateHistoryPos(env, historyPos, historySize)) {
    565             return 0;
    566         }
    567         return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
    568     }
    569 }
    570 
    571 // ----------------- @CriticalNative ------------------------------
    572 
    573 static jlong android_view_MotionEvent_nativeCopy(jlong destNativePtr, jlong sourceNativePtr,
    574         jboolean keepHistory) {
    575     MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
    576     if (!destEvent) {
    577         destEvent = new MotionEvent();
    578     }
    579     MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
    580     destEvent->copyFrom(sourceEvent, keepHistory);
    581     return reinterpret_cast<jlong>(destEvent);
    582 }
    583 
    584 static jint android_view_MotionEvent_nativeGetDeviceId(jlong nativePtr) {
    585     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    586     return event->getDeviceId();
    587 }
    588 
    589 static jint android_view_MotionEvent_nativeGetSource(jlong nativePtr) {
    590     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    591     return event->getSource();
    592 }
    593 
    594 static void android_view_MotionEvent_nativeSetSource(jlong nativePtr, jint source) {
    595     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    596     event->setSource(source);
    597 }
    598 
    599 static jint android_view_MotionEvent_nativeGetAction(jlong nativePtr) {
    600     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    601     return event->getAction();
    602 }
    603 
    604 static void android_view_MotionEvent_nativeSetAction(jlong nativePtr, jint action) {
    605     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    606     event->setAction(action);
    607 }
    608 
    609 static int android_view_MotionEvent_nativeGetActionButton(jlong nativePtr) {
    610     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    611     return event->getActionButton();
    612 }
    613 
    614 static void android_view_MotionEvent_nativeSetActionButton(jlong nativePtr, jint button) {
    615     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    616     event->setActionButton(button);
    617 }
    618 
    619 static jboolean android_view_MotionEvent_nativeIsTouchEvent(jlong nativePtr) {
    620     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    621     return event->isTouchEvent();
    622 }
    623 
    624 static jint android_view_MotionEvent_nativeGetFlags(jlong nativePtr) {
    625     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    626     return event->getFlags();
    627 }
    628 
    629 static void android_view_MotionEvent_nativeSetFlags(jlong nativePtr, jint flags) {
    630     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    631     event->setFlags(flags);
    632 }
    633 
    634 static jint android_view_MotionEvent_nativeGetEdgeFlags(jlong nativePtr) {
    635     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    636     return event->getEdgeFlags();
    637 }
    638 
    639 static void android_view_MotionEvent_nativeSetEdgeFlags(jlong nativePtr, jint edgeFlags) {
    640     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    641     event->setEdgeFlags(edgeFlags);
    642 }
    643 
    644 static jint android_view_MotionEvent_nativeGetMetaState(jlong nativePtr) {
    645     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    646     return event->getMetaState();
    647 }
    648 
    649 static jint android_view_MotionEvent_nativeGetButtonState(jlong nativePtr) {
    650     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    651     return event->getButtonState();
    652 }
    653 
    654 static void android_view_MotionEvent_nativeSetButtonState(jlong nativePtr, jint buttonState) {
    655     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    656     event->setButtonState(buttonState);
    657 }
    658 
    659 static void android_view_MotionEvent_nativeOffsetLocation(jlong nativePtr, jfloat deltaX,
    660         jfloat deltaY) {
    661     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    662     return event->offsetLocation(deltaX, deltaY);
    663 }
    664 
    665 static jfloat android_view_MotionEvent_nativeGetXOffset(jlong nativePtr) {
    666     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    667     return event->getXOffset();
    668 }
    669 
    670 static jfloat android_view_MotionEvent_nativeGetYOffset(jlong nativePtr) {
    671     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    672     return event->getYOffset();
    673 }
    674 
    675 static jfloat android_view_MotionEvent_nativeGetXPrecision(jlong nativePtr) {
    676     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    677     return event->getXPrecision();
    678 }
    679 
    680 static jfloat android_view_MotionEvent_nativeGetYPrecision(jlong nativePtr) {
    681     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    682     return event->getYPrecision();
    683 }
    684 
    685 static jlong android_view_MotionEvent_nativeGetDownTimeNanos(jlong nativePtr) {
    686     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    687     return event->getDownTime();
    688 }
    689 
    690 static void android_view_MotionEvent_nativeSetDownTimeNanos(jlong nativePtr, jlong downTimeNanos) {
    691     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    692     event->setDownTime(downTimeNanos);
    693 }
    694 
    695 static jint android_view_MotionEvent_nativeGetPointerCount(jlong nativePtr) {
    696     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    697     return jint(event->getPointerCount());
    698 }
    699 
    700 static jint android_view_MotionEvent_nativeFindPointerIndex(jlong nativePtr, jint pointerId) {
    701     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    702     return jint(event->findPointerIndex(pointerId));
    703 }
    704 
    705 static jint android_view_MotionEvent_nativeGetHistorySize(jlong nativePtr) {
    706     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    707     return jint(event->getHistorySize());
    708 }
    709 
    710 static void android_view_MotionEvent_nativeScale(jlong nativePtr, jfloat scale) {
    711     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    712     event->scale(scale);
    713 }
    714 
    715 static void android_view_MotionEvent_nativeTransform(jlong nativePtr, jlong matrixPtr) {
    716     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
    717     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
    718 
    719     static_assert(SkMatrix::kMScaleX == 0, "SkMatrix unexpected index");
    720     static_assert(SkMatrix::kMSkewX == 1, "SkMatrix unexpected index");
    721     static_assert(SkMatrix::kMTransX == 2, "SkMatrix unexpected index");
    722     static_assert(SkMatrix::kMSkewY == 3, "SkMatrix unexpected index");
    723     static_assert(SkMatrix::kMScaleY == 4, "SkMatrix unexpected index");
    724     static_assert(SkMatrix::kMTransY == 5, "SkMatrix unexpected index");
    725     static_assert(SkMatrix::kMPersp0 == 6, "SkMatrix unexpected index");
    726     static_assert(SkMatrix::kMPersp1 == 7, "SkMatrix unexpected index");
    727     static_assert(SkMatrix::kMPersp2 == 8, "SkMatrix unexpected index");
    728     float m[9];
    729     matrix->get9(m);
    730     event->transform(m);
    731 }
    732 
    733 // ----------------------------------------------------------------------------
    734 
    735 static const JNINativeMethod gMotionEventMethods[] = {
    736     /* name, signature, funcPtr */
    737     { "nativeInitialize",
    738             "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
    739                     "[Landroid/view/MotionEvent$PointerCoords;)J",
    740             (void*)android_view_MotionEvent_nativeInitialize },
    741     { "nativeDispose",
    742             "(J)V",
    743             (void*)android_view_MotionEvent_nativeDispose },
    744     { "nativeAddBatch",
    745             "(JJ[Landroid/view/MotionEvent$PointerCoords;I)V",
    746             (void*)android_view_MotionEvent_nativeAddBatch },
    747     { "nativeReadFromParcel",
    748             "(JLandroid/os/Parcel;)J",
    749             (void*)android_view_MotionEvent_nativeReadFromParcel },
    750     { "nativeWriteToParcel",
    751             "(JLandroid/os/Parcel;)V",
    752             (void*)android_view_MotionEvent_nativeWriteToParcel },
    753     { "nativeAxisToString", "(I)Ljava/lang/String;",
    754             (void*)android_view_MotionEvent_nativeAxisToString },
    755     { "nativeAxisFromString", "(Ljava/lang/String;)I",
    756             (void*)android_view_MotionEvent_nativeAxisFromString },
    757     { "nativeGetPointerProperties",
    758             "(JILandroid/view/MotionEvent$PointerProperties;)V",
    759             (void*)android_view_MotionEvent_nativeGetPointerProperties },
    760     { "nativeGetPointerCoords",
    761             "(JIILandroid/view/MotionEvent$PointerCoords;)V",
    762             (void*)android_view_MotionEvent_nativeGetPointerCoords },
    763 
    764     // --------------- @FastNative ----------------------
    765     { "nativeGetPointerId",
    766             "(JI)I",
    767             (void*)android_view_MotionEvent_nativeGetPointerId },
    768     { "nativeGetToolType",
    769             "(JI)I",
    770             (void*)android_view_MotionEvent_nativeGetToolType },
    771     { "nativeGetEventTimeNanos",
    772             "(JI)J",
    773             (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
    774     { "nativeGetRawAxisValue",
    775             "(JIII)F",
    776             (void*)android_view_MotionEvent_nativeGetRawAxisValue },
    777     { "nativeGetAxisValue",
    778             "(JIII)F",
    779             (void*)android_view_MotionEvent_nativeGetAxisValue },
    780 
    781     // --------------- @CriticalNative ------------------
    782 
    783     { "nativeCopy",
    784             "(JJZ)J",
    785             (void*)android_view_MotionEvent_nativeCopy },
    786     { "nativeGetDeviceId",
    787             "(J)I",
    788             (void*)android_view_MotionEvent_nativeGetDeviceId },
    789     { "nativeGetSource",
    790             "(J)I",
    791             (void*)android_view_MotionEvent_nativeGetSource },
    792     { "nativeSetSource",
    793             "(JI)I",
    794             (void*)android_view_MotionEvent_nativeSetSource },
    795     { "nativeGetAction",
    796             "(J)I",
    797             (void*)android_view_MotionEvent_nativeGetAction },
    798     { "nativeSetAction",
    799             "(JI)V",
    800             (void*)android_view_MotionEvent_nativeSetAction },
    801     { "nativeGetActionButton",
    802             "(J)I",
    803             (void*)android_view_MotionEvent_nativeGetActionButton},
    804     { "nativeSetActionButton",
    805             "(JI)V",
    806             (void*)android_view_MotionEvent_nativeSetActionButton},
    807     { "nativeIsTouchEvent",
    808             "(J)Z",
    809             (void*)android_view_MotionEvent_nativeIsTouchEvent },
    810     { "nativeGetFlags",
    811             "(J)I",
    812             (void*)android_view_MotionEvent_nativeGetFlags },
    813     { "nativeSetFlags",
    814             "(JI)V",
    815             (void*)android_view_MotionEvent_nativeSetFlags },
    816     { "nativeGetEdgeFlags",
    817             "(J)I",
    818             (void*)android_view_MotionEvent_nativeGetEdgeFlags },
    819     { "nativeSetEdgeFlags",
    820             "(JI)V",
    821             (void*)android_view_MotionEvent_nativeSetEdgeFlags },
    822     { "nativeGetMetaState",
    823             "(J)I",
    824             (void*)android_view_MotionEvent_nativeGetMetaState },
    825     { "nativeGetButtonState",
    826             "(J)I",
    827             (void*)android_view_MotionEvent_nativeGetButtonState },
    828     { "nativeSetButtonState",
    829             "(JI)V",
    830             (void*)android_view_MotionEvent_nativeSetButtonState },
    831     { "nativeOffsetLocation",
    832             "(JFF)V",
    833             (void*)android_view_MotionEvent_nativeOffsetLocation },
    834     { "nativeGetXOffset",
    835             "(J)F",
    836             (void*)android_view_MotionEvent_nativeGetXOffset },
    837     { "nativeGetYOffset",
    838             "(J)F",
    839             (void*)android_view_MotionEvent_nativeGetYOffset },
    840     { "nativeGetXPrecision",
    841             "(J)F",
    842             (void*)android_view_MotionEvent_nativeGetXPrecision },
    843     { "nativeGetYPrecision",
    844             "(J)F",
    845             (void*)android_view_MotionEvent_nativeGetYPrecision },
    846     { "nativeGetDownTimeNanos",
    847             "(J)J",
    848             (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
    849     { "nativeSetDownTimeNanos",
    850             "(JJ)V",
    851             (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
    852     { "nativeGetPointerCount",
    853             "(J)I",
    854             (void*)android_view_MotionEvent_nativeGetPointerCount },
    855     { "nativeFindPointerIndex",
    856             "(JI)I",
    857             (void*)android_view_MotionEvent_nativeFindPointerIndex },
    858     { "nativeGetHistorySize",
    859             "(J)I",
    860             (void*)android_view_MotionEvent_nativeGetHistorySize },
    861     { "nativeScale",
    862             "(JF)V",
    863             (void*)android_view_MotionEvent_nativeScale },
    864     { "nativeTransform",
    865             "(JJ)V",
    866             (void*)android_view_MotionEvent_nativeTransform },
    867 };
    868 
    869 int register_android_view_MotionEvent(JNIEnv* env) {
    870     int res = RegisterMethodsOrDie(env, "android/view/MotionEvent", gMotionEventMethods,
    871                                    NELEM(gMotionEventMethods));
    872 
    873     gMotionEventClassInfo.clazz = FindClassOrDie(env, "android/view/MotionEvent");
    874     gMotionEventClassInfo.clazz = MakeGlobalRefOrDie(env, gMotionEventClassInfo.clazz);
    875 
    876     gMotionEventClassInfo.obtain = GetStaticMethodIDOrDie(env, gMotionEventClassInfo.clazz,
    877             "obtain", "()Landroid/view/MotionEvent;");
    878     gMotionEventClassInfo.recycle = GetMethodIDOrDie(env, gMotionEventClassInfo.clazz,
    879             "recycle", "()V");
    880     gMotionEventClassInfo.mNativePtr = GetFieldIDOrDie(env, gMotionEventClassInfo.clazz,
    881             "mNativePtr", "J");
    882 
    883     jclass clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerCoords");
    884 
    885     gPointerCoordsClassInfo.mPackedAxisBits = GetFieldIDOrDie(env, clazz, "mPackedAxisBits", "J");
    886     gPointerCoordsClassInfo.mPackedAxisValues = GetFieldIDOrDie(env, clazz, "mPackedAxisValues",
    887                                                                 "[F");
    888     gPointerCoordsClassInfo.x = GetFieldIDOrDie(env, clazz, "x", "F");
    889     gPointerCoordsClassInfo.y = GetFieldIDOrDie(env, clazz, "y", "F");
    890     gPointerCoordsClassInfo.pressure = GetFieldIDOrDie(env, clazz, "pressure", "F");
    891     gPointerCoordsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "F");
    892     gPointerCoordsClassInfo.touchMajor = GetFieldIDOrDie(env, clazz, "touchMajor", "F");
    893     gPointerCoordsClassInfo.touchMinor = GetFieldIDOrDie(env, clazz, "touchMinor", "F");
    894     gPointerCoordsClassInfo.toolMajor = GetFieldIDOrDie(env, clazz, "toolMajor", "F");
    895     gPointerCoordsClassInfo.toolMinor = GetFieldIDOrDie(env, clazz, "toolMinor", "F");
    896     gPointerCoordsClassInfo.orientation = GetFieldIDOrDie(env, clazz, "orientation", "F");
    897 
    898     clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerProperties");
    899 
    900     gPointerPropertiesClassInfo.id = GetFieldIDOrDie(env, clazz, "id", "I");
    901     gPointerPropertiesClassInfo.toolType = GetFieldIDOrDie(env, clazz, "toolType", "I");
    902 
    903     return res;
    904 }
    905 
    906 } // namespace android
    907