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