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