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