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 27 namespace android { 28 29 // Special constant to request the velocity of the active pointer. 30 static const int ACTIVE_POINTER_ID = -1; 31 32 static struct { 33 jfieldID xCoeff; 34 jfieldID yCoeff; 35 jfieldID degree; 36 jfieldID confidence; 37 } gEstimatorClassInfo; 38 39 40 // --- VelocityTrackerState --- 41 42 class VelocityTrackerState { 43 public: 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 53 private: 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 64 VelocityTrackerState::VelocityTrackerState() : mActivePointerId(-1) { 65 } 66 67 void VelocityTrackerState::clear() { 68 mVelocityTracker.clear(); 69 mActivePointerId = -1; 70 mCalculatedIdBits.clear(); 71 } 72 73 void VelocityTrackerState::addMovement(const MotionEvent* event) { 74 mVelocityTracker.addMovement(event); 75 } 76 77 void 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 107 void 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 131 bool 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 139 static jint android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz) { 140 return reinterpret_cast<jint>(new VelocityTrackerState()); 141 } 142 143 static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jint ptr) { 144 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 145 delete state; 146 } 147 148 static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jint ptr) { 149 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 150 state->clear(); 151 } 152 153 static 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 LOGW("nativeAddMovement failed because MotionEvent was finalized."); 158 return; 159 } 160 161 VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr); 162 state->addMovement(event); 163 } 164 165 static 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 171 static 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 179 static 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 187 static 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 214 static 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 250 int 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