1 /*
2 * Copyright (C) 2011 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 "VelocityTracker-JNI"
18
19 #include "JNIHelp.h"
20
21 #include <android_runtime/AndroidRuntime.h>
22 #include <utils/Log.h>
23 #include <input/Input.h>
24 #include <input/VelocityTracker.h>
25 #include "android_view_MotionEvent.h"
26
27 #include <ScopedUtfChars.h>
28
29
30 namespace android {
31
32 // Special constant to request the velocity of the active pointer.
33 static const int ACTIVE_POINTER_ID = -1;
34
35 static struct {
36 jfieldID xCoeff;
37 jfieldID yCoeff;
38 jfieldID degree;
39 jfieldID confidence;
40 } gEstimatorClassInfo;
41
42
43 // --- VelocityTrackerState ---
44
45 class VelocityTrackerState {
46 public:
47 VelocityTrackerState(const char* strategy);
48
49 void clear();
50 void addMovement(const MotionEvent* event);
51 void computeCurrentVelocity(int32_t units, float maxVelocity);
52 void getVelocity(int32_t id, float* outVx, float* outVy);
53 bool getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator);
54
55 private:
56 struct Velocity {
57 float vx, vy;
58 };
59
60 VelocityTracker mVelocityTracker;
61 int32_t mActivePointerId;
62 BitSet32 mCalculatedIdBits;
63 Velocity mCalculatedVelocity[MAX_POINTERS];
64 };
65
VelocityTrackerState(const char * strategy)66 VelocityTrackerState::VelocityTrackerState(const char* strategy) :
67 mVelocityTracker(strategy), mActivePointerId(-1) {
68 }
69
clear()70 void VelocityTrackerState::clear() {
71 mVelocityTracker.clear();
72 mActivePointerId = -1;
73 mCalculatedIdBits.clear();
74 }
75
addMovement(const MotionEvent * event)76 void VelocityTrackerState::addMovement(const MotionEvent* event) {
77 mVelocityTracker.addMovement(event);
78 }
79
computeCurrentVelocity(int32_t units,float maxVelocity)80 void VelocityTrackerState::computeCurrentVelocity(int32_t units, float maxVelocity) {
81 BitSet32 idBits(mVelocityTracker.getCurrentPointerIdBits());
82 mCalculatedIdBits = idBits;
83
84 for (uint32_t index = 0; !idBits.isEmpty(); index++) {
85 uint32_t id = idBits.clearFirstMarkedBit();
86
87 float vx, vy;
88 mVelocityTracker.getVelocity(id, &vx, &vy);
89
90 vx = vx * units / 1000;
91 vy = vy * units / 1000;
92
93 if (vx > maxVelocity) {
94 vx = maxVelocity;
95 } else if (vx < -maxVelocity) {
96 vx = -maxVelocity;
97 }
98 if (vy > maxVelocity) {
99 vy = maxVelocity;
100 } else if (vy < -maxVelocity) {
101 vy = -maxVelocity;
102 }
103
104 Velocity& velocity = mCalculatedVelocity[index];
105 velocity.vx = vx;
106 velocity.vy = vy;
107 }
108 }
109
getVelocity(int32_t id,float * outVx,float * outVy)110 void VelocityTrackerState::getVelocity(int32_t id, float* outVx, float* outVy) {
111 if (id == ACTIVE_POINTER_ID) {
112 id = mVelocityTracker.getActivePointerId();
113 }
114
115 float vx, vy;
116 if (id >= 0 && id <= MAX_POINTER_ID && mCalculatedIdBits.hasBit(id)) {
117 uint32_t index = mCalculatedIdBits.getIndexOfBit(id);
118 const Velocity& velocity = mCalculatedVelocity[index];
119 vx = velocity.vx;
120 vy = velocity.vy;
121 } else {
122 vx = 0;
123 vy = 0;
124 }
125
126 if (outVx) {
127 *outVx = vx;
128 }
129 if (outVy) {
130 *outVy = vy;
131 }
132 }
133
getEstimator(int32_t id,VelocityTracker::Estimator * outEstimator)134 bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator) {
135 return mVelocityTracker.getEstimator(id, outEstimator);
136 }
137
138
139 // --- JNI Methods ---
140
android_view_VelocityTracker_nativeInitialize(JNIEnv * env,jclass clazz,jstring strategyStr)141 static jlong android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz,
142 jstring strategyStr) {
143 if (strategyStr) {
144 ScopedUtfChars strategy(env, strategyStr);
145 return reinterpret_cast<jlong>(new VelocityTrackerState(strategy.c_str()));
146 }
147 return reinterpret_cast<jlong>(new VelocityTrackerState(NULL));
148 }
149
android_view_VelocityTracker_nativeDispose(JNIEnv * env,jclass clazz,jlong ptr)150 static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jlong ptr) {
151 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
152 delete state;
153 }
154
android_view_VelocityTracker_nativeClear(JNIEnv * env,jclass clazz,jlong ptr)155 static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jlong ptr) {
156 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
157 state->clear();
158 }
159
android_view_VelocityTracker_nativeAddMovement(JNIEnv * env,jclass clazz,jlong ptr,jobject eventObj)160 static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jlong ptr,
161 jobject eventObj) {
162 const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj);
163 if (!event) {
164 ALOGW("nativeAddMovement failed because MotionEvent was finalized.");
165 return;
166 }
167
168 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
169 state->addMovement(event);
170 }
171
android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv * env,jclass clazz,jlong ptr,jint units,jfloat maxVelocity)172 static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz,
173 jlong ptr, jint units, jfloat maxVelocity) {
174 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
175 state->computeCurrentVelocity(units, maxVelocity);
176 }
177
android_view_VelocityTracker_nativeGetXVelocity(JNIEnv * env,jclass clazz,jlong ptr,jint id)178 static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz,
179 jlong ptr, jint id) {
180 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
181 float vx;
182 state->getVelocity(id, &vx, NULL);
183 return vx;
184 }
185
android_view_VelocityTracker_nativeGetYVelocity(JNIEnv * env,jclass clazz,jlong ptr,jint id)186 static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz,
187 jlong ptr, jint id) {
188 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
189 float vy;
190 state->getVelocity(id, NULL, &vy);
191 return vy;
192 }
193
android_view_VelocityTracker_nativeGetEstimator(JNIEnv * env,jclass clazz,jlong ptr,jint id,jobject outEstimatorObj)194 static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz,
195 jlong ptr, jint id, jobject outEstimatorObj) {
196 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
197 VelocityTracker::Estimator estimator;
198 bool result = state->getEstimator(id, &estimator);
199
200 jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
201 gEstimatorClassInfo.xCoeff));
202 jfloatArray yCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
203 gEstimatorClassInfo.yCoeff));
204
205 env->SetFloatArrayRegion(xCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
206 estimator.xCoeff);
207 env->SetFloatArrayRegion(yCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
208 estimator.yCoeff);
209 env->SetIntField(outEstimatorObj, gEstimatorClassInfo.degree, estimator.degree);
210 env->SetFloatField(outEstimatorObj, gEstimatorClassInfo.confidence, estimator.confidence);
211 return result;
212 }
213
214
215 // --- JNI Registration ---
216
217 static JNINativeMethod gVelocityTrackerMethods[] = {
218 /* name, signature, funcPtr */
219 { "nativeInitialize",
220 "(Ljava/lang/String;)J",
221 (void*)android_view_VelocityTracker_nativeInitialize },
222 { "nativeDispose",
223 "(J)V",
224 (void*)android_view_VelocityTracker_nativeDispose },
225 { "nativeClear",
226 "(J)V",
227 (void*)android_view_VelocityTracker_nativeClear },
228 { "nativeAddMovement",
229 "(JLandroid/view/MotionEvent;)V",
230 (void*)android_view_VelocityTracker_nativeAddMovement },
231 { "nativeComputeCurrentVelocity",
232 "(JIF)V",
233 (void*)android_view_VelocityTracker_nativeComputeCurrentVelocity },
234 { "nativeGetXVelocity",
235 "(JI)F",
236 (void*)android_view_VelocityTracker_nativeGetXVelocity },
237 { "nativeGetYVelocity",
238 "(JI)F",
239 (void*)android_view_VelocityTracker_nativeGetYVelocity },
240 { "nativeGetEstimator",
241 "(JILandroid/view/VelocityTracker$Estimator;)Z",
242 (void*)android_view_VelocityTracker_nativeGetEstimator },
243 };
244
245 #define FIND_CLASS(var, className) \
246 var = env->FindClass(className); \
247 LOG_FATAL_IF(! var, "Unable to find class " className);
248
249 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
250 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
251 LOG_FATAL_IF(! var, "Unable to find field " fieldName);
252
register_android_view_VelocityTracker(JNIEnv * env)253 int register_android_view_VelocityTracker(JNIEnv* env) {
254 int res = jniRegisterNativeMethods(env, "android/view/VelocityTracker",
255 gVelocityTrackerMethods, NELEM(gVelocityTrackerMethods));
256 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
257
258 jclass clazz;
259 FIND_CLASS(clazz, "android/view/VelocityTracker$Estimator");
260
261 GET_FIELD_ID(gEstimatorClassInfo.xCoeff, clazz,
262 "xCoeff", "[F");
263 GET_FIELD_ID(gEstimatorClassInfo.yCoeff, clazz,
264 "yCoeff", "[F");
265 GET_FIELD_ID(gEstimatorClassInfo.degree, clazz,
266 "degree", "I");
267 GET_FIELD_ID(gEstimatorClassInfo.confidence, clazz,
268 "confidence", "F");
269 return 0;
270 }
271
272 } // namespace android
273