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 <nativehelper/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 <nativehelper/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     explicit 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 const 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