android_view_VelocityTracker.cpp revision 8a90e6e3174083f274538567d851f98478fc83e9
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, uint32_t degree, nsecs_t horizon,
52            VelocityTracker::Estimator* outEstimator);
53
54private:
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
65VelocityTrackerState::VelocityTrackerState() : mActivePointerId(-1) {
66}
67
68void VelocityTrackerState::clear() {
69    mVelocityTracker.clear();
70    mActivePointerId = -1;
71    mCalculatedIdBits.clear();
72}
73
74void VelocityTrackerState::addMovement(const MotionEvent* event) {
75    mVelocityTracker.addMovement(event);
76}
77
78void 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
108void 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
132bool VelocityTrackerState::getEstimator(int32_t id, uint32_t degree, nsecs_t horizon,
133        VelocityTracker::Estimator* outEstimator) {
134    return mVelocityTracker.getEstimator(id, degree, horizon, outEstimator);
135}
136
137
138// --- JNI Methods ---
139
140static jint android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz) {
141    return reinterpret_cast<jint>(new VelocityTrackerState());
142}
143
144static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jint ptr) {
145    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
146    delete state;
147}
148
149static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jint ptr) {
150    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
151    state->clear();
152}
153
154static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jint ptr,
155        jobject eventObj) {
156    const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj);
157    if (!event) {
158        ALOGW("nativeAddMovement failed because MotionEvent was finalized.");
159        return;
160    }
161
162    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
163    state->addMovement(event);
164}
165
166static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz,
167        jint ptr, jint units, jfloat maxVelocity) {
168    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
169    state->computeCurrentVelocity(units, maxVelocity);
170}
171
172static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz,
173        jint ptr, jint id) {
174    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
175    float vx;
176    state->getVelocity(id, &vx, NULL);
177    return vx;
178}
179
180static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz,
181        jint ptr, jint id) {
182    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
183    float vy;
184    state->getVelocity(id, NULL, &vy);
185    return vy;
186}
187
188static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz,
189        jint ptr, jint id, jint degree, jint horizonMillis, jobject outEstimatorObj) {
190    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
191    VelocityTracker::Estimator estimator;
192    bool result = state->getEstimator(id,
193            degree < 0 ? VelocityTracker::DEFAULT_DEGREE : uint32_t(degree),
194            horizonMillis < 0 ? VelocityTracker::DEFAULT_HORIZON :
195                    nsecs_t(horizonMillis) * 1000000L,
196            &estimator);
197
198    jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
199            gEstimatorClassInfo.xCoeff));
200    jfloatArray yCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
201            gEstimatorClassInfo.yCoeff));
202
203    env->SetFloatArrayRegion(xCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
204            estimator.xCoeff);
205    env->SetFloatArrayRegion(yCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
206            estimator.yCoeff);
207    env->SetIntField(outEstimatorObj, gEstimatorClassInfo.degree, estimator.degree);
208    env->SetFloatField(outEstimatorObj, gEstimatorClassInfo.confidence, estimator.confidence);
209    return result;
210}
211
212
213// --- JNI Registration ---
214
215static JNINativeMethod gVelocityTrackerMethods[] = {
216    /* name, signature, funcPtr */
217    { "nativeInitialize",
218            "()I",
219            (void*)android_view_VelocityTracker_nativeInitialize },
220    { "nativeDispose",
221            "(I)V",
222            (void*)android_view_VelocityTracker_nativeDispose },
223    { "nativeClear",
224            "(I)V",
225            (void*)android_view_VelocityTracker_nativeClear },
226    { "nativeAddMovement",
227            "(ILandroid/view/MotionEvent;)V",
228            (void*)android_view_VelocityTracker_nativeAddMovement },
229    { "nativeComputeCurrentVelocity",
230            "(IIF)V",
231            (void*)android_view_VelocityTracker_nativeComputeCurrentVelocity },
232    { "nativeGetXVelocity",
233            "(II)F",
234            (void*)android_view_VelocityTracker_nativeGetXVelocity },
235    { "nativeGetYVelocity",
236            "(II)F",
237            (void*)android_view_VelocityTracker_nativeGetYVelocity },
238    { "nativeGetEstimator",
239            "(IIIILandroid/view/VelocityTracker$Estimator;)Z",
240            (void*)android_view_VelocityTracker_nativeGetEstimator },
241};
242
243#define FIND_CLASS(var, className) \
244        var = env->FindClass(className); \
245        LOG_FATAL_IF(! var, "Unable to find class " className);
246
247#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
248        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
249        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
250
251int register_android_view_VelocityTracker(JNIEnv* env) {
252    int res = jniRegisterNativeMethods(env, "android/view/VelocityTracker",
253            gVelocityTrackerMethods, NELEM(gVelocityTrackerMethods));
254    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
255
256    jclass clazz;
257    FIND_CLASS(clazz, "android/view/VelocityTracker$Estimator");
258
259    GET_FIELD_ID(gEstimatorClassInfo.xCoeff, clazz,
260            "xCoeff", "[F");
261    GET_FIELD_ID(gEstimatorClassInfo.yCoeff, clazz,
262            "yCoeff", "[F");
263    GET_FIELD_ID(gEstimatorClassInfo.degree, clazz,
264            "degree", "I");
265    GET_FIELD_ID(gEstimatorClassInfo.confidence, clazz,
266            "confidence", "F");
267    return 0;
268}
269
270} // namespace android
271