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