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