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