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