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