android_view_MotionEvent.cpp revision 337d9d2edc262141f9b8f684e53aae5e47f0ae13
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "MotionEvent-JNI"
18
19#include "JNIHelp.h"
20
21#include <SkMatrix.h>
22#include <android_runtime/AndroidRuntime.h>
23#include <android_runtime/Log.h>
24#include <utils/Log.h>
25#include <input/Input.h>
26#include <ScopedUtfChars.h>
27#include "android_os_Parcel.h"
28#include "android_view_MotionEvent.h"
29#include "android_util_Binder.h"
30#include "android/graphics/Matrix.h"
31
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->GetLongField(eventObj, gMotionEventClassInfo.mNativePtr));
72}
73
74static void android_view_MotionEvent_setNativePtr(JNIEnv* env, jobject eventObj,
75        MotionEvent* event) {
76    env->SetLongField(eventObj, gMotionEventClassInfo.mNativePtr,
77            reinterpret_cast<jlong>(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 jlong android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz,
339        jlong 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<jlong>(event);
382
383Error:
384    if (!nativePtr) {
385        delete event;
386    }
387    return 0;
388}
389
390static jlong android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz,
391        jlong destNativePtr, jlong 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<jlong>(destEvent);
399}
400
401static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
402        jlong nativePtr) {
403    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
404    delete event;
405}
406
407static void android_view_MotionEvent_nativeAddBatch(JNIEnv* env, jclass clazz,
408        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong 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        jlong nativePtr, jobject matrixObj) {
681    SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
682    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
683
684    float m[9];
685    m[0] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleX));
686    m[1] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewX));
687    m[2] = SkScalarToFloat(matrix->get(SkMatrix::kMTransX));
688    m[3] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewY));
689    m[4] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleY));
690    m[5] = SkScalarToFloat(matrix->get(SkMatrix::kMTransY));
691    m[6] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp0));
692    m[7] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp1));
693    m[8] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp2));
694    event->transform(m);
695}
696
697static jlong android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
698        jlong nativePtr, jobject parcelObj) {
699    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
700    if (!event) {
701        event = new MotionEvent();
702    }
703
704    Parcel* parcel = parcelForJavaObject(env, parcelObj);
705
706    status_t status = event->readFromParcel(parcel);
707    if (status) {
708        if (!nativePtr) {
709            delete event;
710        }
711        jniThrowRuntimeException(env, "Failed to read MotionEvent parcel.");
712        return 0;
713    }
714    return reinterpret_cast<jlong>(event);
715}
716
717static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass clazz,
718        jlong nativePtr, jobject parcelObj) {
719    MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
720    Parcel* parcel = parcelForJavaObject(env, parcelObj);
721
722    status_t status = event->writeToParcel(parcel);
723    if (status) {
724        jniThrowRuntimeException(env, "Failed to write MotionEvent parcel.");
725    }
726}
727
728static jstring android_view_MotionEvent_nativeAxisToString(JNIEnv* env, jclass clazz,
729        jint axis) {
730    return env->NewStringUTF(MotionEvent::getLabel(static_cast<int32_t>(axis)));
731}
732
733static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass clazz,
734        jstring label) {
735    ScopedUtfChars axisLabel(env, label);
736    return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str()));
737}
738
739// ----------------------------------------------------------------------------
740
741static JNINativeMethod gMotionEventMethods[] = {
742    /* name, signature, funcPtr */
743    { "nativeInitialize",
744            "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
745                    "[Landroid/view/MotionEvent$PointerCoords;)J",
746            (void*)android_view_MotionEvent_nativeInitialize },
747    { "nativeCopy",
748            "(JJZ)J",
749            (void*)android_view_MotionEvent_nativeCopy },
750    { "nativeDispose",
751            "(J)V",
752            (void*)android_view_MotionEvent_nativeDispose },
753    { "nativeAddBatch",
754            "(JJ[Landroid/view/MotionEvent$PointerCoords;I)V",
755            (void*)android_view_MotionEvent_nativeAddBatch },
756    { "nativeGetDeviceId",
757            "(J)I",
758            (void*)android_view_MotionEvent_nativeGetDeviceId },
759    { "nativeGetSource",
760            "(J)I",
761            (void*)android_view_MotionEvent_nativeGetSource },
762    { "nativeSetSource",
763            "(JI)I",
764            (void*)android_view_MotionEvent_nativeSetSource },
765    { "nativeGetAction",
766            "(J)I",
767            (void*)android_view_MotionEvent_nativeGetAction },
768    { "nativeSetAction",
769            "(JI)V",
770            (void*)android_view_MotionEvent_nativeSetAction },
771    { "nativeIsTouchEvent",
772            "(J)Z",
773            (void*)android_view_MotionEvent_nativeIsTouchEvent },
774    { "nativeGetFlags",
775            "(J)I",
776            (void*)android_view_MotionEvent_nativeGetFlags },
777    { "nativeSetFlags",
778            "(JI)V",
779            (void*)android_view_MotionEvent_nativeSetFlags },
780    { "nativeGetEdgeFlags",
781            "(J)I",
782            (void*)android_view_MotionEvent_nativeGetEdgeFlags },
783    { "nativeSetEdgeFlags",
784            "(JI)V",
785            (void*)android_view_MotionEvent_nativeSetEdgeFlags },
786    { "nativeGetMetaState",
787            "(J)I",
788            (void*)android_view_MotionEvent_nativeGetMetaState },
789    { "nativeGetButtonState",
790            "(J)I",
791            (void*)android_view_MotionEvent_nativeGetButtonState },
792    { "nativeOffsetLocation",
793            "(JFF)V",
794            (void*)android_view_MotionEvent_nativeOffsetLocation },
795    { "nativeGetXOffset",
796            "(J)F",
797            (void*)android_view_MotionEvent_nativeGetXOffset },
798    { "nativeGetYOffset",
799            "(J)F",
800            (void*)android_view_MotionEvent_nativeGetYOffset },
801    { "nativeGetXPrecision",
802            "(J)F",
803            (void*)android_view_MotionEvent_nativeGetXPrecision },
804    { "nativeGetYPrecision",
805            "(J)F",
806            (void*)android_view_MotionEvent_nativeGetYPrecision },
807    { "nativeGetDownTimeNanos",
808            "(J)J",
809            (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
810    { "nativeSetDownTimeNanos",
811            "(JJ)V",
812            (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
813    { "nativeGetPointerCount",
814            "(J)I",
815            (void*)android_view_MotionEvent_nativeGetPointerCount },
816    { "nativeGetPointerId",
817            "(JI)I",
818            (void*)android_view_MotionEvent_nativeGetPointerId },
819    { "nativeGetToolType",
820            "(JI)I",
821            (void*)android_view_MotionEvent_nativeGetToolType },
822    { "nativeFindPointerIndex",
823            "(JI)I",
824            (void*)android_view_MotionEvent_nativeFindPointerIndex },
825    { "nativeGetHistorySize",
826            "(J)I",
827            (void*)android_view_MotionEvent_nativeGetHistorySize },
828    { "nativeGetEventTimeNanos",
829            "(JI)J",
830            (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
831    { "nativeGetRawAxisValue",
832            "(JIII)F",
833            (void*)android_view_MotionEvent_nativeGetRawAxisValue },
834    { "nativeGetAxisValue",
835            "(JIII)F",
836            (void*)android_view_MotionEvent_nativeGetAxisValue },
837    { "nativeGetPointerCoords",
838            "(JIILandroid/view/MotionEvent$PointerCoords;)V",
839            (void*)android_view_MotionEvent_nativeGetPointerCoords },
840    { "nativeGetPointerProperties",
841            "(JILandroid/view/MotionEvent$PointerProperties;)V",
842            (void*)android_view_MotionEvent_nativeGetPointerProperties },
843    { "nativeScale",
844            "(JF)V",
845            (void*)android_view_MotionEvent_nativeScale },
846    { "nativeTransform",
847            "(JLandroid/graphics/Matrix;)V",
848            (void*)android_view_MotionEvent_nativeTransform },
849    { "nativeReadFromParcel",
850            "(JLandroid/os/Parcel;)J",
851            (void*)android_view_MotionEvent_nativeReadFromParcel },
852    { "nativeWriteToParcel",
853            "(JLandroid/os/Parcel;)V",
854            (void*)android_view_MotionEvent_nativeWriteToParcel },
855    { "nativeAxisToString", "(I)Ljava/lang/String;",
856            (void*)android_view_MotionEvent_nativeAxisToString },
857    { "nativeAxisFromString", "(Ljava/lang/String;)I",
858            (void*)android_view_MotionEvent_nativeAxisFromString },
859};
860
861#define FIND_CLASS(var, className) \
862        var = env->FindClass(className); \
863        LOG_FATAL_IF(! var, "Unable to find class " className);
864
865#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
866        var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
867        LOG_FATAL_IF(! var, "Unable to find static method" methodName);
868
869#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
870        var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
871        LOG_FATAL_IF(! var, "Unable to find method" methodName);
872
873#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
874        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
875        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
876
877int register_android_view_MotionEvent(JNIEnv* env) {
878    int res = jniRegisterNativeMethods(env, "android/view/MotionEvent",
879            gMotionEventMethods, NELEM(gMotionEventMethods));
880    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
881
882    FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
883    gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
884
885    GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz,
886            "obtain", "()Landroid/view/MotionEvent;");
887    GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
888            "recycle", "()V");
889    GET_FIELD_ID(gMotionEventClassInfo.mNativePtr, gMotionEventClassInfo.clazz,
890            "mNativePtr", "J");
891
892    jclass clazz;
893    FIND_CLASS(clazz, "android/view/MotionEvent$PointerCoords");
894
895    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, clazz,
896            "mPackedAxisBits", "J");
897    GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, clazz,
898            "mPackedAxisValues", "[F");
899    GET_FIELD_ID(gPointerCoordsClassInfo.x, clazz,
900            "x", "F");
901    GET_FIELD_ID(gPointerCoordsClassInfo.y, clazz,
902            "y", "F");
903    GET_FIELD_ID(gPointerCoordsClassInfo.pressure, clazz,
904            "pressure", "F");
905    GET_FIELD_ID(gPointerCoordsClassInfo.size, clazz,
906            "size", "F");
907    GET_FIELD_ID(gPointerCoordsClassInfo.touchMajor, clazz,
908            "touchMajor", "F");
909    GET_FIELD_ID(gPointerCoordsClassInfo.touchMinor, clazz,
910            "touchMinor", "F");
911    GET_FIELD_ID(gPointerCoordsClassInfo.toolMajor, clazz,
912            "toolMajor", "F");
913    GET_FIELD_ID(gPointerCoordsClassInfo.toolMinor, clazz,
914            "toolMinor", "F");
915    GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz,
916            "orientation", "F");
917
918    FIND_CLASS(clazz, "android/view/MotionEvent$PointerProperties");
919
920    GET_FIELD_ID(gPointerPropertiesClassInfo.id, clazz,
921            "id", "I");
922    GET_FIELD_ID(gPointerPropertiesClassInfo.toolType, clazz,
923            "toolType", "I");
924
925    return 0;
926}
927
928} // namespace android
929