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_nativeCopy(JNIEnv * env,jclass clazz,jlong destNativePtr,jlong sourceNativePtr,jboolean keepHistory)386 static jlong android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz,
387         jlong destNativePtr, jlong sourceNativePtr, jboolean keepHistory) {
388     MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
389     if (!destEvent) {
390         destEvent = new MotionEvent();
391     }
392     MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
393     destEvent->copyFrom(sourceEvent, keepHistory);
394     return reinterpret_cast<jlong>(destEvent);
395 }
396 
android_view_MotionEvent_nativeDispose(JNIEnv * env,jclass clazz,jlong nativePtr)397 static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
398         jlong nativePtr) {
399     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
400     delete event;
401 }
402 
android_view_MotionEvent_nativeAddBatch(JNIEnv * env,jclass clazz,jlong nativePtr,jlong eventTimeNanos,jobjectArray pointerCoordsObjArray,jint metaState)403 static void android_view_MotionEvent_nativeAddBatch(JNIEnv* env, jclass clazz,
404         jlong nativePtr, jlong eventTimeNanos, jobjectArray pointerCoordsObjArray,
405         jint metaState) {
406     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
407     size_t pointerCount = event->getPointerCount();
408     if (!validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) {
409         return;
410     }
411 
412     PointerCoords rawPointerCoords[pointerCount];
413 
414     for (size_t i = 0; i < pointerCount; i++) {
415         jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
416         if (!pointerCoordsObj) {
417             jniThrowNullPointerException(env, "pointerCoords");
418             return;
419         }
420         pointerCoordsToNative(env, pointerCoordsObj,
421                 event->getXOffset(), event->getYOffset(), &rawPointerCoords[i]);
422         env->DeleteLocalRef(pointerCoordsObj);
423     }
424 
425     event->addSample(eventTimeNanos, rawPointerCoords);
426     event->setMetaState(event->getMetaState() | metaState);
427 }
428 
android_view_MotionEvent_nativeGetDeviceId(JNIEnv * env,jclass clazz,jlong nativePtr)429 static jint android_view_MotionEvent_nativeGetDeviceId(JNIEnv* env, jclass clazz,
430         jlong nativePtr) {
431     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
432     return event->getDeviceId();
433 }
434 
android_view_MotionEvent_nativeGetSource(JNIEnv * env,jclass clazz,jlong nativePtr)435 static jint android_view_MotionEvent_nativeGetSource(JNIEnv* env, jclass clazz,
436         jlong nativePtr) {
437     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
438     return event->getSource();
439 }
440 
android_view_MotionEvent_nativeSetSource(JNIEnv * env,jclass clazz,jlong nativePtr,jint source)441 static void android_view_MotionEvent_nativeSetSource(JNIEnv* env, jclass clazz,
442         jlong nativePtr, jint source) {
443     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
444     event->setSource(source);
445 }
446 
android_view_MotionEvent_nativeGetAction(JNIEnv * env,jclass clazz,jlong nativePtr)447 static jint android_view_MotionEvent_nativeGetAction(JNIEnv* env, jclass clazz,
448         jlong nativePtr) {
449     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
450     return event->getAction();
451 }
452 
android_view_MotionEvent_nativeSetAction(JNIEnv * env,jclass clazz,jlong nativePtr,jint action)453 static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz,
454         jlong nativePtr, jint action) {
455     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
456     event->setAction(action);
457 }
458 
android_view_MotionEvent_nativeGetActionButton(JNIEnv * env,jclass clazz,jlong nativePtr)459 static int android_view_MotionEvent_nativeGetActionButton(JNIEnv* env, jclass clazz,
460         jlong nativePtr) {
461     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
462     return event->getActionButton();
463 }
464 
android_view_MotionEvent_nativeSetActionButton(JNIEnv * env,jclass clazz,jlong nativePtr,jint button)465 static void android_view_MotionEvent_nativeSetActionButton(JNIEnv* env, jclass clazz,
466         jlong nativePtr, jint button) {
467     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
468     event->setActionButton(button);
469 }
470 
android_view_MotionEvent_nativeIsTouchEvent(JNIEnv * env,jclass clazz,jlong nativePtr)471 static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz,
472         jlong nativePtr) {
473     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
474     return event->isTouchEvent();
475 }
476 
android_view_MotionEvent_nativeGetFlags(JNIEnv * env,jclass clazz,jlong nativePtr)477 static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz,
478         jlong nativePtr) {
479     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
480     return event->getFlags();
481 }
482 
android_view_MotionEvent_nativeSetFlags(JNIEnv * env,jclass clazz,jlong nativePtr,jint flags)483 static void android_view_MotionEvent_nativeSetFlags(JNIEnv* env, jclass clazz,
484         jlong nativePtr, jint flags) {
485     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
486     event->setFlags(flags);
487 }
488 
android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv * env,jclass clazz,jlong nativePtr)489 static jint android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv* env, jclass clazz,
490         jlong nativePtr) {
491     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
492     return event->getEdgeFlags();
493 }
494 
android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv * env,jclass clazz,jlong nativePtr,jint edgeFlags)495 static void android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv* env, jclass clazz,
496         jlong nativePtr, jint edgeFlags) {
497     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
498     event->setEdgeFlags(edgeFlags);
499 }
500 
android_view_MotionEvent_nativeGetMetaState(JNIEnv * env,jclass clazz,jlong nativePtr)501 static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass clazz,
502         jlong nativePtr) {
503     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
504     return event->getMetaState();
505 }
506 
android_view_MotionEvent_nativeGetButtonState(JNIEnv * env,jclass clazz,jlong nativePtr)507 static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz,
508         jlong nativePtr) {
509     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
510     return event->getButtonState();
511 }
512 
android_view_MotionEvent_nativeSetButtonState(JNIEnv * env,jclass clazz,jlong nativePtr,jint buttonState)513 static void android_view_MotionEvent_nativeSetButtonState(JNIEnv* env, jclass clazz,
514         jlong nativePtr, jint buttonState) {
515     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
516     event->setButtonState(buttonState);
517 }
518 
android_view_MotionEvent_nativeOffsetLocation(JNIEnv * env,jclass clazz,jlong nativePtr,jfloat deltaX,jfloat deltaY)519 static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz,
520         jlong nativePtr, jfloat deltaX, jfloat deltaY) {
521     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
522     return event->offsetLocation(deltaX, deltaY);
523 }
524 
android_view_MotionEvent_nativeGetXOffset(JNIEnv * env,jclass clazz,jlong nativePtr)525 static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz,
526         jlong nativePtr) {
527     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
528     return event->getXOffset();
529 }
530 
android_view_MotionEvent_nativeGetYOffset(JNIEnv * env,jclass clazz,jlong nativePtr)531 static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz,
532         jlong nativePtr) {
533     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
534     return event->getYOffset();
535 }
536 
android_view_MotionEvent_nativeGetXPrecision(JNIEnv * env,jclass clazz,jlong nativePtr)537 static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz,
538         jlong nativePtr) {
539     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
540     return event->getXPrecision();
541 }
542 
android_view_MotionEvent_nativeGetYPrecision(JNIEnv * env,jclass clazz,jlong nativePtr)543 static jfloat android_view_MotionEvent_nativeGetYPrecision(JNIEnv* env, jclass clazz,
544         jlong nativePtr) {
545     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
546     return event->getYPrecision();
547 }
548 
android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv * env,jclass clazz,jlong nativePtr)549 static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass clazz,
550         jlong nativePtr) {
551     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
552     return event->getDownTime();
553 }
554 
android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv * env,jclass clazz,jlong nativePtr,jlong downTimeNanos)555 static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz,
556         jlong nativePtr, jlong downTimeNanos) {
557     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
558     event->setDownTime(downTimeNanos);
559 }
560 
android_view_MotionEvent_nativeGetPointerCount(JNIEnv * env,jclass clazz,jlong nativePtr)561 static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz,
562         jlong nativePtr) {
563     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
564     return jint(event->getPointerCount());
565 }
566 
android_view_MotionEvent_nativeGetPointerId(JNIEnv * env,jclass clazz,jlong nativePtr,jint pointerIndex)567 static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
568         jlong nativePtr, jint pointerIndex) {
569     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
570     size_t pointerCount = event->getPointerCount();
571     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
572         return -1;
573     }
574     return event->getPointerId(pointerIndex);
575 }
576 
android_view_MotionEvent_nativeGetToolType(JNIEnv * env,jclass clazz,jlong nativePtr,jint pointerIndex)577 static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
578         jlong nativePtr, jint pointerIndex) {
579     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
580     size_t pointerCount = event->getPointerCount();
581     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
582         return -1;
583     }
584     return event->getToolType(pointerIndex);
585 }
586 
android_view_MotionEvent_nativeFindPointerIndex(JNIEnv * env,jclass clazz,jlong nativePtr,jint pointerId)587 static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz,
588         jlong nativePtr, jint pointerId) {
589     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
590     return jint(event->findPointerIndex(pointerId));
591 }
592 
android_view_MotionEvent_nativeGetHistorySize(JNIEnv * env,jclass clazz,jlong nativePtr)593 static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz,
594         jlong nativePtr) {
595     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
596     return jint(event->getHistorySize());
597 }
598 
android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv * env,jclass clazz,jlong nativePtr,jint historyPos)599 static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
600         jlong nativePtr, jint historyPos) {
601     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
602     if (historyPos == HISTORY_CURRENT) {
603         return event->getEventTime();
604     } else {
605         size_t historySize = event->getHistorySize();
606         if (!validateHistoryPos(env, historyPos, historySize)) {
607             return 0;
608         }
609         return event->getHistoricalEventTime(historyPos);
610     }
611 }
612 
android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv * env,jclass clazz,jlong nativePtr,jint axis,jint pointerIndex,jint historyPos)613 static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
614         jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
615     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
616     size_t pointerCount = event->getPointerCount();
617     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
618         return 0;
619     }
620 
621     if (historyPos == HISTORY_CURRENT) {
622         return event->getRawAxisValue(axis, pointerIndex);
623     } else {
624         size_t historySize = event->getHistorySize();
625         if (!validateHistoryPos(env, historyPos, historySize)) {
626             return 0;
627         }
628         return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
629     }
630 }
631 
android_view_MotionEvent_nativeGetAxisValue(JNIEnv * env,jclass clazz,jlong nativePtr,jint axis,jint pointerIndex,jint historyPos)632 static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
633         jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
634     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
635     size_t pointerCount = event->getPointerCount();
636     if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
637         return 0;
638     }
639 
640     if (historyPos == HISTORY_CURRENT) {
641         return event->getAxisValue(axis, pointerIndex);
642     } else {
643         size_t historySize = event->getHistorySize();
644         if (!validateHistoryPos(env, historyPos, historySize)) {
645             return 0;
646         }
647         return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
648     }
649 }
650 
android_view_MotionEvent_nativeGetPointerCoords(JNIEnv * env,jclass clazz,jlong nativePtr,jint pointerIndex,jint historyPos,jobject outPointerCoordsObj)651 static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz,
652         jlong nativePtr, jint pointerIndex, jint historyPos, jobject outPointerCoordsObj) {
653     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
654     size_t pointerCount = event->getPointerCount();
655     if (!validatePointerIndex(env, pointerIndex, pointerCount)
656             || !validatePointerCoords(env, outPointerCoordsObj)) {
657         return;
658     }
659 
660     const PointerCoords* rawPointerCoords;
661     if (historyPos == HISTORY_CURRENT) {
662         rawPointerCoords = event->getRawPointerCoords(pointerIndex);
663     } else {
664         size_t historySize = event->getHistorySize();
665         if (!validateHistoryPos(env, historyPos, historySize)) {
666             return;
667         }
668         rawPointerCoords = event->getHistoricalRawPointerCoords(pointerIndex, historyPos);
669     }
670     pointerCoordsFromNative(env, rawPointerCoords, event->getXOffset(), event->getYOffset(),
671             outPointerCoordsObj);
672 }
673 
android_view_MotionEvent_nativeGetPointerProperties(JNIEnv * env,jclass clazz,jlong nativePtr,jint pointerIndex,jobject outPointerPropertiesObj)674 static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz,
675         jlong nativePtr, jint pointerIndex, jobject outPointerPropertiesObj) {
676     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
677     size_t pointerCount = event->getPointerCount();
678     if (!validatePointerIndex(env, pointerIndex, pointerCount)
679             || !validatePointerProperties(env, outPointerPropertiesObj)) {
680         return;
681     }
682 
683     const PointerProperties* pointerProperties = event->getPointerProperties(pointerIndex);
684     pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj);
685 }
686 
android_view_MotionEvent_nativeScale(JNIEnv * env,jclass clazz,jlong nativePtr,jfloat scale)687 static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz,
688         jlong nativePtr, jfloat scale) {
689     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
690     event->scale(scale);
691 }
692 
android_view_MotionEvent_nativeTransform(JNIEnv * env,jclass clazz,jlong nativePtr,jobject matrixObj)693 static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz,
694         jlong nativePtr, jobject matrixObj) {
695     SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
696     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
697 
698     float m[9];
699     m[0] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleX));
700     m[1] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewX));
701     m[2] = SkScalarToFloat(matrix->get(SkMatrix::kMTransX));
702     m[3] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewY));
703     m[4] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleY));
704     m[5] = SkScalarToFloat(matrix->get(SkMatrix::kMTransY));
705     m[6] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp0));
706     m[7] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp1));
707     m[8] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp2));
708     event->transform(m);
709 }
710 
android_view_MotionEvent_nativeReadFromParcel(JNIEnv * env,jclass clazz,jlong nativePtr,jobject parcelObj)711 static jlong android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
712         jlong nativePtr, jobject parcelObj) {
713     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
714     if (!event) {
715         event = new MotionEvent();
716     }
717 
718     Parcel* parcel = parcelForJavaObject(env, parcelObj);
719 
720     status_t status = event->readFromParcel(parcel);
721     if (status) {
722         if (!nativePtr) {
723             delete event;
724         }
725         jniThrowRuntimeException(env, "Failed to read MotionEvent parcel.");
726         return 0;
727     }
728     return reinterpret_cast<jlong>(event);
729 }
730 
android_view_MotionEvent_nativeWriteToParcel(JNIEnv * env,jclass clazz,jlong nativePtr,jobject parcelObj)731 static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass clazz,
732         jlong nativePtr, jobject parcelObj) {
733     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
734     Parcel* parcel = parcelForJavaObject(env, parcelObj);
735 
736     status_t status = event->writeToParcel(parcel);
737     if (status) {
738         jniThrowRuntimeException(env, "Failed to write MotionEvent parcel.");
739     }
740 }
741 
android_view_MotionEvent_nativeAxisToString(JNIEnv * env,jclass clazz,jint axis)742 static jstring android_view_MotionEvent_nativeAxisToString(JNIEnv* env, jclass clazz,
743         jint axis) {
744     return env->NewStringUTF(MotionEvent::getLabel(static_cast<int32_t>(axis)));
745 }
746 
android_view_MotionEvent_nativeAxisFromString(JNIEnv * env,jclass clazz,jstring label)747 static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass clazz,
748         jstring label) {
749     ScopedUtfChars axisLabel(env, label);
750     return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str()));
751 }
752 
753 // ----------------------------------------------------------------------------
754 
755 static JNINativeMethod gMotionEventMethods[] = {
756     /* name, signature, funcPtr */
757     { "nativeInitialize",
758             "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
759                     "[Landroid/view/MotionEvent$PointerCoords;)J",
760             (void*)android_view_MotionEvent_nativeInitialize },
761     { "nativeCopy",
762             "(JJZ)J",
763             (void*)android_view_MotionEvent_nativeCopy },
764     { "nativeDispose",
765             "(J)V",
766             (void*)android_view_MotionEvent_nativeDispose },
767     { "nativeAddBatch",
768             "(JJ[Landroid/view/MotionEvent$PointerCoords;I)V",
769             (void*)android_view_MotionEvent_nativeAddBatch },
770     { "nativeGetDeviceId",
771             "(J)I",
772             (void*)android_view_MotionEvent_nativeGetDeviceId },
773     { "nativeGetSource",
774             "(J)I",
775             (void*)android_view_MotionEvent_nativeGetSource },
776     { "nativeSetSource",
777             "(JI)I",
778             (void*)android_view_MotionEvent_nativeSetSource },
779     { "nativeGetAction",
780             "(J)I",
781             (void*)android_view_MotionEvent_nativeGetAction },
782     { "nativeSetAction",
783             "(JI)V",
784             (void*)android_view_MotionEvent_nativeSetAction },
785     { "nativeGetActionButton",
786             "(J)I",
787             (void*)android_view_MotionEvent_nativeGetActionButton},
788     { "nativeSetActionButton",
789             "(JI)V",
790             (void*)android_view_MotionEvent_nativeSetActionButton},
791     { "nativeIsTouchEvent",
792             "(J)Z",
793             (void*)android_view_MotionEvent_nativeIsTouchEvent },
794     { "nativeGetFlags",
795             "(J)I",
796             (void*)android_view_MotionEvent_nativeGetFlags },
797     { "nativeSetFlags",
798             "(JI)V",
799             (void*)android_view_MotionEvent_nativeSetFlags },
800     { "nativeGetEdgeFlags",
801             "(J)I",
802             (void*)android_view_MotionEvent_nativeGetEdgeFlags },
803     { "nativeSetEdgeFlags",
804             "(JI)V",
805             (void*)android_view_MotionEvent_nativeSetEdgeFlags },
806     { "nativeGetMetaState",
807             "(J)I",
808             (void*)android_view_MotionEvent_nativeGetMetaState },
809     { "nativeGetButtonState",
810             "(J)I",
811             (void*)android_view_MotionEvent_nativeGetButtonState },
812     { "nativeSetButtonState",
813             "(JI)V",
814             (void*)android_view_MotionEvent_nativeSetButtonState },
815     { "nativeOffsetLocation",
816             "(JFF)V",
817             (void*)android_view_MotionEvent_nativeOffsetLocation },
818     { "nativeGetXOffset",
819             "(J)F",
820             (void*)android_view_MotionEvent_nativeGetXOffset },
821     { "nativeGetYOffset",
822             "(J)F",
823             (void*)android_view_MotionEvent_nativeGetYOffset },
824     { "nativeGetXPrecision",
825             "(J)F",
826             (void*)android_view_MotionEvent_nativeGetXPrecision },
827     { "nativeGetYPrecision",
828             "(J)F",
829             (void*)android_view_MotionEvent_nativeGetYPrecision },
830     { "nativeGetDownTimeNanos",
831             "(J)J",
832             (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
833     { "nativeSetDownTimeNanos",
834             "(JJ)V",
835             (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
836     { "nativeGetPointerCount",
837             "(J)I",
838             (void*)android_view_MotionEvent_nativeGetPointerCount },
839     { "nativeGetPointerId",
840             "(JI)I",
841             (void*)android_view_MotionEvent_nativeGetPointerId },
842     { "nativeGetToolType",
843             "(JI)I",
844             (void*)android_view_MotionEvent_nativeGetToolType },
845     { "nativeFindPointerIndex",
846             "(JI)I",
847             (void*)android_view_MotionEvent_nativeFindPointerIndex },
848     { "nativeGetHistorySize",
849             "(J)I",
850             (void*)android_view_MotionEvent_nativeGetHistorySize },
851     { "nativeGetEventTimeNanos",
852             "(JI)J",
853             (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
854     { "nativeGetRawAxisValue",
855             "(JIII)F",
856             (void*)android_view_MotionEvent_nativeGetRawAxisValue },
857     { "nativeGetAxisValue",
858             "(JIII)F",
859             (void*)android_view_MotionEvent_nativeGetAxisValue },
860     { "nativeGetPointerCoords",
861             "(JIILandroid/view/MotionEvent$PointerCoords;)V",
862             (void*)android_view_MotionEvent_nativeGetPointerCoords },
863     { "nativeGetPointerProperties",
864             "(JILandroid/view/MotionEvent$PointerProperties;)V",
865             (void*)android_view_MotionEvent_nativeGetPointerProperties },
866     { "nativeScale",
867             "(JF)V",
868             (void*)android_view_MotionEvent_nativeScale },
869     { "nativeTransform",
870             "(JLandroid/graphics/Matrix;)V",
871             (void*)android_view_MotionEvent_nativeTransform },
872     { "nativeReadFromParcel",
873             "(JLandroid/os/Parcel;)J",
874             (void*)android_view_MotionEvent_nativeReadFromParcel },
875     { "nativeWriteToParcel",
876             "(JLandroid/os/Parcel;)V",
877             (void*)android_view_MotionEvent_nativeWriteToParcel },
878     { "nativeAxisToString", "(I)Ljava/lang/String;",
879             (void*)android_view_MotionEvent_nativeAxisToString },
880     { "nativeAxisFromString", "(Ljava/lang/String;)I",
881             (void*)android_view_MotionEvent_nativeAxisFromString },
882 };
883 
register_android_view_MotionEvent(JNIEnv * env)884 int register_android_view_MotionEvent(JNIEnv* env) {
885     int res = RegisterMethodsOrDie(env, "android/view/MotionEvent", gMotionEventMethods,
886                                    NELEM(gMotionEventMethods));
887 
888     gMotionEventClassInfo.clazz = FindClassOrDie(env, "android/view/MotionEvent");
889     gMotionEventClassInfo.clazz = MakeGlobalRefOrDie(env, gMotionEventClassInfo.clazz);
890 
891     gMotionEventClassInfo.obtain = GetStaticMethodIDOrDie(env, gMotionEventClassInfo.clazz,
892             "obtain", "()Landroid/view/MotionEvent;");
893     gMotionEventClassInfo.recycle = GetMethodIDOrDie(env, gMotionEventClassInfo.clazz,
894             "recycle", "()V");
895     gMotionEventClassInfo.mNativePtr = GetFieldIDOrDie(env, gMotionEventClassInfo.clazz,
896             "mNativePtr", "J");
897 
898     jclass clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerCoords");
899 
900     gPointerCoordsClassInfo.mPackedAxisBits = GetFieldIDOrDie(env, clazz, "mPackedAxisBits", "J");
901     gPointerCoordsClassInfo.mPackedAxisValues = GetFieldIDOrDie(env, clazz, "mPackedAxisValues",
902                                                                 "[F");
903     gPointerCoordsClassInfo.x = GetFieldIDOrDie(env, clazz, "x", "F");
904     gPointerCoordsClassInfo.y = GetFieldIDOrDie(env, clazz, "y", "F");
905     gPointerCoordsClassInfo.pressure = GetFieldIDOrDie(env, clazz, "pressure", "F");
906     gPointerCoordsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "F");
907     gPointerCoordsClassInfo.touchMajor = GetFieldIDOrDie(env, clazz, "touchMajor", "F");
908     gPointerCoordsClassInfo.touchMinor = GetFieldIDOrDie(env, clazz, "touchMinor", "F");
909     gPointerCoordsClassInfo.toolMajor = GetFieldIDOrDie(env, clazz, "toolMajor", "F");
910     gPointerCoordsClassInfo.toolMinor = GetFieldIDOrDie(env, clazz, "toolMinor", "F");
911     gPointerCoordsClassInfo.orientation = GetFieldIDOrDie(env, clazz, "orientation", "F");
912 
913     clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerProperties");
914 
915     gPointerPropertiesClassInfo.id = GetFieldIDOrDie(env, clazz, "id", "I");
916     gPointerPropertiesClassInfo.toolType = GetFieldIDOrDie(env, clazz, "toolType", "I");
917 
918     return res;
919 }
920 
921 } // namespace android
922