OSDN Git Service

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