Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec9a0599 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Tweak VelocityTracker. Bug: 5265529"

parents e271bf8f 137c3c54
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -660,15 +660,19 @@ private:
    static const uint32_t HISTORY_SIZE = 10;

    // 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.
    static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
    static const nsecs_t MIN_DURATION = 5 * 1000000; // 5 ms

    struct Movement {
        nsecs_t eventTime;
        BitSet32 idBits;
        Position positions[MAX_POINTERS];

        inline const Position& getPosition(uint32_t id) const {
            return positions[idBits.getIndexOfBit(id)];
        }
    };

    uint32_t mIndex;
+30 −62
Original line number Diff line number Diff line
@@ -752,6 +752,7 @@ void VelocityTracker::addMovement(const MotionEvent* event) {

    switch (actionMasked) {
    case AMOTION_EVENT_ACTION_DOWN:
    case AMOTION_EVENT_ACTION_HOVER_ENTER:
        // Clear all pointers on down before adding the new movement.
        clear();
        break;
@@ -764,12 +765,11 @@ void VelocityTracker::addMovement(const MotionEvent* event) {
        clearPointers(downIdBits);
        break;
    }
    case AMOTION_EVENT_ACTION_OUTSIDE:
    case AMOTION_EVENT_ACTION_CANCEL:
    case AMOTION_EVENT_ACTION_SCROLL:
    case AMOTION_EVENT_ACTION_UP:
    case AMOTION_EVENT_ACTION_POINTER_UP:
        // Ignore these actions because they do not convey any new information about
    case AMOTION_EVENT_ACTION_MOVE:
    case AMOTION_EVENT_ACTION_HOVER_MOVE:
        break;
    default:
        // Ignore all other actions because they do not convey any new information about
        // 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
        // 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 {
    const Movement& newestMovement = mMovements[mIndex];
    if (newestMovement.idBits.hasBit(id)) {
        // Find the oldest sample that contains the pointer and that is not older than MAX_AGE.
        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.
        const Position& newestPosition = newestMovement.getPosition(id);
        float accumVx = 0;
        float accumVy = 0;
        uint32_t index = oldestIndex;
        uint32_t samplesUsed = 0;
        const Movement& oldestMovement = mMovements[oldestIndex];
        const Position& oldestPosition =
                oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
        nsecs_t lastDuration = 0;
        float duration = 0;

        while (numTouches-- > 1) {
            if (++index == HISTORY_SIZE) {
                index = 0;
            }
        // Iterate over movement samples in reverse time order and accumulate velocity.
        uint32_t index = mIndex;
        do {
            index = (index == 0 ? HISTORY_SIZE : index) - 1;
            const Movement& movement = mMovements[index];
            nsecs_t duration = movement.eventTime - oldestMovement.eventTime;

            // 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;
            if (!movement.idBits.hasBit(id)) {
                break;
            }

            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.
        if (samplesUsed != 0) {
            *outVx = accumVx;
            *outVy = accumVy;
        if (duration >= MIN_DURATION) {
            float scale = 1000000000.0f / duration; // one over time delta in seconds
            *outVx = accumVx * scale;
            *outVy = accumVy * scale;
            return true;
        }
    }