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

Commit 7a95fa7f authored by Siarhei Vishniakou's avatar Siarhei Vishniakou Committed by Android (Google) Code Review
Browse files

Merge "Revert "Check whether pointer has stopped at liftoff""

parents fb55f8a7 21fcc2b1
Loading
Loading
Loading
Loading
+41 −56
Original line number Original line Diff line number Diff line
@@ -27,8 +27,6 @@
#include <utils/BitSet.h>
#include <utils/BitSet.h>
#include <utils/Timers.h>
#include <utils/Timers.h>


using std::literals::chrono_literals::operator""ms;

namespace android {
namespace android {


/**
/**
@@ -59,14 +57,8 @@ static const nsecs_t NANOS_PER_MS = 1000000;
// Some input devices do not send ACTION_MOVE events in the case where a pointer has
// Some input devices do not send ACTION_MOVE events in the case where a pointer has
// stopped.  We need to detect this case so that we can accurately predict the
// stopped.  We need to detect this case so that we can accurately predict the
// velocity after the pointer starts moving again.
// velocity after the pointer starts moving again.
static const std::chrono::duration ASSUME_POINTER_STOPPED_TIME = 40ms;
static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS;


static std::string toString(std::chrono::nanoseconds t) {
    std::stringstream stream;
    stream.precision(1);
    stream << std::fixed << std::chrono::duration<float, std::milli>(t).count() << " ms";
    return stream.str();
}


static float vectorDot(const float* a, const float* b, uint32_t m) {
static float vectorDot(const float* a, const float* b, uint32_t m) {
    float r = 0;
    float r = 0;
@@ -154,14 +146,18 @@ std::unique_ptr<VelocityTrackerStrategy> VelocityTracker::createStrategy(
        VelocityTracker::Strategy strategy) {
        VelocityTracker::Strategy strategy) {
    switch (strategy) {
    switch (strategy) {
        case VelocityTracker::Strategy::IMPULSE:
        case VelocityTracker::Strategy::IMPULSE:
            ALOGI_IF(DEBUG_STRATEGY, "Initializing impulse strategy");
            if (DEBUG_STRATEGY) {
                ALOGI("Initializing impulse strategy");
            }
            return std::make_unique<ImpulseVelocityTrackerStrategy>();
            return std::make_unique<ImpulseVelocityTrackerStrategy>();


        case VelocityTracker::Strategy::LSQ1:
        case VelocityTracker::Strategy::LSQ1:
            return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1);
            return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1);


        case VelocityTracker::Strategy::LSQ2:
        case VelocityTracker::Strategy::LSQ2:
            ALOGI_IF(DEBUG_STRATEGY && !DEBUG_IMPULSE, "Initializing lsq2 strategy");
            if (DEBUG_STRATEGY && !DEBUG_IMPULSE) {
                ALOGI("Initializing lsq2 strategy");
            }
            return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2);
            return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2);


        case VelocityTracker::Strategy::LSQ3:
        case VelocityTracker::Strategy::LSQ3:
@@ -225,11 +221,12 @@ void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits,
        idBits.clearLastMarkedBit();
        idBits.clearLastMarkedBit();
    }
    }


    if ((mCurrentPointerIdBits.value & idBits.value) &&
    if ((mCurrentPointerIdBits.value & idBits.value)
        std::chrono::nanoseconds(eventTime - mLastEventTime) > ASSUME_POINTER_STOPPED_TIME) {
            && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
        ALOGD_IF(DEBUG_VELOCITY, "VelocityTracker: stopped for %s, clearing state.",
        if (DEBUG_VELOCITY) {
                 toString(std::chrono::nanoseconds(eventTime - mLastEventTime)).c_str());
            ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",

                  (eventTime - mLastEventTime) * 0.000001f);
        }
        // We have not received any movements for too long.  Assume that all pointers
        // We have not received any movements for too long.  Assume that all pointers
        // have stopped.
        // have stopped.
        mStrategy->clear();
        mStrategy->clear();
@@ -284,18 +281,8 @@ void VelocityTracker::addMovement(const MotionEvent* event) {
    case AMOTION_EVENT_ACTION_MOVE:
    case AMOTION_EVENT_ACTION_MOVE:
    case AMOTION_EVENT_ACTION_HOVER_MOVE:
    case AMOTION_EVENT_ACTION_HOVER_MOVE:
        break;
        break;
    case AMOTION_EVENT_ACTION_POINTER_UP:
    default:
    case AMOTION_EVENT_ACTION_UP: {
        // Ignore all other actions because they do not convey any new information about
        std::chrono::nanoseconds delaySinceLastEvent(event->getEventTime() - mLastEventTime);
        if (delaySinceLastEvent > ASSUME_POINTER_STOPPED_TIME) {
            ALOGD_IF(DEBUG_VELOCITY,
                     "VelocityTracker: stopped for %s, clearing state upon pointer liftoff.",
                     toString(delaySinceLastEvent).c_str());
            // We have not received any movements for too long.  Assume that all pointers
            // have stopped.
            mStrategy->clear();
        }
        // 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
@@ -305,10 +292,6 @@ void VelocityTracker::addMovement(const MotionEvent* event) {
        // before adding the movement.
        // before adding the movement.
        return;
        return;
    }
    }
    default:
        // Ignore all other actions.
        return;
    }


    size_t pointerCount = event->getPointerCount();
    size_t pointerCount = event->getPointerCount();
    if (pointerCount > MAX_POINTERS) {
    if (pointerCount > MAX_POINTERS) {
@@ -455,10 +438,10 @@ void LeastSquaresVelocityTrackerStrategy::addMovement(
static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y,
static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y,
                              const std::vector<float>& w, uint32_t n, float* outB, float* outDet) {
                              const std::vector<float>& w, uint32_t n, float* outB, float* outDet) {
    const size_t m = x.size();
    const size_t m = x.size();

    if (DEBUG_STRATEGY) {
    ALOGD_IF(DEBUG_STRATEGY, "solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
        ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
              vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str());
              vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str());

    }
    LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes");
    LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes");


    // Expand the X vector to a matrix A, pre-multiplied by the weights.
    // Expand the X vector to a matrix A, pre-multiplied by the weights.
@@ -469,9 +452,9 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo
            a[i][h] = a[i - 1][h] * x[h];
            a[i][h] = a[i - 1][h] * x[h];
        }
        }
    }
    }

    if (DEBUG_STRATEGY) {
    ALOGD_IF(DEBUG_STRATEGY, "  - a=%s",
        ALOGD("  - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
             matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str());
    }


    // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
    // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
    float q[n][m]; // orthonormal basis, column-major order
    float q[n][m]; // orthonormal basis, column-major order
@@ -490,7 +473,9 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo
        float norm = vectorNorm(&q[j][0], m);
        float norm = vectorNorm(&q[j][0], m);
        if (norm < 0.000001f) {
        if (norm < 0.000001f) {
            // vectors are linearly dependent or zero so no solution
            // vectors are linearly dependent or zero so no solution
            ALOGD_IF(DEBUG_STRATEGY, "  - no solution, norm=%f", norm);
            if (DEBUG_STRATEGY) {
                ALOGD("  - no solution, norm=%f", norm);
            }
            return false;
            return false;
        }
        }


@@ -533,8 +518,9 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo
        }
        }
        outB[i] /= r[i][i];
        outB[i] /= r[i][i];
    }
    }

    if (DEBUG_STRATEGY) {
    ALOGD_IF(DEBUG_STRATEGY, "  - b=%s", vectorToString(outB, n).c_str());
        ALOGD("  - b=%s", vectorToString(outB, n).c_str());
    }


    // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
    // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
    // SSerr is the residual sum of squares (variance of the error),
    // SSerr is the residual sum of squares (variance of the error),
@@ -560,11 +546,11 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo
        sstot += w[h] * w[h] * var * var;
        sstot += w[h] * w[h] * var * var;
    }
    }
    *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
    *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;

    if (DEBUG_STRATEGY) {
    ALOGD_IF(DEBUG_STRATEGY, "  - sserr=%f", sserr);
        ALOGD("  - sserr=%f", sserr);
    ALOGD_IF(DEBUG_STRATEGY, "  - sstot=%f", sstot);
        ALOGD("  - sstot=%f", sstot);
    ALOGD_IF(DEBUG_STRATEGY, "  - det=%f", *outDet);
        ALOGD("  - det=%f", *outDet);

    }
    return true;
    return true;
}
}


@@ -687,11 +673,11 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
            outEstimator->time = newestMovement.eventTime;
            outEstimator->time = newestMovement.eventTime;
            outEstimator->degree = degree;
            outEstimator->degree = degree;
            outEstimator->confidence = xdet * ydet;
            outEstimator->confidence = xdet * ydet;

            if (DEBUG_STRATEGY) {
            ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
                ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
                      int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(),
                      int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(),
                      vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence);
                      vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence);

            }
            return true;
            return true;
        }
        }
    }
    }
@@ -1199,10 +1185,9 @@ bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id,
    outEstimator->time = newestMovement.eventTime;
    outEstimator->time = newestMovement.eventTime;
    outEstimator->degree = 2; // similar results to 2nd degree fit
    outEstimator->degree = 2; // similar results to 2nd degree fit
    outEstimator->confidence = 1;
    outEstimator->confidence = 1;

    if (DEBUG_STRATEGY) {
    ALOGD_IF(DEBUG_STRATEGY, "velocity: (%.1f, %.1f)", outEstimator->xCoeff[1],
        ALOGD("velocity: (%.1f, %.1f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
             outEstimator->yCoeff[1]);
    }

    if (DEBUG_IMPULSE) {
    if (DEBUG_IMPULSE) {
        // TODO(b/134179997): delete this block once the switch to 'impulse' is complete.
        // TODO(b/134179997): delete this block once the switch to 'impulse' is complete.
        // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons
        // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons
+7 −66
Original line number Original line Diff line number Diff line
@@ -26,9 +26,7 @@
#include <gui/constants.h>
#include <gui/constants.h>
#include <input/VelocityTracker.h>
#include <input/VelocityTracker.h>


using std::literals::chrono_literals::operator""ms;
using namespace std::chrono_literals;
using std::literals::chrono_literals::operator""ns;
using std::literals::chrono_literals::operator""us;
using android::base::StringPrintf;
using android::base::StringPrintf;


namespace android {
namespace android {
@@ -151,7 +149,8 @@ static std::vector<MotionEvent> createMotionEventStream(
        if (i == 0) {
        if (i == 0) {
            action = AMOTION_EVENT_ACTION_DOWN;
            action = AMOTION_EVENT_ACTION_DOWN;
            EXPECT_EQ(1U, pointerCount) << "First event should only have 1 pointer";
            EXPECT_EQ(1U, pointerCount) << "First event should only have 1 pointer";
        } else if ((i == motions.size() - 1) && pointerCount == 1) {
        } else if (i == motions.size() - 1) {
            EXPECT_EQ(1U, pointerCount) << "Last event should only have 1 pointer";
            action = AMOTION_EVENT_ACTION_UP;
            action = AMOTION_EVENT_ACTION_UP;
        } else {
        } else {
            const MotionEventEntry& previousEntry = motions[i-1];
            const MotionEventEntry& previousEntry = motions[i-1];
@@ -196,7 +195,7 @@ static std::vector<MotionEvent> createMotionEventStream(


static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
                                    const std::vector<MotionEventEntry>& motions, int32_t axis,
                                    const std::vector<MotionEventEntry>& motions, int32_t axis,
                                    float targetVelocity, uint32_t pointerId = DEFAULT_POINTER_ID) {
                                    float targetVelocity) {
    VelocityTracker vt(strategy);
    VelocityTracker vt(strategy);
    float Vx, Vy;
    float Vx, Vy;


@@ -205,7 +204,7 @@ static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
        vt.addMovement(&event);
        vt.addMovement(&event);
    }
    }


    vt.getVelocity(pointerId, &Vx, &Vy);
    vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy);


    switch (axis) {
    switch (axis) {
    case AMOTION_EVENT_AXIS_X:
    case AMOTION_EVENT_AXIS_X:
@@ -847,70 +846,12 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_ThreeFi


    // Velocity should actually be zero, but we expect 0.016 here instead.
    // Velocity should actually be zero, but we expect 0.016 here instead.
    // This is close enough to zero, and is likely caused by division by a very small number.
    // This is close enough to zero, and is likely caused by division by a very small number.
    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, -0.016);
    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, 0);
    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, -0.016);
    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y, 0);
    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y, 0);
}
}


/**
 * ================= Pointer liftoff ===============================================================
 */

/**
 * The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a short delay
 * between the last ACTION_MOVE and the next ACTION_POINTER_UP or ACTION_UP, velocity should not be
 * affected by the liftoff.
 */
TEST_F(VelocityTrackerTest, ShortDelayBeforeActionUp) {
    std::vector<MotionEventEntry> motions = {
            {0ms, {{10, 0}}}, {10ms, {{20, 0}}}, {20ms, {{30, 0}}}, {30ms, {{30, 0}}}, // ACTION_UP
    };
    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
                            1000);
    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 1000);
}

/**
 * The last movement of a single pointer is ACTION_UP. If there's a long delay between the last
 * ACTION_MOVE and the final ACTION_UP, velocity should be reported as zero because the pointer
 * should be assumed to have stopped.
 */
TEST_F(VelocityTrackerTest, LongDelayBeforeActionUp) {
    std::vector<MotionEventEntry> motions = {
            {0ms, {{10, 0}}},
            {10ms, {{20, 0}}},
            {20ms, {{30, 0}}},
            {3000ms, {{30, 0}}}, // ACTION_UP
    };
    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
}

/**
 * The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a long delay
 * before ACTION_POINTER_UP event, the movement should be assumed to have stopped.
 * The final velocity should be reported as zero for all pointers.
 */
TEST_F(VelocityTrackerTest, LongDelayBeforeActionPointerUp) {
    std::vector<MotionEventEntry> motions = {
            {0ms, {{10, 0}}},
            {10ms, {{20, 0}, {100, 0}}},
            {20ms, {{30, 0}, {200, 0}}},
            {30ms, {{30, 0}, {300, 0}}},
            {40ms, {{30, 0}, {400, 0}}},
            {3000ms, {{30, 0}}}, // ACTION_POINTER_UP
    };
    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0,
                            /*pointerId*/ 0);
    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0,
                            /*pointerId*/ 0);
    computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0,
                            /*pointerId*/ 1);
    computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0,
                            /*pointerId*/ 1);
}

/**
/**
 * ================== Tests for least squares fitting ==============================================
 * ================== Tests for least squares fitting ==============================================
 *
 *