android_view_VelocityTracker.cpp revision 8564c8da817a845353d213acd8636b76f567b234
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 <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
32static struct {
33    jfieldID xCoeff;
34    jfieldID yCoeff;
35    jfieldID degree;
36    jfieldID confidence;
37} gEstimatorClassInfo;
38
39
40// --- 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);
50    bool getEstimator(int32_t id, uint32_t degree, nsecs_t horizon,
51            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, uint32_t degree, nsecs_t horizon,
132        VelocityTracker::Estimator* outEstimator) {
133    return mVelocityTracker.getEstimator(id, degree, horizon, outEstimator);
134}
135
136
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        ALOGW("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
187static 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
211
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 },
237    { "nativeGetEstimator",
238            "(IIIILandroid/view/VelocityTracker$Estimator;)Z",
239            (void*)android_view_VelocityTracker_nativeGetEstimator },
240};
241
242#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
250int 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.");
254
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");
266    return 0;
267}
268
269} // namespace android
270