Implement pointer acceleration.
Bug: 4124987
Change-Id: I1f31a28f1594c55302ccabe13fe3ca6d2ff71d50
diff --git a/include/ui/Input.h b/include/ui/Input.h
index fb6152e..d603441 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -627,6 +627,87 @@
int32_t mActivePointerId;
};
+
+/*
+ * Specifies parameters that govern pointer or wheel acceleration.
+ */
+struct VelocityControlParameters {
+ // A scale factor that is multiplied with the raw velocity deltas
+ // prior to applying any other velocity control factors. The scale
+ // factor should be used to adapt the input device resolution
+ // (eg. counts per inch) to the output device resolution (eg. pixels per inch).
+ //
+ // Must be a positive value.
+ // Default is 1.0 (no scaling).
+ float scale;
+
+ // The scaled speed at which acceleration begins to be applied.
+ // This value establishes the upper bound of a low speed regime for
+ // small precise motions that are performed without any acceleration.
+ //
+ // Must be a non-negative value.
+ // Default is 0.0 (no low threshold).
+ float lowThreshold;
+
+ // The scaled speed at which maximum acceleration is applied.
+ // The difference between highThreshold and lowThreshold controls
+ // the range of speeds over which the acceleration factor is interpolated.
+ // The wider the range, the smoother the acceleration.
+ //
+ // Must be a non-negative value greater than or equal to lowThreshold.
+ // Default is 0.0 (no high threshold).
+ float highThreshold;
+
+ // The acceleration factor.
+ // When the speed is above the low speed threshold, the velocity will scaled
+ // by an interpolated value between 1.0 and this amount.
+ //
+ // Must be a positive greater than or equal to 1.0.
+ // Default is 1.0 (no acceleration).
+ float acceleration;
+
+ VelocityControlParameters() :
+ scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) {
+ }
+
+ VelocityControlParameters(float scale, float lowThreshold,
+ float highThreshold, float acceleration) :
+ scale(scale), lowThreshold(lowThreshold),
+ highThreshold(highThreshold), acceleration(acceleration) {
+ }
+};
+
+/*
+ * Implements mouse pointer and wheel speed control and acceleration.
+ */
+class VelocityControl {
+public:
+ VelocityControl();
+
+ /* Sets the various parameters. */
+ void setParameters(const VelocityControlParameters& parameters);
+
+ /* Resets the current movement counters to zero.
+ * This has the effect of nullifying any acceleration. */
+ void reset();
+
+ /* Translates a raw movement delta into an appropriately
+ * scaled / accelerated delta based on the current velocity. */
+ void move(nsecs_t eventTime, float* deltaX, float* deltaY);
+
+private:
+ // If no movements are received within this amount of time,
+ // we assume the movement has stopped and reset the movement counters.
+ static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms
+
+ VelocityControlParameters mParameters;
+
+ nsecs_t mLastMovementTime;
+ VelocityTracker::Position mRawPosition;
+ VelocityTracker mVelocityTracker;
+};
+
+
/*
* Describes the characteristics and capabilities of an input device.
*/
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 684c332..50b75d5 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -13,6 +13,10 @@
// Log debug messages about velocity tracking.
#define DEBUG_VELOCITY 0
+// Log debug messages about acceleration.
+#define DEBUG_ACCELERATION 0
+
+
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
@@ -20,6 +24,7 @@
#include <ui/Input.h>
#include <math.h>
+#include <limits.h>
#ifdef HAVE_ANDROID_OS
#include <binder/Parcel.h>
@@ -670,6 +675,11 @@
// --- VelocityTracker ---
+const uint32_t VelocityTracker::HISTORY_SIZE;
+const nsecs_t VelocityTracker::MAX_AGE;
+const nsecs_t VelocityTracker::MIN_WINDOW;
+const nsecs_t VelocityTracker::MIN_DURATION;
+
VelocityTracker::VelocityTracker() {
clear();
}
@@ -879,6 +889,85 @@
}
+// --- VelocityControl ---
+
+const nsecs_t VelocityControl::STOP_TIME;
+
+VelocityControl::VelocityControl() {
+ reset();
+}
+
+void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
+ mParameters = parameters;
+ reset();
+}
+
+void VelocityControl::reset() {
+ mLastMovementTime = LLONG_MIN;
+ mRawPosition.x = 0;
+ mRawPosition.y = 0;
+ mVelocityTracker.clear();
+}
+
+void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
+ if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
+ if (eventTime >= mLastMovementTime + STOP_TIME) {
+#if DEBUG_ACCELERATION
+ LOGD("VelocityControl: stopped, last movement was %0.3fms ago",
+ (eventTime - mLastMovementTime) * 0.000001f);
+#endif
+ reset();
+ }
+
+ mLastMovementTime = eventTime;
+ if (deltaX) {
+ mRawPosition.x += *deltaX;
+ }
+ if (deltaY) {
+ mRawPosition.y += *deltaY;
+ }
+ mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
+
+ float vx, vy;
+ float scale = mParameters.scale;
+ if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
+ float speed = hypotf(vx, vy) * scale;
+ if (speed >= mParameters.highThreshold) {
+ // Apply full acceleration above the high speed threshold.
+ scale *= mParameters.acceleration;
+ } else if (speed > mParameters.lowThreshold) {
+ // Linearly interpolate the acceleration to apply between the low and high
+ // speed thresholds.
+ scale *= 1 + (speed - mParameters.lowThreshold)
+ / (mParameters.highThreshold - mParameters.lowThreshold)
+ * (mParameters.acceleration - 1);
+ }
+
+#if DEBUG_ACCELERATION
+ LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
+ "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration,
+ vx, vy, speed, scale / mParameters.scale);
+#endif
+ } else {
+#if DEBUG_ACCELERATION
+ LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration);
+#endif
+ }
+
+ if (deltaX) {
+ *deltaX *= scale;
+ }
+ if (deltaY) {
+ *deltaY *= scale;
+ }
+ }
+}
+
+
// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {