OSDN Git Service

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