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 #include <ScopedUtfChars.h> 28 29 30 namespace android { 31 32 // Special constant to request the velocity of the active pointer. 33 static const int ACTIVE_POINTER_ID = -1; 34 35 static struct { 36 jfieldID xCoeff; 37 jfieldID yCoeff; 38 jfieldID degree; 39 jfieldID confidence; 40 } gEstimatorClassInfo; 41 42 43 // --- VelocityTrackerState --- 44 45 class VelocityTrackerState { 46 public: 47 VelocityTrackerState(const char* strategy); 48 49 void clear(); 50 void addMovement(const MotionEvent* event); 51 void computeCurrentVelocity(int32_t units, float maxVelocity); 52 void getVelocity(int32_t id, float* outVx, float* outVy); 53 bool getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator); 54 55 private: 56 struct Velocity { 57 float vx, vy; 58 }; 59 60 VelocityTracker mVelocityTracker; 61 int32_t mActivePointerId; 62 BitSet32 mCalculatedIdBits; 63 Velocity mCalculatedVelocity[MAX_POINTERS]; 64 }; 65 66 VelocityTrackerState::VelocityTrackerState(const char* strategy) : 67 mVelocityTracker(strategy), mActivePointerId(-1) { 68 } 69 70 void VelocityTrackerState::clear() { 71 mVelocityTracker.clear(); 72 mActivePointerId = -1; 73 mCalculatedIdBits.clear(); 74 } 75 76 void VelocityTrackerState::addMovement(const MotionEvent* event) { 77 mVelocityTracker.addMovement(event); 78 } 79 80 void VelocityTrackerState::computeCurrentVelocity(int32_t units, float maxVelocity) { 81 BitSet32 idBits(mVelocityTracker.getCurrentPointerIdBits()); 82 mCalculatedIdBits = idBits; 83 84 for (uint32_t index = 0; !idBits.isEmpty(); index++) { 85 uint32_t id = idBits.clearFirstMarkedBit(); 86 87 float vx, vy; 88 mVelocityTracker.getVelocity(id, &vx, &vy); 89 90 vx = vx * units / 1000; 91 vy = vy * units / 1000; 92 93 if (vx > maxVelocity) { 94 vx = maxVelocity; 95 } else if (vx < -maxVelocity) { 96 vx = -maxVelocity; 97 } 98 if (vy > maxVelocity) { 99 vy = maxVelocity; 100 } else if (vy < -maxVelocity) { 101 vy = -maxVelocity; 102 } 103 104 Velocity& velocity = mCalculatedVelocity[index]; 105 velocity.vx = vx; 106 velocity.vy = vy; 107 } 108 } 109 110 void VelocityTrackerState::getVelocity(int32_t id, float* outVx, float* outVy) { 111 if (id == ACTIVE_POINTER_ID) { 112 id = mVelocityTracker.getActivePointerId(); 113 } 114 115 float vx, vy; 116 if (id >= 0 && id <= MAX_POINTER_ID && mCalculatedIdBits.hasBit(id)) { 117 uint32_t index = mCalculatedIdBits.getIndexOfBit(id); 118 const Velocity& velocity = mCalculatedVelocity[index]; 119 vx = velocity.vx; 120 vy = velocity.vy; 121 } else { 122 vx = 0; 123 vy = 0; 124 } 125 126 if (outVx) { 127 *outVx = vx; 128 } 129 if (outVy) { 130 *outVy = vy; 131 } 132 } 133 134 bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator) { 135 return mVelocityTracker.getEstimator(id, outEstimator); 136 } 137 138 139 // --- JNI Methods --- 140 141 static jint android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz, 142 jstring strategyStr) { 143 if (strategyStr) { 144 ScopedUtfChars strategy(env, strategyStr); 145 return reinterpret_cast<jint>(new VelocityTrackerState(strategy.c_str())); 146 } 147 return reinterpret_cast<jint>(new VelocityTrackerState(NULL)); 148 } 149 150 static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jint ptr) { 151 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 152 delete state; 153 } 154 155 static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jint ptr) { 156 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 157 state->clear(); 158 } 159 160 static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jint ptr, 161 jobject eventObj) { 162 const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj); 163 if (!event) { 164 ALOGW("nativeAddMovement failed because MotionEvent was finalized."); 165 return; 166 } 167 168 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 169 state->addMovement(event); 170 } 171 172 static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz, 173 jint ptr, jint units, jfloat maxVelocity) { 174 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 175 state->computeCurrentVelocity(units, maxVelocity); 176 } 177 178 static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz, 179 jint ptr, jint id) { 180 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 181 float vx; 182 state->getVelocity(id, &vx, NULL); 183 return vx; 184 } 185 186 static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz, 187 jint ptr, jint id) { 188 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 189 float vy; 190 state->getVelocity(id, NULL, &vy); 191 return vy; 192 } 193 194 static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz, 195 jint ptr, jint id, jobject outEstimatorObj) { 196 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 197 VelocityTracker::Estimator estimator; 198 bool result = state->getEstimator(id, &estimator); 199 200 jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj, 201 gEstimatorClassInfo.xCoeff)); 202 jfloatArray yCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj, 203 gEstimatorClassInfo.yCoeff)); 204 205 env->SetFloatArrayRegion(xCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1, 206 estimator.xCoeff); 207 env->SetFloatArrayRegion(yCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1, 208 estimator.yCoeff); 209 env->SetIntField(outEstimatorObj, gEstimatorClassInfo.degree, estimator.degree); 210 env->SetFloatField(outEstimatorObj, gEstimatorClassInfo.confidence, estimator.confidence); 211 return result; 212 } 213 214 215 // --- JNI Registration --- 216 217 static JNINativeMethod gVelocityTrackerMethods[] = { 218 /* name, signature, funcPtr */ 219 { "nativeInitialize", 220 "(Ljava/lang/String;)I", 221 (void*)android_view_VelocityTracker_nativeInitialize }, 222 { "nativeDispose", 223 "(I)V", 224 (void*)android_view_VelocityTracker_nativeDispose }, 225 { "nativeClear", 226 "(I)V", 227 (void*)android_view_VelocityTracker_nativeClear }, 228 { "nativeAddMovement", 229 "(ILandroid/view/MotionEvent;)V", 230 (void*)android_view_VelocityTracker_nativeAddMovement }, 231 { "nativeComputeCurrentVelocity", 232 "(IIF)V", 233 (void*)android_view_VelocityTracker_nativeComputeCurrentVelocity }, 234 { "nativeGetXVelocity", 235 "(II)F", 236 (void*)android_view_VelocityTracker_nativeGetXVelocity }, 237 { "nativeGetYVelocity", 238 "(II)F", 239 (void*)android_view_VelocityTracker_nativeGetYVelocity }, 240 { "nativeGetEstimator", 241 "(IILandroid/view/VelocityTracker$Estimator;)Z", 242 (void*)android_view_VelocityTracker_nativeGetEstimator }, 243 }; 244 245 #define FIND_CLASS(var, className) \ 246 var = env->FindClass(className); \ 247 LOG_FATAL_IF(! var, "Unable to find class " className); 248 249 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 250 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 251 LOG_FATAL_IF(! var, "Unable to find field " fieldName); 252 253 int register_android_view_VelocityTracker(JNIEnv* env) { 254 int res = jniRegisterNativeMethods(env, "android/view/VelocityTracker", 255 gVelocityTrackerMethods, NELEM(gVelocityTrackerMethods)); 256 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 257 258 jclass clazz; 259 FIND_CLASS(clazz, "android/view/VelocityTracker$Estimator"); 260 261 GET_FIELD_ID(gEstimatorClassInfo.xCoeff, clazz, 262 "xCoeff", "[F"); 263 GET_FIELD_ID(gEstimatorClassInfo.yCoeff, clazz, 264 "yCoeff", "[F"); 265 GET_FIELD_ID(gEstimatorClassInfo.degree, clazz, 266 "degree", "I"); 267 GET_FIELD_ID(gEstimatorClassInfo.confidence, clazz, 268 "confidence", "F"); 269 return 0; 270 } 271 272 } // namespace android 273