Merge "Tweak VelocityTracker. Bug: 5265529"
This commit is contained in:
@@ -660,15 +660,19 @@ private:
|
|||||||
static const uint32_t HISTORY_SIZE = 10;
|
static const uint32_t HISTORY_SIZE = 10;
|
||||||
|
|
||||||
// Oldest sample to consider when calculating the velocity.
|
// Oldest sample to consider when calculating the velocity.
|
||||||
static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
|
static const nsecs_t MAX_AGE = 100 * 1000000; // 100 ms
|
||||||
|
|
||||||
// The minimum duration between samples when estimating velocity.
|
// The minimum duration between samples when estimating velocity.
|
||||||
static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
|
static const nsecs_t MIN_DURATION = 5 * 1000000; // 5 ms
|
||||||
|
|
||||||
struct Movement {
|
struct Movement {
|
||||||
nsecs_t eventTime;
|
nsecs_t eventTime;
|
||||||
BitSet32 idBits;
|
BitSet32 idBits;
|
||||||
Position positions[MAX_POINTERS];
|
Position positions[MAX_POINTERS];
|
||||||
|
|
||||||
|
inline const Position& getPosition(uint32_t id) const {
|
||||||
|
return positions[idBits.getIndexOfBit(id)];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t mIndex;
|
uint32_t mIndex;
|
||||||
|
|||||||
@@ -752,6 +752,7 @@ void VelocityTracker::addMovement(const MotionEvent* event) {
|
|||||||
|
|
||||||
switch (actionMasked) {
|
switch (actionMasked) {
|
||||||
case AMOTION_EVENT_ACTION_DOWN:
|
case AMOTION_EVENT_ACTION_DOWN:
|
||||||
|
case AMOTION_EVENT_ACTION_HOVER_ENTER:
|
||||||
// Clear all pointers on down before adding the new movement.
|
// Clear all pointers on down before adding the new movement.
|
||||||
clear();
|
clear();
|
||||||
break;
|
break;
|
||||||
@@ -764,12 +765,11 @@ void VelocityTracker::addMovement(const MotionEvent* event) {
|
|||||||
clearPointers(downIdBits);
|
clearPointers(downIdBits);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AMOTION_EVENT_ACTION_OUTSIDE:
|
case AMOTION_EVENT_ACTION_MOVE:
|
||||||
case AMOTION_EVENT_ACTION_CANCEL:
|
case AMOTION_EVENT_ACTION_HOVER_MOVE:
|
||||||
case AMOTION_EVENT_ACTION_SCROLL:
|
break;
|
||||||
case AMOTION_EVENT_ACTION_UP:
|
default:
|
||||||
case AMOTION_EVENT_ACTION_POINTER_UP:
|
// Ignore all other actions because they do not convey any new information about
|
||||||
// Ignore these actions because they do not convey any new information about
|
|
||||||
// pointer movement. We also want to preserve the last known velocity of the pointers.
|
// pointer movement. We also want to preserve the last known velocity of the pointers.
|
||||||
// Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
|
// Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
|
||||||
// of the pointers that went up. ACTION_POINTER_UP does include the new position of
|
// of the pointers that went up. ACTION_POINTER_UP does include the new position of
|
||||||
@@ -814,68 +814,36 @@ void VelocityTracker::addMovement(const MotionEvent* event) {
|
|||||||
bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
|
bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
|
||||||
const Movement& newestMovement = mMovements[mIndex];
|
const Movement& newestMovement = mMovements[mIndex];
|
||||||
if (newestMovement.idBits.hasBit(id)) {
|
if (newestMovement.idBits.hasBit(id)) {
|
||||||
// Find the oldest sample that contains the pointer and that is not older than MAX_AGE.
|
const Position& newestPosition = newestMovement.getPosition(id);
|
||||||
nsecs_t minTime = newestMovement.eventTime - MAX_AGE;
|
|
||||||
uint32_t oldestIndex = mIndex;
|
|
||||||
uint32_t numTouches = 1;
|
|
||||||
do {
|
|
||||||
uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
|
|
||||||
const Movement& nextOldestMovement = mMovements[nextOldestIndex];
|
|
||||||
if (!nextOldestMovement.idBits.hasBit(id)
|
|
||||||
|| nextOldestMovement.eventTime < minTime) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
oldestIndex = nextOldestIndex;
|
|
||||||
} while (++numTouches < HISTORY_SIZE);
|
|
||||||
|
|
||||||
// Calculate an exponentially weighted moving average of the velocity estimate
|
|
||||||
// at different points in time measured relative to the oldest sample.
|
|
||||||
// This is essentially an IIR filter. Newer samples are weighted more heavily
|
|
||||||
// than older samples. Samples at equal time points are weighted more or less
|
|
||||||
// equally.
|
|
||||||
//
|
|
||||||
// One tricky problem is that the sample data may be poorly conditioned.
|
|
||||||
// Sometimes samples arrive very close together in time which can cause us to
|
|
||||||
// overestimate the velocity at that time point. Most samples might be measured
|
|
||||||
// 16ms apart but some consecutive samples could be only 0.5sm apart because
|
|
||||||
// the hardware or driver reports them irregularly or in bursts.
|
|
||||||
float accumVx = 0;
|
float accumVx = 0;
|
||||||
float accumVy = 0;
|
float accumVy = 0;
|
||||||
uint32_t index = oldestIndex;
|
float duration = 0;
|
||||||
uint32_t samplesUsed = 0;
|
|
||||||
const Movement& oldestMovement = mMovements[oldestIndex];
|
|
||||||
const Position& oldestPosition =
|
|
||||||
oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
|
|
||||||
nsecs_t lastDuration = 0;
|
|
||||||
|
|
||||||
while (numTouches-- > 1) {
|
// Iterate over movement samples in reverse time order and accumulate velocity.
|
||||||
if (++index == HISTORY_SIZE) {
|
uint32_t index = mIndex;
|
||||||
index = 0;
|
do {
|
||||||
}
|
index = (index == 0 ? HISTORY_SIZE : index) - 1;
|
||||||
const Movement& movement = mMovements[index];
|
const Movement& movement = mMovements[index];
|
||||||
nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
|
if (!movement.idBits.hasBit(id)) {
|
||||||
|
break;
|
||||||
// If the duration between samples is small, we may significantly overestimate
|
|
||||||
// the velocity. Consequently, we impose a minimum duration constraint on the
|
|
||||||
// samples that we include in the calculation.
|
|
||||||
if (duration >= MIN_DURATION) {
|
|
||||||
const Position& position = movement.positions[movement.idBits.getIndexOfBit(id)];
|
|
||||||
float scale = 1000000000.0f / duration; // one over time delta in seconds
|
|
||||||
float vx = (position.x - oldestPosition.x) * scale;
|
|
||||||
float vy = (position.y - oldestPosition.y) * scale;
|
|
||||||
|
|
||||||
accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
|
|
||||||
accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
|
|
||||||
|
|
||||||
lastDuration = duration;
|
|
||||||
samplesUsed += 1;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
nsecs_t age = newestMovement.eventTime - movement.eventTime;
|
||||||
|
if (age > MAX_AGE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Position& position = movement.getPosition(id);
|
||||||
|
accumVx += newestPosition.x - position.x;
|
||||||
|
accumVy += newestPosition.y - position.y;
|
||||||
|
duration += age;
|
||||||
|
} while (index != mIndex);
|
||||||
|
|
||||||
// Make sure we used at least one sample.
|
// Make sure we used at least one sample.
|
||||||
if (samplesUsed != 0) {
|
if (duration >= MIN_DURATION) {
|
||||||
*outVx = accumVx;
|
float scale = 1000000000.0f / duration; // one over time delta in seconds
|
||||||
*outVy = accumVy;
|
*outVx = accumVx * scale;
|
||||||
|
*outVy = accumVy * scale;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user