android_view_VelocityTracker.cpp revision 96804bc8fb3d6b2de11e3b9779c976e7b0e96ee8
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
30namespace android {
31
32// Special constant to request the velocity of the active pointer.
33static const int ACTIVE_POINTER_ID = -1;
34
35static struct {
36    jfieldID xCoeff;
37    jfieldID yCoeff;
38    jfieldID degree;
39    jfieldID confidence;
40} gEstimatorClassInfo;
41
42
43// --- VelocityTrackerState ---
44
45class VelocityTrackerState {
46public:
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
55private:
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
66VelocityTrackerState::VelocityTrackerState(const char* strategy) :
67        mVelocityTracker(strategy), mActivePointerId(-1) {
68}
69
70void VelocityTrackerState::clear() {
71    mVelocityTracker.clear();
72    mActivePointerId = -1;
73    mCalculatedIdBits.clear();
74}
75
76void VelocityTrackerState::addMovement(const MotionEvent* event) {
77    mVelocityTracker.addMovement(event);
78}
79
80void 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
110void 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
134bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator) {
135    return mVelocityTracker.getEstimator(id, outEstimator);
136}
137
138
139// --- JNI Methods ---
140
141static 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
150static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jlong ptr) {
151    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
152    delete state;
153}
154
155static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jlong ptr) {
156    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
157    state->clear();
158}
159
160static 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
172static 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
178static 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
186static 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
194static 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
217static 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
253int 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