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