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 <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