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