Loading include/input/Input.h +9 −1 Original line number Diff line number Diff line Loading @@ -181,6 +181,7 @@ static constexpr size_t MAX_POINTERS = 16; */ struct AInputEvent { virtual ~AInputEvent() {} bool operator==(const AInputEvent&) const = default; }; /* Loading Loading @@ -545,6 +546,8 @@ public: static int32_t nextId(); bool operator==(const InputEvent&) const = default; protected: void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac); Loading Loading @@ -598,6 +601,8 @@ public: static const char* actionToString(int32_t action); bool operator==(const KeyEvent&) const = default; protected: int32_t mAction; int32_t mFlags; Loading Loading @@ -917,6 +922,9 @@ public: // The rounding precision for transformed motion events. static constexpr float ROUNDING_PRECISION = 0.001f; bool operator==(const MotionEvent&) const; inline bool operator!=(const MotionEvent& o) const { return !(*this == o); }; protected: int32_t mAction; int32_t mActionButton; Loading libs/input/Input.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -1007,6 +1007,33 @@ PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source, return out; } bool MotionEvent::operator==(const android::MotionEvent& o) const { // We use NaN values to represent invalid cursor positions. Since NaN values are not equal // to themselves according to IEEE 754, we cannot use the default equality operator to compare // MotionEvents. Therefore we define a custom equality operator with special handling for NaNs. // clang-format off return InputEvent::operator==(static_cast<const InputEvent&>(o)) && mAction == o.mAction && mActionButton == o.mActionButton && mFlags == o.mFlags && mEdgeFlags == o.mEdgeFlags && mMetaState == o.mMetaState && mButtonState == o.mButtonState && mClassification == o.mClassification && mTransform == o.mTransform && mXPrecision == o.mXPrecision && mYPrecision == o.mYPrecision && ((std::isnan(mRawXCursorPosition) && std::isnan(o.mRawXCursorPosition)) || mRawXCursorPosition == o.mRawXCursorPosition) && ((std::isnan(mRawYCursorPosition) && std::isnan(o.mRawYCursorPosition)) || mRawYCursorPosition == o.mRawYCursorPosition) && mRawTransform == o.mRawTransform && mDownTime == o.mDownTime && mPointerProperties == o.mPointerProperties && mSampleEventTimes == o.mSampleEventTimes && mSamplePointerCoords == o.mSamplePointerCoords; // clang-format on } std::ostream& operator<<(std::ostream& out, const MotionEvent& event) { out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction()); if (event.getActionButton() != 0) { Loading services/inputflinger/tests/FakeInputTracingBackend.cpp +57 −5 Original line number Diff line number Diff line Loading @@ -37,6 +37,30 @@ inline auto getId(const trace::TracedEvent& v) { return std::visit([](const auto& event) { return event.id; }, v); } MotionEvent toInputEvent( const trace::TracedMotionEvent& e, const trace::InputTracingBackendInterface::WindowDispatchArgs& dispatchArgs, const std::array<uint8_t, 32>& hmac) { MotionEvent traced; traced.initialize(e.id, e.deviceId, e.source, e.displayId, hmac, e.action, e.actionButton, dispatchArgs.resolvedFlags, e.edgeFlags, e.metaState, e.buttonState, e.classification, dispatchArgs.transform, e.xPrecision, e.yPrecision, e.xCursorPosition, e.yCursorPosition, dispatchArgs.rawTransform, e.downTime, e.eventTime, e.pointerProperties.size(), e.pointerProperties.data(), e.pointerCoords.data()); return traced; } KeyEvent toInputEvent(const trace::TracedKeyEvent& e, const trace::InputTracingBackendInterface::WindowDispatchArgs& dispatchArgs, const std::array<uint8_t, 32>& hmac) { KeyEvent traced; traced.initialize(e.id, e.deviceId, e.source, e.displayId, hmac, e.action, dispatchArgs.resolvedFlags, e.keyCode, e.scanCode, e.metaState, e.repeatCount, e.downTime, e.eventTime); return traced; } } // namespace // --- VerifyingTrace --- Loading @@ -55,6 +79,7 @@ void VerifyingTrace::verifyExpectedEventsTraced() { std::unique_lock lock(mLock); base::ScopedLockAssertion assumeLocked(mLock); // Poll for all expected events to be traced, and keep track of the latest poll result. base::Result<void> result; mEventTracedCondition.wait_for(lock, TRACE_TIMEOUT, [&]() REQUIRES(mLock) { for (const auto& [expectedEvent, windowId] : mExpectedEvents) { Loading Loading @@ -101,12 +126,39 @@ base::Result<void> VerifyingTrace::verifyEventTraced(const Event& expectedEvent, }); if (tracedDispatchesIt == mTracedWindowDispatches.end()) { msg << "Expected dispatch of event with ID 0x" << std::hex << expectedEvent.getId() << " to window with ID 0x" << expectedWindowId << " to be traced, but it was not." << "\nExpected event: " << expectedEvent; << " to window with ID 0x" << expectedWindowId << " to be traced, but it was not.\n" << "Expected event: " << expectedEvent; return error(msg); } // Verify that the traced event matches the expected event exactly. return std::visit( [&](const auto& traced) -> base::Result<void> { Event tracedEvent; using T = std::decay_t<decltype(traced)>; if constexpr (std::is_same_v<Event, MotionEvent> && std::is_same_v<T, trace::TracedMotionEvent>) { tracedEvent = toInputEvent(traced, *tracedDispatchesIt, expectedEvent.getHmac()); } else if constexpr (std::is_same_v<Event, KeyEvent> && std::is_same_v<T, trace::TracedKeyEvent>) { tracedEvent = toInputEvent(traced, *tracedDispatchesIt, expectedEvent.getHmac()); } else { msg << "Received the wrong event type!\n" << "Expected event: " << expectedEvent; return error(msg); } const auto result = testing::internal::CmpHelperEQ("expectedEvent", "tracedEvent", expectedEvent, tracedEvent); if (!result) { msg << result.failure_message(); return error(msg); } return {}; }, tracedEventsIt->second); } // --- FakeInputTracingBackend --- Loading @@ -114,7 +166,7 @@ base::Result<void> VerifyingTrace::verifyEventTraced(const Event& expectedEvent, void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) const { { std::scoped_lock lock(mTrace->mLock); mTrace->mTracedEvents.emplace(event.id); mTrace->mTracedEvents.emplace(event.id, event); } mTrace->mEventTracedCondition.notify_all(); } Loading @@ -122,7 +174,7 @@ void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) void FakeInputTracingBackend::traceMotionEvent(const trace::TracedMotionEvent& event) const { { std::scoped_lock lock(mTrace->mLock); mTrace->mTracedEvents.emplace(event.id); mTrace->mTracedEvents.emplace(event.id, event); } mTrace->mEventTracedCondition.notify_all(); } Loading services/inputflinger/tests/FakeInputTracingBackend.h +2 −2 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ #include <condition_variable> #include <memory> #include <mutex> #include <unordered_set> #include <unordered_map> #include <vector> namespace android::inputdispatcher { Loading Loading @@ -58,7 +58,7 @@ public: private: std::mutex mLock; std::condition_variable mEventTracedCondition; std::unordered_set<uint32_t /*eventId*/> mTracedEvents GUARDED_BY(mLock); std::unordered_map<uint32_t /*eventId*/, trace::TracedEvent> mTracedEvents GUARDED_BY(mLock); using WindowDispatchArgs = trace::InputTracingBackendInterface::WindowDispatchArgs; std::vector<WindowDispatchArgs> mTracedWindowDispatches GUARDED_BY(mLock); std::vector<std::pair<std::variant<KeyEvent, MotionEvent>, int32_t /*windowId*/>> Loading Loading
include/input/Input.h +9 −1 Original line number Diff line number Diff line Loading @@ -181,6 +181,7 @@ static constexpr size_t MAX_POINTERS = 16; */ struct AInputEvent { virtual ~AInputEvent() {} bool operator==(const AInputEvent&) const = default; }; /* Loading Loading @@ -545,6 +546,8 @@ public: static int32_t nextId(); bool operator==(const InputEvent&) const = default; protected: void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId, std::array<uint8_t, 32> hmac); Loading Loading @@ -598,6 +601,8 @@ public: static const char* actionToString(int32_t action); bool operator==(const KeyEvent&) const = default; protected: int32_t mAction; int32_t mFlags; Loading Loading @@ -917,6 +922,9 @@ public: // The rounding precision for transformed motion events. static constexpr float ROUNDING_PRECISION = 0.001f; bool operator==(const MotionEvent&) const; inline bool operator!=(const MotionEvent& o) const { return !(*this == o); }; protected: int32_t mAction; int32_t mActionButton; Loading
libs/input/Input.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -1007,6 +1007,33 @@ PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source, return out; } bool MotionEvent::operator==(const android::MotionEvent& o) const { // We use NaN values to represent invalid cursor positions. Since NaN values are not equal // to themselves according to IEEE 754, we cannot use the default equality operator to compare // MotionEvents. Therefore we define a custom equality operator with special handling for NaNs. // clang-format off return InputEvent::operator==(static_cast<const InputEvent&>(o)) && mAction == o.mAction && mActionButton == o.mActionButton && mFlags == o.mFlags && mEdgeFlags == o.mEdgeFlags && mMetaState == o.mMetaState && mButtonState == o.mButtonState && mClassification == o.mClassification && mTransform == o.mTransform && mXPrecision == o.mXPrecision && mYPrecision == o.mYPrecision && ((std::isnan(mRawXCursorPosition) && std::isnan(o.mRawXCursorPosition)) || mRawXCursorPosition == o.mRawXCursorPosition) && ((std::isnan(mRawYCursorPosition) && std::isnan(o.mRawYCursorPosition)) || mRawYCursorPosition == o.mRawYCursorPosition) && mRawTransform == o.mRawTransform && mDownTime == o.mDownTime && mPointerProperties == o.mPointerProperties && mSampleEventTimes == o.mSampleEventTimes && mSamplePointerCoords == o.mSamplePointerCoords; // clang-format on } std::ostream& operator<<(std::ostream& out, const MotionEvent& event) { out << "MotionEvent { action=" << MotionEvent::actionToString(event.getAction()); if (event.getActionButton() != 0) { Loading
services/inputflinger/tests/FakeInputTracingBackend.cpp +57 −5 Original line number Diff line number Diff line Loading @@ -37,6 +37,30 @@ inline auto getId(const trace::TracedEvent& v) { return std::visit([](const auto& event) { return event.id; }, v); } MotionEvent toInputEvent( const trace::TracedMotionEvent& e, const trace::InputTracingBackendInterface::WindowDispatchArgs& dispatchArgs, const std::array<uint8_t, 32>& hmac) { MotionEvent traced; traced.initialize(e.id, e.deviceId, e.source, e.displayId, hmac, e.action, e.actionButton, dispatchArgs.resolvedFlags, e.edgeFlags, e.metaState, e.buttonState, e.classification, dispatchArgs.transform, e.xPrecision, e.yPrecision, e.xCursorPosition, e.yCursorPosition, dispatchArgs.rawTransform, e.downTime, e.eventTime, e.pointerProperties.size(), e.pointerProperties.data(), e.pointerCoords.data()); return traced; } KeyEvent toInputEvent(const trace::TracedKeyEvent& e, const trace::InputTracingBackendInterface::WindowDispatchArgs& dispatchArgs, const std::array<uint8_t, 32>& hmac) { KeyEvent traced; traced.initialize(e.id, e.deviceId, e.source, e.displayId, hmac, e.action, dispatchArgs.resolvedFlags, e.keyCode, e.scanCode, e.metaState, e.repeatCount, e.downTime, e.eventTime); return traced; } } // namespace // --- VerifyingTrace --- Loading @@ -55,6 +79,7 @@ void VerifyingTrace::verifyExpectedEventsTraced() { std::unique_lock lock(mLock); base::ScopedLockAssertion assumeLocked(mLock); // Poll for all expected events to be traced, and keep track of the latest poll result. base::Result<void> result; mEventTracedCondition.wait_for(lock, TRACE_TIMEOUT, [&]() REQUIRES(mLock) { for (const auto& [expectedEvent, windowId] : mExpectedEvents) { Loading Loading @@ -101,12 +126,39 @@ base::Result<void> VerifyingTrace::verifyEventTraced(const Event& expectedEvent, }); if (tracedDispatchesIt == mTracedWindowDispatches.end()) { msg << "Expected dispatch of event with ID 0x" << std::hex << expectedEvent.getId() << " to window with ID 0x" << expectedWindowId << " to be traced, but it was not." << "\nExpected event: " << expectedEvent; << " to window with ID 0x" << expectedWindowId << " to be traced, but it was not.\n" << "Expected event: " << expectedEvent; return error(msg); } // Verify that the traced event matches the expected event exactly. return std::visit( [&](const auto& traced) -> base::Result<void> { Event tracedEvent; using T = std::decay_t<decltype(traced)>; if constexpr (std::is_same_v<Event, MotionEvent> && std::is_same_v<T, trace::TracedMotionEvent>) { tracedEvent = toInputEvent(traced, *tracedDispatchesIt, expectedEvent.getHmac()); } else if constexpr (std::is_same_v<Event, KeyEvent> && std::is_same_v<T, trace::TracedKeyEvent>) { tracedEvent = toInputEvent(traced, *tracedDispatchesIt, expectedEvent.getHmac()); } else { msg << "Received the wrong event type!\n" << "Expected event: " << expectedEvent; return error(msg); } const auto result = testing::internal::CmpHelperEQ("expectedEvent", "tracedEvent", expectedEvent, tracedEvent); if (!result) { msg << result.failure_message(); return error(msg); } return {}; }, tracedEventsIt->second); } // --- FakeInputTracingBackend --- Loading @@ -114,7 +166,7 @@ base::Result<void> VerifyingTrace::verifyEventTraced(const Event& expectedEvent, void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) const { { std::scoped_lock lock(mTrace->mLock); mTrace->mTracedEvents.emplace(event.id); mTrace->mTracedEvents.emplace(event.id, event); } mTrace->mEventTracedCondition.notify_all(); } Loading @@ -122,7 +174,7 @@ void FakeInputTracingBackend::traceKeyEvent(const trace::TracedKeyEvent& event) void FakeInputTracingBackend::traceMotionEvent(const trace::TracedMotionEvent& event) const { { std::scoped_lock lock(mTrace->mLock); mTrace->mTracedEvents.emplace(event.id); mTrace->mTracedEvents.emplace(event.id, event); } mTrace->mEventTracedCondition.notify_all(); } Loading
services/inputflinger/tests/FakeInputTracingBackend.h +2 −2 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ #include <condition_variable> #include <memory> #include <mutex> #include <unordered_set> #include <unordered_map> #include <vector> namespace android::inputdispatcher { Loading Loading @@ -58,7 +58,7 @@ public: private: std::mutex mLock; std::condition_variable mEventTracedCondition; std::unordered_set<uint32_t /*eventId*/> mTracedEvents GUARDED_BY(mLock); std::unordered_map<uint32_t /*eventId*/, trace::TracedEvent> mTracedEvents GUARDED_BY(mLock); using WindowDispatchArgs = trace::InputTracingBackendInterface::WindowDispatchArgs; std::vector<WindowDispatchArgs> mTracedWindowDispatches GUARDED_BY(mLock); std::vector<std::pair<std::variant<KeyEvent, MotionEvent>, int32_t /*windowId*/>> Loading