1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "MotionEvent-JNI"
18
19#include "JNIHelp.h"
20
21#include <android_runtime/AndroidRuntime.h>
22#include <utils/Log.h>
23#include <ui/Input.h>
24#include "android_view_MotionEvent.h"
25#include "android_util_Binder.h"
26#include "android/graphics/Matrix.h"
27
28#include "SkMatrix.h"
29
30
31namespace android {
32
33// ----------------------------------------------------------------------------
34
35static struct {
36    jclass clazz;
37
38    jmethodID obtain;
39    jmethodID recycle;
40
41    jfieldID mNativePtr;
42} gMotionEventClassInfo;
43
44static struct {
45    jfieldID mPackedAxisBits;
46    jfieldID mPackedAxisValues;
47    jfieldID x;
48    jfieldID y;
49    jfieldID pressure;
50    jfieldID size;
51    jfieldID touchMajor;
52    jfieldID touchMinor;
53    jfieldID toolMajor;
54    jfieldID toolMinor;
55    jfieldID orientation;
56} gPointerCoordsClassInfo;
57
58static struct {
59    jfieldID id;
60    jfieldID toolType;
61} gPointerPropertiesClassInfo;
62
63// ----------------------------------------------------------------------------
64
65MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) {
66    if (!eventObj) {
67        return NULL;
68    }
69    return reinterpret_cast<MotionEvent*>(
70            env->GetIntField(eventObj, gMotionEventClassInfo.mNativePtr));
71}
72
73static void android_view_MotionEvent_setNativePtr(JNIEnv* env, jobject eventObj,
74        MotionEvent* event) {
75    env->SetIntField(eventObj, gMotionEventClassInfo.mNativePtr,
76            reinterpret_cast<int>(event));
77}
78
79jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent* event) {
80    jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,
81            gMotionEventClassInfo.obtain);
82    if (env->ExceptionCheck() || !eventObj) {
83        LOGE("An exception occurred while obtaining a motion event.");
84        LOGE_EX(env);
85        env->ExceptionClear();
86        return NULL;
87    }
88
89    MotionEvent* destEvent = android_view_MotionEvent_getNativePtr(env, eventObj);
90    if (!destEvent) {
91        destEvent = new MotionEvent();
92        android_view_MotionEvent_setNativePtr(env, eventObj, destEvent);
93    }
94
95    destEvent->copyFrom(event, true);
96    return eventObj;
97}
98
99status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
100    env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle);
101    if (env->ExceptionCheck()) {
102        LOGW("An exception occurred while recycling a motion event.");
103        LOGW_EX(env);
104        env->ExceptionClear();
105        return UNKNOWN_ERROR;
106    }
107    return OK;
108}
109
110// ----------------------------------------------------------------------------
111
112static const jint HISTORY_CURRENT = -0x80000000;
113
114static bool validatePointerCount(JNIEnv* env, jint pointerCount) {
115    if (pointerCount < 1) {
116        jniThrowException(env, "java/lang/IllegalArgumentException",
117                "pointerCount must be at least 1");
118        return false;
119    }
120    return true;
121}
122
123static bool validatePointerPropertiesArray(JNIEnv* env, jobjectArray pointerPropertiesObjArray,
124        size_t pointerCount) {
125    if (!pointerPropertiesObjArray) {
126        jniThrowException(env, "java/lang/IllegalArgumentException",
127                "pointerProperties array must not be null");
128        return false;
129    }
130    size_t length = size_t(env->GetArrayLength(pointerPropertiesObjArray));
131    if (length < pointerCount) {
132        jniThrowException(env, "java/lang/IllegalArgumentException",
133                "pointerProperties array must be large enough to hold all pointers");
134        return false;
135    }
136    return true;
137}
138
139static bool validatePointerCoordsObjArray(JNIEnv* env, jobjectArray pointerCoordsObjArray,
140        size_t pointerCount) {
141    if (!pointerCoordsObjArray) {
142        jniThrowException(env, "java/lang/IllegalArgumentException",
143                "pointerCoords array must not be null");
144        return false;
145    }
146    size_t length = size_t(env->GetArrayLength(pointerCoordsObjArray));
147    if (length < pointerCount) {
148        jniThrowException(env, "java/lang/IllegalArgumentException",
149                "pointerCoords array must be large enough to hold all pointers");
150        return false;
151    }
152    return true;
153}
154
155static bool validatePointerIndex(JNIEnv* env, jint pointerIndex, size_t pointerCount) {
156    if (pointerIndex < 0 || size_t(pointerIndex) >= pointerCount) {
157        jniThrowException(env, "java/lang/IllegalArgumentException",
158                "pointerIndex out of range");
159        return false;
160    }
161    return true;
162}
163
164static bool validateHistoryPos(JNIEnv* env, jint historyPos, size_t historySize) {
165    if (historyPos < 0 || size_t(historyPos) >= historySize) {
166        jniThrowException(env, "java/lang/IllegalArgumentException",
167                "historyPos out of range");
168        return false;
169    }
170    return true;
171}
172
173static bool validatePointerCoords(JNIEnv* env, jobject pointerCoordsObj) {
174    if (!pointerCoordsObj) {
175        jniThrowException(env, "java/lang/IllegalArgumentException",
176                "pointerCoords must not be null");
177        return false;
178    }
179    return true;
180}
181
182static bool validatePointerProperties(JNIEnv* env, jobject pointerPropertiesObj) {
183    if (!pointerPropertiesObj) {
184        jniThrowException(env, "java/lang/IllegalArgumentException",
185                "pointerProperties must not be null");
186        return false;
187    }
188    return true;
189}
190
191static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj,
192        float xOffset, float yOffset, PointerCoords* outRawPointerCoords) {
193    outRawPointerCoords->clear();
194    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_X,
195            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.x) - xOffset);
196    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_Y,
197            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.y) - yOffset);
198    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
199            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.pressure));
200    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_SIZE,
201            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.size));
202    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
203            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMajor));
204    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR,
205            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMinor));
206    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR,
207            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMajor));
208    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR,
209            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor));
210    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
211            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));
212
213    uint64_t bits = env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits);
214    if (bits) {
215        jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj,
216                gPointerCoordsClassInfo.mPackedAxisValues));
217        if (valuesArray) {
218            jfloat* values = static_cast<jfloat*>(
219                    env->GetPrimitiveArrayCritical(valuesArray, NULL));
220
221            uint32_t index = 0;
222            do {
223                uint32_t axis = __builtin_ctzll(bits);
224                uint64_t axisBit = 1LL << axis;
225                bits &= ~axisBit;
226                outRawPointerCoords->setAxisValue(axis, values[index++]);
227            } while (bits);
228
229            env->ReleasePrimitiveArrayCritical(valuesArray, values, JNI_ABORT);
230            env->DeleteLocalRef(valuesArray);
231        }
232    }
233}
234
235static jfloatArray obtainPackedAxisValuesArray(JNIEnv* env, uint32_t minSize,
236        jobject outPointerCoordsObj) {
237    jfloatArray outValuesArray = jfloatArray(env->GetObjectField(outPointerCoordsObj,
238            gPointerCoordsClassInfo.mPackedAxisValues));
239    if (outValuesArray) {
240        uint32_t size = env->GetArrayLength(outValuesArray);
241        if (minSize <= size) {
242            return outValuesArray;
243        }
244        env->DeleteLocalRef(outValuesArray);
245    }
246    uint32_t size = 8;
247    while (size < minSize) {
248        size *= 2;
249    }
250    outValuesArray = env->NewFloatArray(size);
251    env->SetObjectField(outPointerCoordsObj,
252            gPointerCoordsClassInfo.mPackedAxisValues, outValuesArray);
253    return outValuesArray;
254}
255
256static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointerCoords,
257        float xOffset, float yOffset, jobject outPointerCoordsObj) {
258    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.x,
259            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset);
260    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.y,
261            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset);
262    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.pressure,
263            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
264    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.size,
265            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_SIZE));
266    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.touchMajor,
267            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR));
268    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.touchMinor,
269            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR));
270    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.toolMajor,
271            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR));
272    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.toolMinor,
273            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR));
274    env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.orientation,
275            rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
276
277    const uint64_t unpackedAxisBits = 0
278            | (1LL << AMOTION_EVENT_AXIS_X)
279            | (1LL << AMOTION_EVENT_AXIS_Y)
280            | (1LL << AMOTION_EVENT_AXIS_PRESSURE)
281            | (1LL << AMOTION_EVENT_AXIS_SIZE)
282            | (1LL << AMOTION_EVENT_AXIS_TOUCH_MAJOR)
283            | (1LL << AMOTION_EVENT_AXIS_TOUCH_MINOR)
284            | (1LL << AMOTION_EVENT_AXIS_TOOL_MAJOR)
285            | (1LL << AMOTION_EVENT_AXIS_TOOL_MINOR)
286            | (1LL << AMOTION_EVENT_AXIS_ORIENTATION);
287
288    uint64_t outBits = 0;
289    uint64_t remainingBits = rawPointerCoords->bits & ~unpackedAxisBits;
290    if (remainingBits) {
291        uint32_t packedAxesCount = __builtin_popcountll(remainingBits);
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        const float* values = rawPointerCoords->values;
302        uint32_t index = 0;
303        do {
304            uint32_t axis = __builtin_ctzll(remainingBits);
305            uint64_t axisBit = 1LL << axis;
306            remainingBits &= ~axisBit;
307            outBits |= axisBit;
308            outValues[index++] = rawPointerCoords->getAxisValue(axis);
309        } while (remainingBits);
310
311        env->ReleasePrimitiveArrayCritical(outValuesArray, outValues, 0);
312        env->DeleteLocalRef(outValuesArray);
313    }
314    env->SetLongField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits);
315}
316
317static void pointerPropertiesToNative(JNIEnv* env, jobject pointerPropertiesObj,
318        PointerProperties* outPointerProperties) {
319    outPointerProperties->clear();
320    outPointerProperties->id = env->GetIntField(pointerPropertiesObj,
321            gPointerPropertiesClassInfo.id);
322    outPointerProperties->toolType = env->GetIntField(pointerPropertiesObj,
323            gPointerPropertiesClassInfo.toolType);
324}
325
326static void pointerPropertiesFromNative(JNIEnv* env, const PointerProperties* pointerProperties,
327        jobject outPointerPropertiesObj) {
328    env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.id,
329            pointerProperties->id);
330    env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.toolType,
331            pointerProperties->toolType);
332}
333
334
335// ----------------------------------------------------------------------------
336
337static jint android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz,
338        jint nativePtr,
339        jint deviceId, jint source, jint action, jint flags, jint edgeFlags,
340        jint metaState, jint buttonState,
341        jfloat xOffset, jfloat yOffset, jfloat xPrecision, jfloat yPrecision,
342        jlong downTimeNanos, jlong eventTimeNanos,
343        jint pointerCount, jobjectArray pointerPropertiesObjArray,
344        jobjectArray pointerCoordsObjArray) {
345    if (!validatePointerCount(env, pointerCount)
346            || !validatePointerPropertiesArray(env, pointerPropertiesObjArray, pointerCount)
347            || !validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) {
348        return 0;
349    }
350
351    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
352    if (!event) {
353        event = new MotionEvent();
354    }
355
356    PointerProperties pointerProperties[pointerCount];
357    PointerCoords rawPointerCoords[pointerCount];
358
359    for (jint i = 0; i < pointerCount; i++) {
360        jobject pointerPropertiesObj = env->GetObjectArrayElement(pointerPropertiesObjArray, i);
361        if (!pointerPropertiesObj) {
362            goto Error;
363        }
364        pointerPropertiesToNative(env, pointerPropertiesObj, &pointerProperties[i]);
365        env->DeleteLocalRef(pointerPropertiesObj);
366
367        jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
368        if (!pointerCoordsObj) {
369            jniThrowNullPointerException(env, "pointerCoords");
370            goto Error;
371        }
372        pointerCoordsToNative(env, pointerCoordsObj, xOffset, yOffset, &rawPointerCoords[i]);
373        env->DeleteLocalRef(pointerCoordsObj);
374    }
375
376    event->initialize(deviceId, source, action, flags, edgeFlags, metaState, buttonState,
377            xOffset, yOffset, xPrecision, yPrecision,
378            downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords);
379
380    return reinterpret_cast<jint>(event);
381
382Error:
383    if (!nativePtr) {
384        delete event;
385    }
386    return 0;
387}
388
389static jint android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz,
390        jint destNativePtr, jint sourceNativePtr, jboolean keepHistory) {
391    MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
392    if (!destEvent) {
393        destEvent = new MotionEvent();
394    }
395    MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
396    destEvent->copyFrom(sourceEvent, keepHistory);
397    return reinterpret_cast<jint>(destEvent);
398}
399
400static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
401        jint nativePtr) {
402    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
403    delete event;
404}
405
406static void android_view_MotionEvent_nativeAddBatch(JNIEnv* env, jclass clazz,
407        jint nativePtr, jlong eventTimeNanos, jobjectArray pointerCoordsObjArray,
408        jint metaState) {
409    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
410    size_t pointerCount = event->getPointerCount();
411    if (!validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) {
412        return;
413    }
414
415    PointerCoords rawPointerCoords[pointerCount];
416
417    for (size_t i = 0; i < pointerCount; i++) {
418        jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
419        if (!pointerCoordsObj) {
420            jniThrowNullPointerException(env, "pointerCoords");
421            return;
422        }
423        pointerCoordsToNative(env, pointerCoordsObj,
424                event->getXOffset(), event->getYOffset(), &rawPointerCoords[i]);
425        env->DeleteLocalRef(pointerCoordsObj);
426    }
427
428    event->addSample(eventTimeNanos, rawPointerCoords);
429    event->setMetaState(event->getMetaState() | metaState);
430}
431
432static jint android_view_MotionEvent_nativeGetDeviceId(JNIEnv* env, jclass clazz,
433        jint nativePtr) {
434    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
435    return event->getDeviceId();
436}
437
438static jint android_view_MotionEvent_nativeGetSource(JNIEnv* env, jclass clazz,
439        jint nativePtr) {
440    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
441    return event->getSource();
442}
443
444static void android_view_MotionEvent_nativeSetSource(JNIEnv* env, jclass clazz,
445        jint nativePtr, jint source) {
446    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
447    event->setSource(source);
448}
449
450static jint android_view_MotionEvent_nativeGetAction(JNIEnv* env, jclass clazz,
451        jint nativePtr) {
452    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
453    return event->getAction();
454}
455
456static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz,
457        jint nativePtr, jint action) {
458    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
459    event->setAction(action);
460}
461
462static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz,
463        jint nativePtr) {
464    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
465    return event->isTouchEvent();
466}
467
468static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz,
469        jint nativePtr) {
470    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
471    return event->getFlags();
472}
473
474static void android_view_MotionEvent_nativeSetFlags(JNIEnv* env, jclass clazz,
475        jint nativePtr, jint flags) {
476    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
477    event->setFlags(flags);
478}
479
480static jint android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv* env, jclass clazz,
481        jint nativePtr) {
482    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
483    return event->getEdgeFlags();
484}
485
486static void android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv* env, jclass clazz,
487        jint nativePtr, jint edgeFlags) {
488    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
489    event->setEdgeFlags(edgeFlags);
490}
491
492static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass clazz,
493        jint nativePtr) {
494    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
495    return event->getMetaState();
496}
497
498static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz,
499        jint nativePtr) {
500    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
501    return event->getButtonState();
502}
503
504static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz,
505        jint nativePtr, jfloat deltaX, jfloat deltaY) {
506    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
507    return event->offsetLocation(deltaX, deltaY);
508}
509
510static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz,
511        jint nativePtr) {
512    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
513    return event->getXOffset();
514}
515
516static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz,
517        jint nativePtr) {
518    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
519    return event->getYOffset();
520}
521
522static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz,
523        jint nativePtr) {
524    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
525    return event->getXPrecision();
526}
527
528static jfloat android_view_MotionEvent_nativeGetYPrecision(JNIEnv* env, jclass clazz,
529        jint nativePtr) {
530    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
531    return event->getYPrecision();
532}
533
534static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass clazz,
535        jint nativePtr) {
536    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
537    return event->getDownTime();
538}
539
540static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz,
541        jint nativePtr, jlong downTimeNanos) {
542    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
543    event->setDownTime(downTimeNanos);
544}
545
546static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz,
547        jint nativePtr) {
548    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
549    return jint(event->getPointerCount());
550}
551
552static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
553        jint nativePtr, jint pointerIndex) {
554    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
555    size_t pointerCount = event->getPointerCount();
556    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
557        return -1;
558    }
559    return event->getPointerId(pointerIndex);
560}
561
562static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
563        jint nativePtr, jint pointerIndex) {
564    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
565    size_t pointerCount = event->getPointerCount();
566    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
567        return -1;
568    }
569    return event->getToolType(pointerIndex);
570}
571
572static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz,
573        jint nativePtr, jint pointerId) {
574    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
575    return jint(event->findPointerIndex(pointerId));
576}
577
578static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz,
579        jint nativePtr) {
580    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
581    return jint(event->getHistorySize());
582}
583
584static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
585        jint nativePtr, jint historyPos) {
586    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
587    if (historyPos == HISTORY_CURRENT) {
588        return event->getEventTime();
589    } else {
590        size_t historySize = event->getHistorySize();
591        if (!validateHistoryPos(env, historyPos, historySize)) {
592            return 0;
593        }
594        return event->getHistoricalEventTime(historyPos);
595    }
596}
597
598static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
599        jint nativePtr, jint axis, jint pointerIndex, jint historyPos) {
600    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
601    size_t pointerCount = event->getPointerCount();
602    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
603        return 0;
604    }
605
606    if (historyPos == HISTORY_CURRENT) {
607        return event->getRawAxisValue(axis, pointerIndex);
608    } else {
609        size_t historySize = event->getHistorySize();
610        if (!validateHistoryPos(env, historyPos, historySize)) {
611            return 0;
612        }
613        return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
614    }
615}
616
617static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
618        jint nativePtr, jint axis, jint pointerIndex, jint historyPos) {
619    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
620    size_t pointerCount = event->getPointerCount();
621    if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
622        return 0;
623    }
624
625    if (historyPos == HISTORY_CURRENT) {
626        return event->getAxisValue(axis, pointerIndex);
627    } else {
628        size_t historySize = event->getHistorySize();
629        if (!validateHistoryPos(env, historyPos, historySize)) {
630            return 0;
631        }
632        return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
633    }
634}
635
636static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz,
637        jint nativePtr, jint pointerIndex, jint historyPos, jobject outPointerCoordsObj) {
638    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
639    size_t pointerCount = event->getPointerCount();
640    if (!validatePointerIndex(env, pointerIndex, pointerCount)
641            || !validatePointerCoords(env, outPointerCoordsObj)) {
642        return;
643    }
644
645    const PointerCoords* rawPointerCoords;
646    if (historyPos == HISTORY_CURRENT) {
647        rawPointerCoords = event->getRawPointerCoords(pointerIndex);
648    } else {
649        size_t historySize = event->getHistorySize();
650        if (!validateHistoryPos(env, historyPos, historySize)) {
651            return;
652        }
653        rawPointerCoords = event->getHistoricalRawPointerCoords(pointerIndex, historyPos);
654    }
655    pointerCoordsFromNative(env, rawPointerCoords, event->getXOffset(), event->getYOffset(),
656            outPointerCoordsObj);
657}
658
659static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz,
660        jint nativePtr, jint pointerIndex, jobject outPointerPropertiesObj) {
661    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
662    size_t pointerCount = event->getPointerCount();
663    if (!validatePointerIndex(env, pointerIndex, pointerCount)
664            || !validatePointerProperties(env, outPointerPropertiesObj)) {
665        return;
666    }
667
668    const PointerProperties* pointerProperties = event->getPointerProperties(pointerIndex);
669    pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj);
670}
671
672static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz,
673        jint nativePtr, jfloat scale) {
674    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
675    event->scale(scale);
676}
677
678static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz,
679        jint nativePtr, jobject matrixObj) {
680    SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
681    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
682    event->transform(matrix);
683}
684
685static jint android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
686        jint nativePtr, jobject parcelObj) {
687    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
688    if (!event) {
689        event = new MotionEvent();
690    }
691
692    Parcel* parcel = parcelForJavaObject(env, parcelObj);
693
694    status_t status = event->readFromParcel(parcel);
695    if (status) {
696        if (!nativePtr) {
697            delete event;
698        }
699        jniThrowRuntimeException(env, "Failed to read MotionEvent parcel.");
700        return 0;
701    }
702    return reinterpret_cast<jint>(event);
703}
704
705static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass clazz,
706        jint nativePtr, jobject parcelObj) {
707    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
708    Parcel* parcel = parcelForJavaObject(env, parcelObj);
709
710    status_t status = event->writeToParcel(parcel);
711    if (status) {
712        jniThrowRuntimeException(env, "Failed to write MotionEvent parcel.");
713    }
714}
715
716// ----------------------------------------------------------------------------
717
718static JNINativeMethod gMotionEventMethods[] = {
719    /* name, signature, funcPtr */
720    { "nativeInitialize",
721            "(IIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
722                    "[Landroid/view/MotionEvent$PointerCoords;)I",
723            (void*)android_view_MotionEvent_nativeInitialize },
724    { "nativeCopy",
725            "(IIZ)I",
726            (void*)android_view_MotionEvent_nativeCopy },
727    { "nativeDispose",
728            "(I)V",
729            (void*)android_view_MotionEvent_nativeDispose },
730    { "nativeAddBatch",
731            "(IJ[Landroid/view/MotionEvent$PointerCoords;I)V",
732            (void*)android_view_MotionEvent_nativeAddBatch },
733    { "nativeGetDeviceId",
734            "(I)I",
735            (void*)android_view_MotionEvent_nativeGetDeviceId },
736    { "nativeGetSource",
737            "(I)I",
738            (void*)android_view_MotionEvent_nativeGetSource },
739    { "nativeSetSource",
740            "(II)I",
741            (void*)android_view_MotionEvent_nativeSetSource },
742    { "nativeGetAction",
743            "(I)I",
744            (void*)android_view_MotionEvent_nativeGetAction },
745    { "nativeSetAction",
746            "(II)V",
747            (void*)android_view_MotionEvent_nativeSetAction },
748    { "nativeIsTouchEvent",
749            "(I)Z",
750            (void*)android_view_MotionEvent_nativeIsTouchEvent },
751    { "nativeGetFlags",
752            "(I)I",
753            (void*)android_view_MotionEvent_nativeGetFlags },
754    { "nativeSetFlags",
755            "(II)V",
756            (void*)android_view_MotionEvent_nativeSetFlags },
757    { "nativeGetEdgeFlags",
758            "(I)I",
759            (void*)android_view_MotionEvent_nativeGetEdgeFlags },
760    { "nativeSetEdgeFlags",
761            "(II)V",
762            (void*)android_view_MotionEvent_nativeSetEdgeFlags },
763    { "nativeGetMetaState",
764            "(I)I",
765            (void*)android_view_MotionEvent_nativeGetMetaState },
766    { "nativeGetButtonState",
767            "(I)I",
768            (void*)android_view_MotionEvent_nativeGetButtonState },
769    { "nativeOffsetLocation",
770            "(IFF)V",
771            (void*)android_view_MotionEvent_nativeOffsetLocation },
772    { "nativeGetXOffset",
773            "(I)F",
774            (void*)android_view_MotionEvent_nativeGetXOffset },
775    { "nativeGetYOffset",
776            "(I)F",
777            (void*)android_view_MotionEvent_nativeGetYOffset },
778    { "nativeGetXPrecision",
779            "(I)F",
780            (void*)android_view_MotionEvent_nativeGetXPrecision },
781    { "nativeGetYPrecision",
782            "(I)F",
783            (void*)android_view_MotionEvent_nativeGetYPrecision },
784    { "nativeGetDownTimeNanos",
785            "(I)J",
786            (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
787    { "nativeSetDownTimeNanos",
788            "(IJ)V",
789            (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
790    { "nativeGetPointerCount",
791            "(I)I",
792            (void*)android_view_MotionEvent_nativeGetPointerCount },
793    { "nativeGetPointerId",
794            "(II)I",
795            (void*)android_view_MotionEvent_nativeGetPointerId },
796    { "nativeGetToolType",
797            "(II)I",
798            (void*)android_view_MotionEvent_nativeGetToolType },
799    { "nativeFindPointerIndex",
800            "(II)I",
801            (void*)android_view_MotionEvent_nativeFindPointerIndex },
802    { "nativeGetHistorySize",
803            "(I)I",
804            (void*)android_view_MotionEvent_nativeGetHistorySize },
805    { "nativeGetEventTimeNanos",
806            "(II)J",
807            (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
808    { "nativeGetRawAxisValue",
809            "(IIII)F",
810            (void*)android_view_MotionEvent_nativeGetRawAxisValue },
811    { "nativeGetAxisValue",
812            "(IIII)F",
813            (void*)android_view_MotionEvent_nativeGetAxisValue },
814    { "nativeGetPointerCoords",
815            "(IIILandroid/view/MotionEvent$PointerCoords;)V",
816            (void*)android_view_MotionEvent_nativeGetPointerCoords },
817    { "nativeGetPointerProperties",
818            "(IILandroid/view/MotionEvent$PointerProperties;)V",
819            (void*)android_view_MotionEvent_nativeGetPointerProperties },
820    { "nativeScale",
821            "(IF)V",
822            (void*)android_view_MotionEvent_nativeScale },
823    { "nativeTransform",
824            "(ILandroid/graphics/Matrix;)V",
825            (void*)android_view_MotionEvent_nativeTransform },
826    { "nativeReadFromParcel",
827            "(ILandroid/os/Parcel;)I",
828            (void*)android_view_MotionEvent_nativeReadFromParcel },
829    { "nativeWriteToParcel",
830            "(ILandroid/os/Parcel;)V",
831            (void*)android_view_MotionEvent_nativeWriteToParcel },
832};
833
834#define FIND_CLASS(var, className) \
835        var = env->FindClass(className); \
836        LOG_FATAL_IF(! var, "Unable to find class " className);
837
838#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
839        var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
840        LOG_FATAL_IF(! var, "Unable to find static method" methodName);
841
842#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
843        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
844        LOG_FATAL_IF(! var, "Unable to find method" methodName);
845
846#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
847        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
848        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
849
850int register_android_view_MotionEvent(JNIEnv* env) {
851    int res = jniRegisterNativeMethods(env, "android/view/MotionEvent",
852            gMotionEventMethods, NELEM(gMotionEventMethods));
853    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
854
855    FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
856    gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
857
858    GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz,
859            "obtain", "()Landroid/view/MotionEvent;");
860    GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
861            "recycle", "()V");
862    GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz,
863            "mNativePtr", "I");
864
865    jclass clazz;
866    FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords");
867
868    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz,
869            "mPackedAxisBits", "J");
870    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz,
871            "mPackedAxisValues", "[F");
872    GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz,
873            "x", "F");
874    GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz,
875            "y", "F");
876    GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz,
877            "pressure", "F");
878    GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz,
879            "size", "F");
880    GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz,
881            "touchMajor", "F");
882    GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz,
883            "touchMinor", "F");
884    GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz,
885            "toolMajor", "F");
886    GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz,
887            "toolMinor", "F");
888    GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz,
889            "orientation", "F");
890
891    FIND_CLASS(clazz, "android/view/MotionEvent$PointerProperties");
892
893    GET_FIELD_ID(gPointerPropertiesClassInfo.id, clazz,
894            "id", "I");
895    GET_FIELD_ID(gPointerPropertiesClassInfo.toolType, clazz,
896            "toolType", "I");
897
898    return 0;
899}
900
901} // namespace android
902