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