/*
|
* Copyright (C) 2011 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
#define LOG_TAG "VelocityTracker-JNI"
|
|
#include <nativehelper/JNIHelp.h>
|
|
#include <android_runtime/AndroidRuntime.h>
|
#include <utils/Log.h>
|
#include <input/Input.h>
|
#include <input/VelocityTracker.h>
|
#include "android_view_MotionEvent.h"
|
|
#include <nativehelper/ScopedUtfChars.h>
|
|
#include "core_jni_helpers.h"
|
|
namespace android {
|
|
// Special constant to request the velocity of the active pointer.
|
static const int ACTIVE_POINTER_ID = -1;
|
|
static struct {
|
jfieldID xCoeff;
|
jfieldID yCoeff;
|
jfieldID degree;
|
jfieldID confidence;
|
} gEstimatorClassInfo;
|
|
|
// --- VelocityTrackerState ---
|
|
class VelocityTrackerState {
|
public:
|
explicit VelocityTrackerState(const char* strategy);
|
|
void clear();
|
void addMovement(const MotionEvent* event);
|
void computeCurrentVelocity(int32_t units, float maxVelocity);
|
void getVelocity(int32_t id, float* outVx, float* outVy);
|
bool getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator);
|
|
private:
|
struct Velocity {
|
float vx, vy;
|
};
|
|
VelocityTracker mVelocityTracker;
|
int32_t mActivePointerId;
|
BitSet32 mCalculatedIdBits;
|
Velocity mCalculatedVelocity[MAX_POINTERS];
|
};
|
|
VelocityTrackerState::VelocityTrackerState(const char* strategy) :
|
mVelocityTracker(strategy), mActivePointerId(-1) {
|
}
|
|
void VelocityTrackerState::clear() {
|
mVelocityTracker.clear();
|
mActivePointerId = -1;
|
mCalculatedIdBits.clear();
|
}
|
|
void VelocityTrackerState::addMovement(const MotionEvent* event) {
|
mVelocityTracker.addMovement(event);
|
}
|
|
void VelocityTrackerState::computeCurrentVelocity(int32_t units, float maxVelocity) {
|
BitSet32 idBits(mVelocityTracker.getCurrentPointerIdBits());
|
mCalculatedIdBits = idBits;
|
|
for (uint32_t index = 0; !idBits.isEmpty(); index++) {
|
uint32_t id = idBits.clearFirstMarkedBit();
|
|
float vx, vy;
|
mVelocityTracker.getVelocity(id, &vx, &vy);
|
|
vx = vx * units / 1000;
|
vy = vy * units / 1000;
|
|
if (vx > maxVelocity) {
|
vx = maxVelocity;
|
} else if (vx < -maxVelocity) {
|
vx = -maxVelocity;
|
}
|
if (vy > maxVelocity) {
|
vy = maxVelocity;
|
} else if (vy < -maxVelocity) {
|
vy = -maxVelocity;
|
}
|
|
Velocity& velocity = mCalculatedVelocity[index];
|
velocity.vx = vx;
|
velocity.vy = vy;
|
}
|
}
|
|
void VelocityTrackerState::getVelocity(int32_t id, float* outVx, float* outVy) {
|
if (id == ACTIVE_POINTER_ID) {
|
id = mVelocityTracker.getActivePointerId();
|
}
|
|
float vx, vy;
|
if (id >= 0 && id <= MAX_POINTER_ID && mCalculatedIdBits.hasBit(id)) {
|
uint32_t index = mCalculatedIdBits.getIndexOfBit(id);
|
const Velocity& velocity = mCalculatedVelocity[index];
|
vx = velocity.vx;
|
vy = velocity.vy;
|
} else {
|
vx = 0;
|
vy = 0;
|
}
|
|
if (outVx) {
|
*outVx = vx;
|
}
|
if (outVy) {
|
*outVy = vy;
|
}
|
}
|
|
bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator) {
|
return mVelocityTracker.getEstimator(id, outEstimator);
|
}
|
|
|
// --- JNI Methods ---
|
|
static jlong android_view_VelocityTracker_nativeInitialize(JNIEnv* env, jclass clazz,
|
jstring strategyStr) {
|
if (strategyStr) {
|
ScopedUtfChars strategy(env, strategyStr);
|
return reinterpret_cast<jlong>(new VelocityTrackerState(strategy.c_str()));
|
}
|
return reinterpret_cast<jlong>(new VelocityTrackerState(NULL));
|
}
|
|
static void android_view_VelocityTracker_nativeDispose(JNIEnv* env, jclass clazz, jlong ptr) {
|
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
|
delete state;
|
}
|
|
static void android_view_VelocityTracker_nativeClear(JNIEnv* env, jclass clazz, jlong ptr) {
|
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
|
state->clear();
|
}
|
|
static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jlong ptr,
|
jobject eventObj) {
|
const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj);
|
if (!event) {
|
ALOGW("nativeAddMovement failed because MotionEvent was finalized.");
|
return;
|
}
|
|
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
|
state->addMovement(event);
|
}
|
|
static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz,
|
jlong ptr, jint units, jfloat maxVelocity) {
|
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
|
state->computeCurrentVelocity(units, maxVelocity);
|
}
|
|
static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz,
|
jlong ptr, jint id) {
|
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
|
float vx;
|
state->getVelocity(id, &vx, NULL);
|
return vx;
|
}
|
|
static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz,
|
jlong ptr, jint id) {
|
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
|
float vy;
|
state->getVelocity(id, NULL, &vy);
|
return vy;
|
}
|
|
static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz,
|
jlong ptr, jint id, jobject outEstimatorObj) {
|
VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
|
VelocityTracker::Estimator estimator;
|
bool result = state->getEstimator(id, &estimator);
|
|
jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
|
gEstimatorClassInfo.xCoeff));
|
jfloatArray yCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
|
gEstimatorClassInfo.yCoeff));
|
|
env->SetFloatArrayRegion(xCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
|
estimator.xCoeff);
|
env->SetFloatArrayRegion(yCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
|
estimator.yCoeff);
|
env->SetIntField(outEstimatorObj, gEstimatorClassInfo.degree, estimator.degree);
|
env->SetFloatField(outEstimatorObj, gEstimatorClassInfo.confidence, estimator.confidence);
|
return result;
|
}
|
|
|
// --- JNI Registration ---
|
|
static const JNINativeMethod gVelocityTrackerMethods[] = {
|
/* name, signature, funcPtr */
|
{ "nativeInitialize",
|
"(Ljava/lang/String;)J",
|
(void*)android_view_VelocityTracker_nativeInitialize },
|
{ "nativeDispose",
|
"(J)V",
|
(void*)android_view_VelocityTracker_nativeDispose },
|
{ "nativeClear",
|
"(J)V",
|
(void*)android_view_VelocityTracker_nativeClear },
|
{ "nativeAddMovement",
|
"(JLandroid/view/MotionEvent;)V",
|
(void*)android_view_VelocityTracker_nativeAddMovement },
|
{ "nativeComputeCurrentVelocity",
|
"(JIF)V",
|
(void*)android_view_VelocityTracker_nativeComputeCurrentVelocity },
|
{ "nativeGetXVelocity",
|
"(JI)F",
|
(void*)android_view_VelocityTracker_nativeGetXVelocity },
|
{ "nativeGetYVelocity",
|
"(JI)F",
|
(void*)android_view_VelocityTracker_nativeGetYVelocity },
|
{ "nativeGetEstimator",
|
"(JILandroid/view/VelocityTracker$Estimator;)Z",
|
(void*)android_view_VelocityTracker_nativeGetEstimator },
|
};
|
|
int register_android_view_VelocityTracker(JNIEnv* env) {
|
int res = RegisterMethodsOrDie(env, "android/view/VelocityTracker", gVelocityTrackerMethods,
|
NELEM(gVelocityTrackerMethods));
|
|
jclass clazz = FindClassOrDie(env, "android/view/VelocityTracker$Estimator");
|
|
gEstimatorClassInfo.xCoeff = GetFieldIDOrDie(env, clazz, "xCoeff", "[F");
|
gEstimatorClassInfo.yCoeff = GetFieldIDOrDie(env, clazz, "yCoeff", "[F");
|
gEstimatorClassInfo.degree = GetFieldIDOrDie(env, clazz, "degree", "I");
|
gEstimatorClassInfo.confidence = GetFieldIDOrDie(env, clazz, "confidence", "F");
|
|
return res;
|
}
|
|
} // namespace android
|