• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <android_runtime/AndroidRuntime.h>
22 #include <utils/Log.h>
23 #include <androidfw/Input.h>
24 #include "android_os_Parcel.h"
25 #include "android_view_MotionEvent.h"
26 #include "android_util_Binder.h"
27 #include "android/graphics/Matrix.h"
28 
29 #include "SkMatrix.h"
30 
31 
32 namespace android {
33 
34 // ----------------------------------------------------------------------------
35 
36 static struct {
37     jclass clazz;
38 
39     jmethodID obtain;
40     jmethodID recycle;
41 
42     jfieldID mNativePtr;
43 } gMotionEventClassInfo;
44 
45 static struct {
46     jfieldID mPackedAxisBits;
47     jfieldID mPackedAxisValues;
48     jfieldID x;
49     jfieldID y;
50     jfieldID pressure;
51     jfieldID size;
52     jfieldID touchMajor;
53     jfieldID touchMinor;
54     jfieldID toolMajor;
55     jfieldID toolMinor;
56     jfieldID orientation;
57 } gPointerCoordsClassInfo;
58 
59 static struct {
60     jfieldID id;
61     jfieldID toolType;
62 } gPointerPropertiesClassInfo;
63 
64 // ----------------------------------------------------------------------------
65 
android_view_MotionEvent_getNativePtr(JNIEnv * env,jobject eventObj)66 MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) {
67     if (!eventObj) {
68         return NULL;
69     }
70     return reinterpret_cast<MotionEvent*>(
71             env->GetIntField(eventObj, gMotionEventClassInfo.mNativePtr));
72 }
73 
android_view_MotionEvent_setNativePtr(JNIEnv * env,jobject eventObj,MotionEvent * event)74 static void android_view_MotionEvent_setNativePtr(JNIEnv* env, jobject eventObj,
75         MotionEvent* event) {
76     env->SetIntField(eventObj, gMotionEventClassInfo.mNativePtr,
77             reinterpret_cast<int>(event));
78 }
79 
android_view_MotionEvent_obtainAsCopy(JNIEnv * env,const MotionEvent * event)80 jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent* event) {
81     jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,
82             gMotionEventClassInfo.obtain);
83     if (env->ExceptionCheck() || !eventObj) {
84         ALOGE("An exception occurred while obtaining a motion event.");
85         LOGE_EX(env);
86         env->ExceptionClear();
87         return NULL;
88     }
89 
90     MotionEvent* destEvent = android_view_MotionEvent_getNativePtr(env, eventObj);
91     if (!destEvent) {
92         destEvent = new MotionEvent();
93         android_view_MotionEvent_setNativePtr(env, eventObj, destEvent);
94     }
95 
96     destEvent->copyFrom(event, true);
97     return eventObj;
98 }
99 
android_view_MotionEvent_recycle(JNIEnv * env,jobject eventObj)100 status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
101     env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle);
102     if (env->ExceptionCheck()) {
103         ALOGW("An exception occurred while recycling a motion event.");
104         LOGW_EX(env);
105         env->ExceptionClear();
106         return UNKNOWN_ERROR;
107     }
108     return OK;
109 }
110 
111 // ----------------------------------------------------------------------------
112 
113 static const jint HISTORY_CURRENT = -0x80000000;
114 
validatePointerCount(JNIEnv * env,jint pointerCount)115 static bool validatePointerCount(JNIEnv* env, jint pointerCount) {
116     if (pointerCount < 1) {
117         jniThrowException(env, "java/lang/IllegalArgumentException",
118                 "pointerCount must be at least 1");
119         return false;
120     }
121     return true;
122 }
123 
validatePointerPropertiesArray(JNIEnv * env,jobjectArray pointerPropertiesObjArray,size_t pointerCount)124 static bool validatePointerPropertiesArray(JNIEnv* env, jobjectArray pointerPropertiesObjArray,
125         size_t pointerCount) {
126     if (!pointerPropertiesObjArray) {
127         jniThrowException(env, "java/lang/IllegalArgumentException",
128                 "pointerProperties array must not be null");
129         return false;
130     }
131     size_t length = size_t(env->GetArrayLength(pointerPropertiesObjArray));
132     if (length < pointerCount) {
133         jniThrowException(env, "java/lang/IllegalArgumentException",
134                 "pointerProperties array must be large enough to hold all pointers");
135         return false;
136     }
137     return true;
138 }
139 
validatePointerCoordsObjArray(JNIEnv * env,jobjectArray pointerCoordsObjArray,size_t pointerCount)140 static bool validatePointerCoordsObjArray(JNIEnv* env, jobjectArray pointerCoordsObjArray,
141         size_t pointerCount) {
142     if (!pointerCoordsObjArray) {
143         jniThrowException(env, "java/lang/IllegalArgumentException",
144                 "pointerCoords array must not be null");
145         return false;
146     }
147     size_t length = size_t(env->GetArrayLength(pointerCoordsObjArray));
148     if (length < pointerCount) {
149         jniThrowException(env, "java/lang/IllegalArgumentException",
150                 "pointerCoords array must be large enough to hold all pointers");
151         return false;
152     }
153     return true;
154 }
155 
validatePointerIndex(JNIEnv * env,jint pointerIndex,size_t pointerCount)156 static bool validatePointerIndex(JNIEnv* env, jint pointerIndex, size_t pointerCount) {
157     if (pointerIndex < 0 || size_t(pointerIndex) >= pointerCount) {
158         jniThrowException(env, "java/lang/IllegalArgumentException",
159                 "pointerIndex out of range");
160         return false;
161     }
162     return true;
163 }
164 
validateHistoryPos(JNIEnv * env,jint historyPos,size_t historySize)165 static bool validateHistoryPos(JNIEnv* env, jint historyPos, size_t historySize) {
166     if (historyPos < 0 || size_t(historyPos) >= historySize) {
167         jniThrowException(env, "java/lang/IllegalArgumentException",
168                 "historyPos out of range");
169         return false;
170     }
171     return true;
172 }
173 
validatePointerCoords(JNIEnv * env,jobject pointerCoordsObj)174 static bool validatePointerCoords(JNIEnv* env, jobject pointerCoordsObj) {
175     if (!pointerCoordsObj) {
176         jniThrowException(env, "java/lang/IllegalArgumentException",
177                 "pointerCoords must not be null");
178         return false;
179     }
180     return true;
181 }
182 
validatePointerProperties(JNIEnv * env,jobject pointerPropertiesObj)183 static bool validatePointerProperties(JNIEnv* env, jobject pointerPropertiesObj) {
184     if (!pointerPropertiesObj) {
185         jniThrowException(env, "java/lang/IllegalArgumentException",
186                 "pointerProperties must not be null");
187         return false;
188     }
189     return true;
190 }
191 
pointerCoordsToNative(JNIEnv * env,jobject pointerCoordsObj,float xOffset,float yOffset,PointerCoords * outRawPointerCoords)192 static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj,
193         float xOffset, float yOffset, PointerCoords* outRawPointerCoords) {
194     outRawPointerCoords->clear();
195     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_X,
196             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.x) - xOffset);
197     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_Y,
198             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.y) - yOffset);
199     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
200             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.pressure));
201     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_SIZE,
202             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.size));
203     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
204             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMajor));
205     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR,
206             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMinor));
207     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR,
208             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMajor));
209     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR,
210             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor));
211     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
212             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));
213 
214     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 
obtainPackedAxisValuesArray(JNIEnv * env,uint32_t minSize,jobject outPointerCoordsObj)236 static 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 
pointerCoordsFromNative(JNIEnv * env,const PointerCoords * rawPointerCoords,float xOffset,float yOffset,jobject outPointerCoordsObj)257 static 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 
pointerPropertiesToNative(JNIEnv * env,jobject pointerPropertiesObj,PointerProperties * outPointerProperties)318 static 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 
pointerPropertiesFromNative(JNIEnv * env,const PointerProperties * pointerProperties,jobject outPointerPropertiesObj)327 static 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 
android_view_MotionEvent_nativeInitialize(JNIEnv * env,jclass clazz,jint 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)338 static jint android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz,
339         jint 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<jint>(event);
382 
383 Error:
384     if (!nativePtr) {
385         delete event;
386     }
387     return 0;
388 }
389 
android_view_MotionEvent_nativeCopy(JNIEnv * env,jclass clazz,jint destNativePtr,jint sourceNativePtr,jboolean keepHistory)390 static jint android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz,
391         jint destNativePtr, jint 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<jint>(destEvent);
399 }
400 
android_view_MotionEvent_nativeDispose(JNIEnv * env,jclass clazz,jint nativePtr)401 static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
402         jint nativePtr) {
403     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
404     delete event;
405 }
406 
android_view_MotionEvent_nativeAddBatch(JNIEnv * env,jclass clazz,jint nativePtr,jlong eventTimeNanos,jobjectArray pointerCoordsObjArray,jint metaState)407 static void android_view_MotionEvent_nativeAddBatch(JNIEnv* env, jclass clazz,
408         jint 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 
android_view_MotionEvent_nativeGetDeviceId(JNIEnv * env,jclass clazz,jint nativePtr)433 static jint android_view_MotionEvent_nativeGetDeviceId(JNIEnv* env, jclass clazz,
434         jint nativePtr) {
435     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
436     return event->getDeviceId();
437 }
438 
android_view_MotionEvent_nativeGetSource(JNIEnv * env,jclass clazz,jint nativePtr)439 static jint android_view_MotionEvent_nativeGetSource(JNIEnv* env, jclass clazz,
440         jint nativePtr) {
441     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
442     return event->getSource();
443 }
444 
android_view_MotionEvent_nativeSetSource(JNIEnv * env,jclass clazz,jint nativePtr,jint source)445 static void android_view_MotionEvent_nativeSetSource(JNIEnv* env, jclass clazz,
446         jint nativePtr, jint source) {
447     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
448     event->setSource(source);
449 }
450 
android_view_MotionEvent_nativeGetAction(JNIEnv * env,jclass clazz,jint nativePtr)451 static jint android_view_MotionEvent_nativeGetAction(JNIEnv* env, jclass clazz,
452         jint nativePtr) {
453     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
454     return event->getAction();
455 }
456 
android_view_MotionEvent_nativeSetAction(JNIEnv * env,jclass clazz,jint nativePtr,jint action)457 static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz,
458         jint nativePtr, jint action) {
459     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
460     event->setAction(action);
461 }
462 
android_view_MotionEvent_nativeIsTouchEvent(JNIEnv * env,jclass clazz,jint nativePtr)463 static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz,
464         jint nativePtr) {
465     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
466     return event->isTouchEvent();
467 }
468 
android_view_MotionEvent_nativeGetFlags(JNIEnv * env,jclass clazz,jint nativePtr)469 static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz,
470         jint nativePtr) {
471     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
472     return event->getFlags();
473 }
474 
android_view_MotionEvent_nativeSetFlags(JNIEnv * env,jclass clazz,jint nativePtr,jint flags)475 static void android_view_MotionEvent_nativeSetFlags(JNIEnv* env, jclass clazz,
476         jint nativePtr, jint flags) {
477     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
478     event->setFlags(flags);
479 }
480 
android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv * env,jclass clazz,jint nativePtr)481 static jint android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv* env, jclass clazz,
482         jint nativePtr) {
483     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
484     return event->getEdgeFlags();
485 }
486 
android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv * env,jclass clazz,jint nativePtr,jint edgeFlags)487 static void android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv* env, jclass clazz,
488         jint nativePtr, jint edgeFlags) {
489     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
490     event->setEdgeFlags(edgeFlags);
491 }
492 
android_view_MotionEvent_nativeGetMetaState(JNIEnv * env,jclass clazz,jint nativePtr)493 static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass clazz,
494         jint nativePtr) {
495     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
496     return event->getMetaState();
497 }
498 
android_view_MotionEvent_nativeGetButtonState(JNIEnv * env,jclass clazz,jint nativePtr)499 static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz,
500         jint nativePtr) {
501     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
502     return event->getButtonState();
503 }
504 
android_view_MotionEvent_nativeOffsetLocation(JNIEnv * env,jclass clazz,jint nativePtr,jfloat deltaX,jfloat deltaY)505 static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz,
506         jint nativePtr, jfloat deltaX, jfloat deltaY) {
507     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
508     return event->offsetLocation(deltaX, deltaY);
509 }
510 
android_view_MotionEvent_nativeGetXOffset(JNIEnv * env,jclass clazz,jint nativePtr)511 static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz,
512         jint nativePtr) {
513     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
514     return event->getXOffset();
515 }
516 
android_view_MotionEvent_nativeGetYOffset(JNIEnv * env,jclass clazz,jint nativePtr)517 static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz,
518         jint nativePtr) {
519     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
520     return event->getYOffset();
521 }
522 
android_view_MotionEvent_nativeGetXPrecision(JNIEnv * env,jclass clazz,jint nativePtr)523 static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz,
524         jint nativePtr) {
525     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
526     return event->getXPrecision();
527 }
528 
android_view_MotionEvent_nativeGetYPrecision(JNIEnv * env,jclass clazz,jint nativePtr)529 static jfloat android_view_MotionEvent_nativeGetYPrecision(JNIEnv* env, jclass clazz,
530         jint nativePtr) {
531     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
532     return event->getYPrecision();
533 }
534 
android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv * env,jclass clazz,jint nativePtr)535 static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass clazz,
536         jint nativePtr) {
537     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
538     return event->getDownTime();
539 }
540 
android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv * env,jclass clazz,jint nativePtr,jlong downTimeNanos)541 static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz,
542         jint nativePtr, jlong downTimeNanos) {
543     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
544     event->setDownTime(downTimeNanos);
545 }
546 
android_view_MotionEvent_nativeGetPointerCount(JNIEnv * env,jclass clazz,jint nativePtr)547 static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz,
548         jint nativePtr) {
549     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
550     return jint(event->getPointerCount());
551 }
552 
android_view_MotionEvent_nativeGetPointerId(JNIEnv * env,jclass clazz,jint nativePtr,jint pointerIndex)553 static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
554         jint 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 
android_view_MotionEvent_nativeGetToolType(JNIEnv * env,jclass clazz,jint nativePtr,jint pointerIndex)563 static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
564         jint 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 
android_view_MotionEvent_nativeFindPointerIndex(JNIEnv * env,jclass clazz,jint nativePtr,jint pointerId)573 static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz,
574         jint nativePtr, jint pointerId) {
575     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
576     return jint(event->findPointerIndex(pointerId));
577 }
578 
android_view_MotionEvent_nativeGetHistorySize(JNIEnv * env,jclass clazz,jint nativePtr)579 static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz,
580         jint nativePtr) {
581     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
582     return jint(event->getHistorySize());
583 }
584 
android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv * env,jclass clazz,jint nativePtr,jint historyPos)585 static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
586         jint 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 
android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv * env,jclass clazz,jint nativePtr,jint axis,jint pointerIndex,jint historyPos)599 static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
600         jint 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 
android_view_MotionEvent_nativeGetAxisValue(JNIEnv * env,jclass clazz,jint nativePtr,jint axis,jint pointerIndex,jint historyPos)618 static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
619         jint 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 
android_view_MotionEvent_nativeGetPointerCoords(JNIEnv * env,jclass clazz,jint nativePtr,jint pointerIndex,jint historyPos,jobject outPointerCoordsObj)637 static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz,
638         jint 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 
android_view_MotionEvent_nativeGetPointerProperties(JNIEnv * env,jclass clazz,jint nativePtr,jint pointerIndex,jobject outPointerPropertiesObj)660 static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz,
661         jint 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 
android_view_MotionEvent_nativeScale(JNIEnv * env,jclass clazz,jint nativePtr,jfloat scale)673 static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz,
674         jint nativePtr, jfloat scale) {
675     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
676     event->scale(scale);
677 }
678 
android_view_MotionEvent_nativeTransform(JNIEnv * env,jclass clazz,jint nativePtr,jobject matrixObj)679 static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz,
680         jint nativePtr, jobject matrixObj) {
681     SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
682     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
683     event->transform(matrix);
684 }
685 
android_view_MotionEvent_nativeReadFromParcel(JNIEnv * env,jclass clazz,jint nativePtr,jobject parcelObj)686 static jint android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
687         jint nativePtr, jobject parcelObj) {
688     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
689     if (!event) {
690         event = new MotionEvent();
691     }
692 
693     Parcel* parcel = parcelForJavaObject(env, parcelObj);
694 
695     status_t status = event->readFromParcel(parcel);
696     if (status) {
697         if (!nativePtr) {
698             delete event;
699         }
700         jniThrowRuntimeException(env, "Failed to read MotionEvent parcel.");
701         return 0;
702     }
703     return reinterpret_cast<jint>(event);
704 }
705 
android_view_MotionEvent_nativeWriteToParcel(JNIEnv * env,jclass clazz,jint nativePtr,jobject parcelObj)706 static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass clazz,
707         jint nativePtr, jobject parcelObj) {
708     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
709     Parcel* parcel = parcelForJavaObject(env, parcelObj);
710 
711     status_t status = event->writeToParcel(parcel);
712     if (status) {
713         jniThrowRuntimeException(env, "Failed to write MotionEvent parcel.");
714     }
715 }
716 
717 // ----------------------------------------------------------------------------
718 
719 static JNINativeMethod gMotionEventMethods[] = {
720     /* name, signature, funcPtr */
721     { "nativeInitialize",
722             "(IIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
723                     "[Landroid/view/MotionEvent$PointerCoords;)I",
724             (void*)android_view_MotionEvent_nativeInitialize },
725     { "nativeCopy",
726             "(IIZ)I",
727             (void*)android_view_MotionEvent_nativeCopy },
728     { "nativeDispose",
729             "(I)V",
730             (void*)android_view_MotionEvent_nativeDispose },
731     { "nativeAddBatch",
732             "(IJ[Landroid/view/MotionEvent$PointerCoords;I)V",
733             (void*)android_view_MotionEvent_nativeAddBatch },
734     { "nativeGetDeviceId",
735             "(I)I",
736             (void*)android_view_MotionEvent_nativeGetDeviceId },
737     { "nativeGetSource",
738             "(I)I",
739             (void*)android_view_MotionEvent_nativeGetSource },
740     { "nativeSetSource",
741             "(II)I",
742             (void*)android_view_MotionEvent_nativeSetSource },
743     { "nativeGetAction",
744             "(I)I",
745             (void*)android_view_MotionEvent_nativeGetAction },
746     { "nativeSetAction",
747             "(II)V",
748             (void*)android_view_MotionEvent_nativeSetAction },
749     { "nativeIsTouchEvent",
750             "(I)Z",
751             (void*)android_view_MotionEvent_nativeIsTouchEvent },
752     { "nativeGetFlags",
753             "(I)I",
754             (void*)android_view_MotionEvent_nativeGetFlags },
755     { "nativeSetFlags",
756             "(II)V",
757             (void*)android_view_MotionEvent_nativeSetFlags },
758     { "nativeGetEdgeFlags",
759             "(I)I",
760             (void*)android_view_MotionEvent_nativeGetEdgeFlags },
761     { "nativeSetEdgeFlags",
762             "(II)V",
763             (void*)android_view_MotionEvent_nativeSetEdgeFlags },
764     { "nativeGetMetaState",
765             "(I)I",
766             (void*)android_view_MotionEvent_nativeGetMetaState },
767     { "nativeGetButtonState",
768             "(I)I",
769             (void*)android_view_MotionEvent_nativeGetButtonState },
770     { "nativeOffsetLocation",
771             "(IFF)V",
772             (void*)android_view_MotionEvent_nativeOffsetLocation },
773     { "nativeGetXOffset",
774             "(I)F",
775             (void*)android_view_MotionEvent_nativeGetXOffset },
776     { "nativeGetYOffset",
777             "(I)F",
778             (void*)android_view_MotionEvent_nativeGetYOffset },
779     { "nativeGetXPrecision",
780             "(I)F",
781             (void*)android_view_MotionEvent_nativeGetXPrecision },
782     { "nativeGetYPrecision",
783             "(I)F",
784             (void*)android_view_MotionEvent_nativeGetYPrecision },
785     { "nativeGetDownTimeNanos",
786             "(I)J",
787             (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
788     { "nativeSetDownTimeNanos",
789             "(IJ)V",
790             (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
791     { "nativeGetPointerCount",
792             "(I)I",
793             (void*)android_view_MotionEvent_nativeGetPointerCount },
794     { "nativeGetPointerId",
795             "(II)I",
796             (void*)android_view_MotionEvent_nativeGetPointerId },
797     { "nativeGetToolType",
798             "(II)I",
799             (void*)android_view_MotionEvent_nativeGetToolType },
800     { "nativeFindPointerIndex",
801             "(II)I",
802             (void*)android_view_MotionEvent_nativeFindPointerIndex },
803     { "nativeGetHistorySize",
804             "(I)I",
805             (void*)android_view_MotionEvent_nativeGetHistorySize },
806     { "nativeGetEventTimeNanos",
807             "(II)J",
808             (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
809     { "nativeGetRawAxisValue",
810             "(IIII)F",
811             (void*)android_view_MotionEvent_nativeGetRawAxisValue },
812     { "nativeGetAxisValue",
813             "(IIII)F",
814             (void*)android_view_MotionEvent_nativeGetAxisValue },
815     { "nativeGetPointerCoords",
816             "(IIILandroid/view/MotionEvent$PointerCoords;)V",
817             (void*)android_view_MotionEvent_nativeGetPointerCoords },
818     { "nativeGetPointerProperties",
819             "(IILandroid/view/MotionEvent$PointerProperties;)V",
820             (void*)android_view_MotionEvent_nativeGetPointerProperties },
821     { "nativeScale",
822             "(IF)V",
823             (void*)android_view_MotionEvent_nativeScale },
824     { "nativeTransform",
825             "(ILandroid/graphics/Matrix;)V",
826             (void*)android_view_MotionEvent_nativeTransform },
827     { "nativeReadFromParcel",
828             "(ILandroid/os/Parcel;)I",
829             (void*)android_view_MotionEvent_nativeReadFromParcel },
830     { "nativeWriteToParcel",
831             "(ILandroid/os/Parcel;)V",
832             (void*)android_view_MotionEvent_nativeWriteToParcel },
833 };
834 
835 #define FIND_CLASS(var, className) \
836         var = env->FindClass(className); \
837         LOG_FATAL_IF(! var, "Unable to find class " className);
838 
839 #define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
840         var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
841         LOG_FATAL_IF(! var, "Unable to find static method" methodName);
842 
843 #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
844         var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
845         LOG_FATAL_IF(! var, "Unable to find method" methodName);
846 
847 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
848         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
849         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
850 
register_android_view_MotionEvent(JNIEnv * env)851 int register_android_view_MotionEvent(JNIEnv* env) {
852     int res = jniRegisterNativeMethods(env, "android/view/MotionEvent",
853             gMotionEventMethods, NELEM(gMotionEventMethods));
854     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
855 
856     FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
857     gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
858 
859     GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz,
860             "obtain", "()Landroid/view/MotionEvent;");
861     GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
862             "recycle", "()V");
863     GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz,
864             "mNativePtr", "I");
865 
866     jclass clazz;
867     FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords");
868 
869     GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz,
870             "mPackedAxisBits", "J");
871     GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz,
872             "mPackedAxisValues", "[F");
873     GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz,
874             "x", "F");
875     GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz,
876             "y", "F");
877     GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz,
878             "pressure", "F");
879     GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz,
880             "size", "F");
881     GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz,
882             "touchMajor", "F");
883     GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz,
884             "touchMinor", "F");
885     GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz,
886             "toolMajor", "F");
887     GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz,
888             "toolMinor", "F");
889     GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz,
890             "orientation", "F");
891 
892     FIND_CLASS(clazz, "android/view/MotionEvent$PointerProperties");
893 
894     GET_FIELD_ID(gPointerPropertiesClassInfo.id, clazz,
895             "id", "I");
896     GET_FIELD_ID(gPointerPropertiesClassInfo.toolType, clazz,
897             "toolType", "I");
898 
899     return 0;
900 }
901 
902 } // namespace android
903