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