diff options
author | Jeff Brown <jeffbrown@google.com> | 2010-08-23 12:01:02 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2010-09-30 11:52:48 -0700 |
commit | 20e987bfc35d0ae6cb6344ead65ed44ee7cf8750 (patch) | |
tree | 7ae616a2c7a21a09950760babb0b980c40e4651a /core/jni/android_view_MotionEvent.cpp | |
parent | 4f4870f0bb7009e6d974b5d2c371924214684735 (diff) | |
download | frameworks_base-20e987bfc35d0ae6cb6344ead65ed44ee7cf8750.zip frameworks_base-20e987bfc35d0ae6cb6344ead65ed44ee7cf8750.tar.gz frameworks_base-20e987bfc35d0ae6cb6344ead65ed44ee7cf8750.tar.bz2 |
Add MotionEvent Matrix transformations.
Fixed issued in ViewGroup's transformation of MotionEvents to ensure
that the entire historical trace is transformed, not just the current
pointer.
Simplified the code in ViewGroup for splitting events across Views.
The new code also handles the case where some pointers are dispatched
to the ViewGroup in addition to its children whereas the previous
code would drop some pointers on the floor.
Change-Id: I56ac31903e1de8a9c376d9c935b7217b0c42d93e
Diffstat (limited to 'core/jni/android_view_MotionEvent.cpp')
-rw-r--r-- | core/jni/android_view_MotionEvent.cpp | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 93fd54f..537ac72 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -22,10 +22,26 @@ #include <utils/Log.h> #include <ui/Input.h> #include "android_view_MotionEvent.h" +#include "android/graphics/Matrix.h" + +#include <math.h> +#include "SkMatrix.h" +#include "SkScalar.h" // Number of float items per entry in a DVM sample data array #define NUM_SAMPLE_DATA 9 +#define SAMPLE_X 0 +#define SAMPLE_Y 1 +#define SAMPLE_PRESSURE 2 +#define SAMPLE_SIZE 3 +#define SAMPLE_TOUCH_MAJOR 4 +#define SAMPLE_TOUCH_MINOR 5 +#define SAMPLE_TOOL_MAJOR 6 +#define SAMPLE_TOOL_MINOR 7 +#define SAMPLE_ORIENTATION 8 + + namespace android { // ---------------------------------------------------------------------------- @@ -238,8 +254,87 @@ void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) { } } +static inline float transformAngle(const SkMatrix* matrix, float angleRadians) { + // Construct and transform a vector oriented at the specified clockwise angle from vertical. + // Coordinate system: down is increasing Y, right is increasing X. + SkPoint vector; + vector.fX = SkFloatToScalar(sinf(angleRadians)); + vector.fY = SkFloatToScalar(- cosf(angleRadians)); + matrix->mapVectors(& vector, 1); + + // Derive the transformed vector's clockwise angle from vertical. + float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(- vector.fY)); + if (result < - M_PI_2) { + result += M_PI; + } else if (result > M_PI_2) { + result -= M_PI; + } + return result; +} + +static void android_view_MotionEvent_nativeTransform(JNIEnv* env, + jobject eventObj, jobject matrixObj) { + SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj); + + jfloat oldXOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mXOffset); + jfloat oldYOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mYOffset); + jint numPointers = env->GetIntField(eventObj, gMotionEventClassInfo.mNumPointers); + jint numSamples = env->GetIntField(eventObj, gMotionEventClassInfo.mNumSamples); + jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj, + gMotionEventClassInfo.mDataSamples)); + jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL); + + // The tricky part of this implementation is to preserve the value of + // rawX and rawY. So we apply the transformation to the first point + // then derive an appropriate new X/Y offset that will preserve rawX and rawY. + SkPoint point; + jfloat rawX = dataSamples[SAMPLE_X]; + jfloat rawY = dataSamples[SAMPLE_Y]; + matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset), + & point); + jfloat newX = SkScalarToFloat(point.fX); + jfloat newY = SkScalarToFloat(point.fY); + jfloat newXOffset = newX - rawX; + jfloat newYOffset = newY - rawY; + + dataSamples[SAMPLE_ORIENTATION] = transformAngle(matrix, dataSamples[SAMPLE_ORIENTATION]); + + // Apply the transformation to all samples. + jfloat* currentDataSample = dataSamples; + jfloat* endDataSample = dataSamples + numPointers * numSamples * NUM_SAMPLE_DATA; + for (;;) { + currentDataSample += NUM_SAMPLE_DATA; + if (currentDataSample == endDataSample) { + break; + } + + jfloat x = currentDataSample[SAMPLE_X] + oldXOffset; + jfloat y = currentDataSample[SAMPLE_Y] + oldYOffset; + matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), & point); + currentDataSample[SAMPLE_X] = SkScalarToFloat(point.fX) - newXOffset; + currentDataSample[SAMPLE_Y] = SkScalarToFloat(point.fY) - newYOffset; + + currentDataSample[SAMPLE_ORIENTATION] = transformAngle(matrix, + currentDataSample[SAMPLE_ORIENTATION]); + } + + env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, 0); + + env->SetFloatField(eventObj, gMotionEventClassInfo.mXOffset, newXOffset); + env->SetFloatField(eventObj, gMotionEventClassInfo.mYOffset, newYOffset); + + env->DeleteLocalRef(dataSampleArray); +} + // ---------------------------------------------------------------------------- +static JNINativeMethod gMotionEventMethods[] = { + /* name, signature, funcPtr */ + { "nativeTransform", + "(Landroid/graphics/Matrix;)V", + (void*)android_view_MotionEvent_nativeTransform }, +}; + #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ LOG_FATAL_IF(! var, "Unable to find class " className); \ @@ -258,6 +353,10 @@ void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) { LOG_FATAL_IF(! var, "Unable to find field " fieldName); int register_android_view_MotionEvent(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "android/view/MotionEvent", + gMotionEventMethods, NELEM(gMotionEventMethods)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent"); GET_STATIC_METHOD_ID(gMotionEventClassInfo.obtain, gMotionEventClassInfo.clazz, |