Home | History | Annotate | Download | only in jni
      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 <input/Input.h>
     24 #include <input/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