Merge "Erase touch state if empty"
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 4a0f2ec..b3b4fb1 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -41,6 +41,7 @@
"include-filter": "android.view.cts.input",
"include-filter": "android.view.cts.MotionEventTest",
"include-filter": "android.view.cts.PointerCaptureTest",
+ "include-filter": "android.view.cts.TooltipTest",
"include-filter": "android.view.cts.VerifyInputEventTest"
}
]
@@ -128,6 +129,7 @@
{
"include-filter": "android.view.cts.MotionEventTest",
"include-filter": "android.view.cts.PointerCaptureTest",
+ "include-filter": "android.view.cts.TooltipTest",
"include-filter": "android.view.cts.VerifyInputEventTest"
}
]
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 87a4ff4..eb938c8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1769,15 +1769,16 @@
void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry& entry) {
if (DEBUG_OUTBOUND_EVENT_DETAILS) {
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=%s, displayId=%" PRId32
", policyFlags=0x%x, "
"action=%s, actionButton=0x%x, flags=0x%x, "
"metaState=0x%x, buttonState=0x%x,"
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
- prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId,
- entry.policyFlags, MotionEvent::actionToString(entry.action).c_str(),
- entry.actionButton, entry.flags, entry.metaState, entry.buttonState, entry.edgeFlags,
- entry.xPrecision, entry.yPrecision, entry.downTime);
+ prefix, entry.eventTime, entry.deviceId,
+ inputEventSourceToString(entry.source).c_str(), entry.displayId, entry.policyFlags,
+ MotionEvent::actionToString(entry.action).c_str(), entry.actionButton, entry.flags,
+ entry.metaState, entry.buttonState, entry.edgeFlags, entry.xPrecision,
+ entry.yPrecision, entry.downTime);
for (uint32_t i = 0; i < entry.pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
@@ -2502,6 +2503,10 @@
}
}
+ if (tempTouchState.windows.empty()) {
+ mTouchStatesByDisplay.erase(displayId);
+ }
+
// Update hover state.
mLastHoverWindowHandle = newHoverWindowHandle;
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index ee7da93..114e0bf 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -148,7 +148,8 @@
std::string TouchState::dump() const {
std::string out;
- out += StringPrintf("deviceId=%d, source=0x%08x\n", deviceId, source);
+ out += StringPrintf("deviceId=%d, source=%s\n", deviceId,
+ inputEventSourceToString(source).c_str());
if (!windows.empty()) {
out += " Windows:\n";
for (size_t i = 0; i < windows.size(); i++) {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index aaf50ce..689fe5c 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -22,6 +22,7 @@
#include <android-base/thread_annotations.h>
#include <binder/Binder.h>
#include <fcntl.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <input/Input.h>
#include <linux/input.h>
@@ -43,6 +44,7 @@
namespace android::inputdispatcher {
using namespace ftl::flag_operators;
+using testing::AllOf;
// An arbitrary time value.
static constexpr nsecs_t ARBITRARY_TIME = 1234;
@@ -102,6 +104,28 @@
<< MotionEvent::actionToString(receivedAction);
}
+MATCHER_P(WithMotionAction, action, "MotionEvent with specified action") {
+ bool matches = action == arg.getAction();
+ if (!matches) {
+ *result_listener << "expected action " << MotionEvent::actionToString(action)
+ << ", but got " << MotionEvent::actionToString(arg.getAction());
+ }
+ if (action == AMOTION_EVENT_ACTION_CANCEL) {
+ if (!matches) {
+ *result_listener << "; ";
+ }
+ *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set";
+ matches &= (arg.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ }
+ return matches;
+}
+
+MATCHER_P(WithSource, source, "InputEvent with specified source") {
+ *result_listener << "expected source " << inputEventSourceToString(source) << ", but got "
+ << inputEventSourceToString(arg.getSource());
+ return arg.getSource() == source;
+}
+
// --- FakeInputDispatcherPolicy ---
class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
@@ -1205,6 +1229,12 @@
mInputReceiver->consumeCaptureEvent(hasCapture);
}
+ void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
+ MotionEvent* motionEvent = consumeMotion();
+ ASSERT_NE(nullptr, motionEvent) << "Did not get a motion event";
+ ASSERT_THAT(*motionEvent, matcher);
+ }
+
void consumeEvent(int32_t expectedEventType, int32_t expectedAction,
std::optional<int32_t> expectedDisplayId,
std::optional<int32_t> expectedFlags) {
@@ -2207,6 +2237,48 @@
ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */);
}
+/**
+ * Inject a mouse hover event followed by a tap from touchscreen.
+ * In the current implementation, the tap does not cause a HOVER_EXIT event.
+ */
+TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 100, 100));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // Inject a hover_move from mouse.
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE,
+ ADISPLAY_ID_DEFAULT, {{50, 50}});
+ motionArgs.xCursorPosition = 50;
+ motionArgs.yCursorPosition = 50;
+ mDispatcher->notifyMotion(&motionArgs);
+ ASSERT_NO_FATAL_FAILURE(
+ window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
+ WithSource(AINPUT_SOURCE_MOUSE))));
+ ASSERT_NO_FATAL_FAILURE(
+ window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithSource(AINPUT_SOURCE_MOUSE))));
+
+ // Tap on the window
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {{10, 10}});
+ mDispatcher->notifyMotion(&motionArgs);
+ ASSERT_NO_FATAL_FAILURE(
+ window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
+
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {{10, 10}});
+ mDispatcher->notifyMotion(&motionArgs);
+ ASSERT_NO_FATAL_FAILURE(
+ window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
+ WithSource(AINPUT_SOURCE_TOUCHSCREEN))));
+}
+
TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
index 8721bd8..9db3422 100644
--- a/services/inputflinger/tests/TestInputListenerMatchers.h
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -46,7 +46,8 @@
}
MATCHER_P(WithSource, source, "InputEvent with specified source") {
- *result_listener << "expected source " << source << ", but got " << arg.source;
+ *result_listener << "expected source " << inputEventSourceToString(source) << ", but got "
+ << inputEventSourceToString(arg.source);
return arg.source == source;
}