diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2023-03-11 03:19:59 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-03-11 03:19:59 +0000 |
commit | f24a0c6b22855d4dc437a11f8513708d6863c2a2 (patch) | |
tree | eaa550119aee163a1b0d492d5e06793d46c75d55 | |
parent | 36e64fa1cfc4c1ef36fb858adcaa02abd92087a0 (diff) | |
parent | 7262ab6b9e55027bb5fb9ca67ac4eb6bd0ea43d7 (diff) | |
download | native-f24a0c6b22855d4dc437a11f8513708d6863c2a2.tar.gz |
Merge "MotionEvent: Round coordinates to a precision of 0.001" am: 7262ab6b9e
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/2480581
Change-Id: Ide748f30d5706b26d464d2dac261a6145602c661
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | include/input/Input.h | 2 | ||||
-rw-r--r-- | libs/input/Input.cpp | 21 | ||||
-rw-r--r-- | libs/input/tests/InputEvent_test.cpp | 318 | ||||
-rw-r--r-- | libs/input/tests/InputPublisherAndConsumer_test.cpp | 20 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 8 |
5 files changed, 227 insertions, 142 deletions
diff --git a/include/input/Input.h b/include/input/Input.h index 7ea297049b..1eda981ee9 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -818,6 +818,8 @@ public: const PointerCoords&); static PointerCoords calculateTransformedCoords(uint32_t source, const ui::Transform&, const PointerCoords&); + // The rounding precision for transformed motion events. + static constexpr float ROUNDING_PRECISION = 0.001f; protected: int32_t mAction; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 2b7483d27d..2581668429 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -137,10 +137,23 @@ int32_t IdGenerator::nextId() const { // --- InputEvent --- +// Due to precision limitations when working with floating points, transforming - namely +// scaling - floating points can lead to minute errors. We round transformed values to approximately +// three decimal places so that values like 0.99997 show up as 1.0. +inline float roundTransformedCoords(float val) { + // Use a power to two to approximate three decimal places to potentially reduce some cycles. + // This should be at least as precise as MotionEvent::ROUNDING_PRECISION. + return std::round(val * 1024.f) / 1024.f; +} + +inline vec2 roundTransformedCoords(vec2 p) { + return {roundTransformedCoords(p.x), roundTransformedCoords(p.y)}; +} + vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) { const vec2 transformedXy = transform.transform(xy); const vec2 transformedOrigin = transform.transform(0, 0); - return transformedXy - transformedOrigin; + return roundTransformedCoords(transformedXy - transformedOrigin); } const char* inputEventTypeToString(int32_t type) { @@ -548,12 +561,12 @@ int MotionEvent::getSurfaceRotation() const { float MotionEvent::getXCursorPosition() const { vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition()); - return vals.x; + return roundTransformedCoords(vals.x); } float MotionEvent::getYCursorPosition() const { vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition()); - return vals.y; + return roundTransformedCoords(vals.y); } void MotionEvent::setCursorPosition(float x, float y) { @@ -875,7 +888,7 @@ std::string MotionEvent::actionToString(int32_t action) { static inline vec2 calculateTransformedXYUnchecked(uint32_t source, const ui::Transform& transform, const vec2& xy) { return shouldDisregardOffset(source) ? transformWithoutTranslation(transform, xy) - : transform.transform(xy); + : roundTransformedCoords(transform.transform(xy)); } vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& transform, diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 4b3124636b..597b38912b 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -29,6 +29,8 @@ namespace android { // Default display id. static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; +static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION; + class BaseTest : public testing::Test { protected: static constexpr std::array<uint8_t, 32> HMAC = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, @@ -231,95 +233,107 @@ protected: static constexpr float RAW_X_OFFSET = 12; static constexpr float RAW_Y_OFFSET = -41.1; + void SetUp() override; + int32_t mId; ui::Transform mTransform; ui::Transform mRawTransform; + PointerProperties mPointerProperties[2]; + struct Sample { + PointerCoords pointerCoords[2]; + }; + std::array<Sample, 3> mSamples{}; void initializeEventWithHistory(MotionEvent* event); void assertEqualsEventWithHistory(const MotionEvent* event); }; -void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { +void MotionEventTest::SetUp() { mId = InputEvent::nextId(); mTransform.set({X_SCALE, 0, X_OFFSET, 0, Y_SCALE, Y_OFFSET, 0, 0, 1}); mRawTransform.set({RAW_X_SCALE, 0, RAW_X_OFFSET, 0, RAW_Y_SCALE, RAW_Y_OFFSET, 0, 0, 1}); - PointerProperties pointerProperties[2]; - pointerProperties[0].clear(); - pointerProperties[0].id = 1; - pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - pointerProperties[1].clear(); - pointerProperties[1].id = 2; - pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; - - PointerCoords pointerCoords[2]; - pointerCoords[0].clear(); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18); - pointerCoords[1].clear(); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); + mPointerProperties[0].clear(); + mPointerProperties[0].id = 1; + mPointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerProperties[1].clear(); + mPointerProperties[1].id = 2; + mPointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + + mSamples[0].pointerCoords[0].clear(); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17); + mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18); + mSamples[0].pointerCoords[1].clear(); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); + mSamples[0].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); + + mSamples[1].pointerCoords[0].clear(); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117); + mSamples[1].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118); + mSamples[1].pointerCoords[1].clear(); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127); + mSamples[1].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128); + + mSamples[2].pointerCoords[0].clear(); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217); + mSamples[2].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218); + mSamples[2].pointerCoords[1].clear(); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227); + mSamples[2].pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228); +} + +void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { event->initialize(mId, 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC, AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, mTransform, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, mRawTransform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, - pointerProperties, pointerCoords); - - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128); - event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords); - - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217); - pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227); - pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228); - event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords); + mPointerProperties, mSamples[0].pointerCoords); + event->addSample(ARBITRARY_EVENT_TIME + 1, mSamples[1].pointerCoords); + event->addSample(ARBITRARY_EVENT_TIME + 2, mSamples[2].pointerCoords); } void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { @@ -356,51 +370,65 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1)); ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime()); - ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(211, event->getRawPointerCoords(0)->getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(221, event->getRawPointerCoords(1)->getAxisValue(AMOTION_EVENT_AXIS_Y)); - - ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, - event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); - ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, - event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); - ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, - event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); - ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, - event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); - ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); - ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); - - ASSERT_EQ(RAW_X_OFFSET + 10 * RAW_X_SCALE, event->getHistoricalRawX(0, 0)); - ASSERT_EQ(RAW_X_OFFSET + 20 * RAW_X_SCALE, event->getHistoricalRawX(1, 0)); - ASSERT_EQ(RAW_X_OFFSET + 110 * RAW_X_SCALE, event->getHistoricalRawX(0, 1)); - ASSERT_EQ(RAW_X_OFFSET + 120 * RAW_X_SCALE, event->getHistoricalRawX(1, 1)); - ASSERT_EQ(RAW_X_OFFSET + 210 * RAW_X_SCALE, event->getRawX(0)); - ASSERT_EQ(RAW_X_OFFSET + 220 * RAW_X_SCALE, event->getRawX(1)); - - ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, event->getHistoricalRawY(0, 0)); - ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, event->getHistoricalRawY(1, 0)); - ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, event->getHistoricalRawY(0, 1)); - ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, event->getHistoricalRawY(1, 1)); - ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawY(0)); - ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawY(1)); - - ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0)); - ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0)); - ASSERT_EQ(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1)); - ASSERT_EQ(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1)); - ASSERT_EQ(X_OFFSET + 210 * X_SCALE, event->getX(0)); - ASSERT_EQ(X_OFFSET + 220 * X_SCALE, event->getX(1)); - - ASSERT_EQ(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0)); - ASSERT_EQ(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0)); - ASSERT_EQ(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1)); - ASSERT_EQ(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1)); - ASSERT_EQ(Y_OFFSET + 211 * Y_SCALE, event->getY(0)); - ASSERT_EQ(Y_OFFSET + 221 * Y_SCALE, event->getY(1)); + // Ensure the underlying PointerCoords are identical. + for (int sampleIdx = 0; sampleIdx < 3; sampleIdx++) { + for (int pointerIdx = 0; pointerIdx < 2; pointerIdx++) { + ASSERT_EQ(mSamples[sampleIdx].pointerCoords[pointerIdx], + event->getSamplePointerCoords()[sampleIdx * 2 + pointerIdx]); + } + } + + ASSERT_NEAR(11, event->getHistoricalRawPointerCoords(0, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y), + EPSILON); + ASSERT_NEAR(21, event->getHistoricalRawPointerCoords(1, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y), + EPSILON); + ASSERT_NEAR(111, event->getHistoricalRawPointerCoords(0, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y), + EPSILON); + ASSERT_NEAR(121, event->getHistoricalRawPointerCoords(1, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y), + EPSILON); + ASSERT_NEAR(211, event->getRawPointerCoords(0)->getAxisValue(AMOTION_EVENT_AXIS_Y), EPSILON); + ASSERT_NEAR(221, event->getRawPointerCoords(1)->getAxisValue(AMOTION_EVENT_AXIS_Y), EPSILON); + + ASSERT_NEAR(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, + event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0), + EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1), + EPSILON); + + ASSERT_NEAR(RAW_X_OFFSET + 10 * RAW_X_SCALE, event->getHistoricalRawX(0, 0), EPSILON); + ASSERT_NEAR(RAW_X_OFFSET + 20 * RAW_X_SCALE, event->getHistoricalRawX(1, 0), EPSILON); + ASSERT_NEAR(RAW_X_OFFSET + 110 * RAW_X_SCALE, event->getHistoricalRawX(0, 1), EPSILON); + ASSERT_NEAR(RAW_X_OFFSET + 120 * RAW_X_SCALE, event->getHistoricalRawX(1, 1), EPSILON); + ASSERT_NEAR(RAW_X_OFFSET + 210 * RAW_X_SCALE, event->getRawX(0), EPSILON); + ASSERT_NEAR(RAW_X_OFFSET + 220 * RAW_X_SCALE, event->getRawX(1), EPSILON); + + ASSERT_NEAR(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, event->getHistoricalRawY(0, 0), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, event->getHistoricalRawY(1, 0), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, event->getHistoricalRawY(0, 1), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, event->getHistoricalRawY(1, 1), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawY(0), EPSILON); + ASSERT_NEAR(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawY(1), EPSILON); + + ASSERT_NEAR(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0), EPSILON); + ASSERT_NEAR(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0), EPSILON); + ASSERT_NEAR(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1), EPSILON); + ASSERT_NEAR(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1), EPSILON); + ASSERT_NEAR(X_OFFSET + 210 * X_SCALE, event->getX(0), EPSILON); + ASSERT_NEAR(X_OFFSET + 220 * X_SCALE, event->getX(1), EPSILON); + + ASSERT_NEAR(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0), EPSILON); + ASSERT_NEAR(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0), EPSILON); + ASSERT_NEAR(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1), EPSILON); + ASSERT_NEAR(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1), EPSILON); + ASSERT_NEAR(Y_OFFSET + 211 * Y_SCALE, event->getY(0), EPSILON); + ASSERT_NEAR(Y_OFFSET + 221 * Y_SCALE, event->getY(1), EPSILON); ASSERT_EQ(12, event->getHistoricalPressure(0, 0)); ASSERT_EQ(22, event->getHistoricalPressure(1, 0)); @@ -532,10 +560,10 @@ TEST_F(MotionEventTest, Scale) { ASSERT_EQ(X_OFFSET * 2, event.getXOffset()); ASSERT_EQ(Y_OFFSET * 2, event.getYOffset()); - ASSERT_EQ((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0)); - ASSERT_EQ((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0)); - ASSERT_EQ((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0)); - ASSERT_EQ((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0)); + ASSERT_NEAR((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0), EPSILON); + ASSERT_NEAR((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0), EPSILON); + ASSERT_NEAR((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0), EPSILON); + ASSERT_NEAR((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0), EPSILON); ASSERT_EQ(212, event.getPressure(0)); ASSERT_EQ(213, event.getSize(0)); ASSERT_EQ(214 * 2, event.getTouchMajor(0)); @@ -773,18 +801,18 @@ TEST_F(MotionEventTest, AxesAreCorrectlyTransformed) { // The x and y axes should have the window transform applied. const auto newPoint = transform.transform(60, 100); - ASSERT_EQ(newPoint.x, event.getX(0)); - ASSERT_EQ(newPoint.y, event.getY(0)); + ASSERT_NEAR(newPoint.x, event.getX(0), EPSILON); + ASSERT_NEAR(newPoint.y, event.getY(0), EPSILON); // The raw values should have the display transform applied. const auto raw = rawTransform.transform(60, 100); - ASSERT_EQ(raw.x, event.getRawX(0)); - ASSERT_EQ(raw.y, event.getRawY(0)); + ASSERT_NEAR(raw.x, event.getRawX(0), EPSILON); + ASSERT_NEAR(raw.y, event.getRawY(0), EPSILON); // Relative values should have the window transform applied without any translation. const auto rel = transformWithoutTranslation(transform, 42, 96); - ASSERT_EQ(rel.x, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0)); - ASSERT_EQ(rel.y, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0)); + ASSERT_NEAR(rel.x, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), EPSILON); + ASSERT_NEAR(rel.y, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), EPSILON); } TEST_F(MotionEventTest, Initialize_SetsClassification) { @@ -851,4 +879,42 @@ TEST_F(MotionEventTest, SetCursorPosition) { ASSERT_EQ(4, event.getYCursorPosition()); } +TEST_F(MotionEventTest, CoordinatesAreRoundedAppropriately) { + // These are specifically integral values, since we are testing for rounding. + const vec2 EXPECTED{400.f, 700.f}; + + // Pick a transform such that transforming the point with its inverse and bringing that + // back to the original coordinate space results in a non-zero error amount due to the + // nature of floating point arithmetics. This can happen when the display is scaled. + // For example, the 'adb shell wm size' command can be used to set an override for the + // logical display size, which could result in the display being scaled. + constexpr float scale = 720.f / 1080.f; + ui::Transform transform; + transform.set(scale, 0, 0, scale); + ASSERT_NE(EXPECTED, transform.transform(transform.inverse().transform(EXPECTED))); + + // Store the inverse-transformed values in the motion event. + const vec2 rawCoords = transform.inverse().transform(EXPECTED); + PointerCoords pc{}; + pc.setAxisValue(AMOTION_EVENT_AXIS_X, rawCoords.x); + pc.setAxisValue(AMOTION_EVENT_AXIS_Y, rawCoords.y); + PointerProperties pp{}; + MotionEvent event; + event.initialize(InputEvent::nextId(), 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC, + AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, + AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, + MotionClassification::NONE, transform, 2.0f, 2.1f, rawCoords.x, rawCoords.y, + transform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 1, &pp, &pc); + + // When using the getters from the MotionEvent to obtain the coordinates, the transformed + // values should be rounded by an appropriate amount so that they now precisely equal the + // original coordinates. + ASSERT_EQ(EXPECTED.x, event.getX(0)); + ASSERT_EQ(EXPECTED.y, event.getY(0)); + ASSERT_EQ(EXPECTED.x, event.getRawX(0)); + ASSERT_EQ(EXPECTED.y, event.getRawY(0)); + ASSERT_EQ(EXPECTED.x, event.getXCursorPosition()); + ASSERT_EQ(EXPECTED.y, event.getYCursorPosition()); +} + } // namespace android diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 05bc0bcbe8..8393e99d65 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -32,6 +32,8 @@ using android::base::Result; namespace android { +constexpr static float EPSILON = MotionEvent::ROUNDING_PRECISION; + class InputPublisherAndConsumerTest : public testing::Test { protected: std::shared_ptr<InputChannel> mServerChannel, mClientChannel; @@ -233,10 +235,10 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(yOffset, motionEvent->getYOffset()); EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); - EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition()); - EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition()); - EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition()); - EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition()); + EXPECT_NEAR(xCursorPosition, motionEvent->getRawXCursorPosition(), EPSILON); + EXPECT_NEAR(yCursorPosition, motionEvent->getRawYCursorPosition(), EPSILON); + EXPECT_NEAR(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition(), EPSILON); + EXPECT_NEAR(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition(), EPSILON); EXPECT_EQ(rawTransform, motionEvent->getRawTransform()); EXPECT_EQ(downTime, motionEvent->getDownTime()); EXPECT_EQ(eventTime, motionEvent->getEventTime()); @@ -249,10 +251,12 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i)); const auto& pc = pointerCoords[i]; - EXPECT_EQ(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i)); - EXPECT_EQ(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i)); - EXPECT_EQ(pc.getX() * xScale + xOffset, motionEvent->getX(i)); - EXPECT_EQ(pc.getY() * yScale + yOffset, motionEvent->getY(i)); + EXPECT_EQ(pc, motionEvent->getSamplePointerCoords()[i]); + + EXPECT_NEAR(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i), EPSILON); + EXPECT_NEAR(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i), EPSILON); + EXPECT_NEAR(pc.getX() * xScale + xOffset, motionEvent->getX(i), EPSILON); + EXPECT_NEAR(pc.getY() * yScale + yOffset, motionEvent->getY(i), EPSILON); EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i)); EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent->getSize(i)); EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent->getTouchMajor(i)); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bcef62c696..e860e3c532 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -128,10 +128,10 @@ public: const auto& motionEvent = static_cast<const MotionEvent&>(event); EXPECT_EQ(motionEvent.getEventTime(), args.eventTime); EXPECT_EQ(motionEvent.getAction(), args.action); - EXPECT_EQ(motionEvent.getX(0), point.x); - EXPECT_EQ(motionEvent.getY(0), point.y); - EXPECT_EQ(motionEvent.getRawX(0), point.x); - EXPECT_EQ(motionEvent.getRawY(0), point.y); + EXPECT_NEAR(motionEvent.getX(0), point.x, MotionEvent::ROUNDING_PRECISION); + EXPECT_NEAR(motionEvent.getY(0), point.y, MotionEvent::ROUNDING_PRECISION); + EXPECT_NEAR(motionEvent.getRawX(0), point.x, MotionEvent::ROUNDING_PRECISION); + EXPECT_NEAR(motionEvent.getRawY(0), point.y, MotionEvent::ROUNDING_PRECISION); }); } |