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