android_view_VelocityTracker.cpp revision 85bd0d62830a098c1bdc720dfdcf4fe1b18b657c
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 <androidfw/Input.h>
24#include <androidfw/VelocityTracker.h>
25#include "android_view_MotionEvent.h"
26
27
28namespace android {
29
30// Special constant to request the velocity of the active pointer.
31static const int ACTIVE_POINTER_ID = -1;
32
33static struct {
34    jfieldID xCoeff;
35    jfieldID yCoeff;
36    jfieldID degree;
37    jfieldID confidence;
38} gEstimatorClassInfo;
39
40
41// --- VelocityTrackerState ---
42
43class VelocityTrackerState {
44public:
45    VelocityTrackerState();
46
47    void clear();
48    void addMovement(const MotionEvent* event);
49    void computeCurrentVelocity(int32_t units, float maxVelocity);
50    void getVelocity(int32_t id, float* outVx, float* outVy);
51    bool getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator);
52
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++) {
82        uint32_t id = idBits.clearFirstMarkedBit();
83
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
131bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator) {
132    return mVelocityTracker.getEstimator(id, outEstimator);
133}
134
135
136// --- JNI Methods ---
137
138static jint android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz) {
139    return reinterpret_cast<jint>(new VelocityTrackerState());
140}
141
142static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jint ptr) {
143    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
144    delete state;
145}
146
147static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jint ptr) {
148    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
149    state->clear();
150}
151
152static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jint ptr,
153        jobject eventObj) {
154    const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj);
155    if (!event) {
156        ALOGW("nativeAddMovement failed because MotionEvent was finalized.");
157        return;
158    }
159
160    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
161    state->addMovement(event);
162}
163
164static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz,
165        jint ptr, jint units, jfloat maxVelocity) {
166    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
167    state->computeCurrentVelocity(units, maxVelocity);
168}
169
170static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz,
171        jint ptr, jint id) {
172    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
173    float vx;
174    state->getVelocity(id, &vx, NULL);
175    return vx;
176}
177
178static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz,
179        jint ptr, jint id) {
180    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
181    float vy;
182    state->getVelocity(id, NULL, &vy);
183    return vy;
184}
185
186static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz,
187        jint ptr, jint id, jobject outEstimatorObj) {
188    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
189    VelocityTracker::Estimator estimator;
190    bool result = state->getEstimator(id, &estimator);
191
192    jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
193            gEstimatorClassInfo.xCoeff));
194    jfloatArray yCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
195            gEstimatorClassInfo.yCoeff));
196
197    env->SetFloatArrayRegion(xCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
198            estimator.xCoeff);
199    env->SetFloatArrayRegion(yCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
200            estimator.yCoeff);
201    env->SetIntField(outEstimatorObj, gEstimatorClassInfo.degree, estimator.degree);
202    env->SetFloatField(outEstimatorObj, gEstimatorClassInfo.confidence, estimator.confidence);
203    return result;
204}
205
206
207// --- JNI Registration ---
208
209static JNINativeMethod gVelocityTrackerMethods[] = {
210    /* name, signature, funcPtr */
211    { "nativeInitialize",
212            "()I",
213            (void*)android_view_VelocityTracker_nativeInitialize },
214    { "nativeDispose",
215            "(I)V",
216            (void*)android_view_VelocityTracker_nativeDispose },
217    { "nativeClear",
218            "(I)V",
219            (void*)android_view_VelocityTracker_nativeClear },
220    { "nativeAddMovement",
221            "(ILandroid/view/MotionEvent;)V",
222            (void*)android_view_VelocityTracker_nativeAddMovement },
223    { "nativeComputeCurrentVelocity",
224            "(IIF)V",
225            (void*)android_view_VelocityTracker_nativeComputeCurrentVelocity },
226    { "nativeGetXVelocity",
227            "(II)F",
228            (void*)android_view_VelocityTracker_nativeGetXVelocity },
229    { "nativeGetYVelocity",
230            "(II)F",
231            (void*)android_view_VelocityTracker_nativeGetYVelocity },
232    { "nativeGetEstimator",
233            "(IILandroid/view/VelocityTracker$Estimator;)Z",
234            (void*)android_view_VelocityTracker_nativeGetEstimator },
235};
236
237#define FIND_CLASS(var, className) \
238        var = env->FindClass(className); \
239        LOG_FATAL_IF(! var, "Unable to find class " className);
240
241#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
242        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
243        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
244
245int register_android_view_VelocityTracker(JNIEnv* env) {
246    int res = jniRegisterNativeMethods(env, "android/view/VelocityTracker",
247            gVelocityTrackerMethods, NELEM(gVelocityTrackerMethods));
248    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
249
250    jclass clazz;
251    FIND_CLASS(clazz, "android/view/VelocityTracker$Estimator");
252
253    GET_FIELD_ID(gEstimatorClassInfo.xCoeff, clazz,
254            "xCoeff", "[F");
255    GET_FIELD_ID(gEstimatorClassInfo.yCoeff, clazz,
256            "yCoeff", "[F");
257    GET_FIELD_ID(gEstimatorClassInfo.degree, clazz,
258            "degree", "I");
259    GET_FIELD_ID(gEstimatorClassInfo.confidence, clazz,
260            "confidence", "F");
261    return 0;
262}
263
264} // namespace android
265