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