From 907ae738dae0ff389383d7acb496d939f1e62499 Mon Sep 17 00:00:00 2001 From: Linnan Li Date: Tue, 5 Sep 2023 17:14:21 +0800 Subject: Add POLICY_FLAG_PASS_TO_USER while hovering is active In the following hover event sequence: ENTER->MOVE->EXIT, the policy might not set POLICY_FLAG_PASS_TO_USER after the MOVE event is received. This would cause MOVE and EXIT events to be dropped. This would later cause problems with stream consistency, because the following HOVER_ENTER event would not be expected. So add POLICY_FLAG_PASS_TO_USER to the hover event while hovering is active, even if the policy does not add POLICY_FLAG_PASS_TO_USER. Bug: 299055469 Test: atest inputflinger_tests Change-Id: If99e493a6a645c66a18a97351763f00a37dc1dc0 Signed-off-by: Linnan Li --- .../inputflinger/dispatcher/InputDispatcher.cpp | 3 +- .../inputflinger/tests/InputDispatcher_test.cpp | 63 ++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 341d146249..c2a593556a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4424,7 +4424,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { const auto touchStateIt = mTouchStatesByDisplay.find(args.displayId); if (touchStateIt != mTouchStatesByDisplay.end()) { const TouchState& touchState = touchStateIt->second; - if (touchState.hasTouchingPointers(args.deviceId)) { + if (touchState.hasTouchingPointers(args.deviceId) || + touchState.hasHoveringPointers(args.deviceId)) { policyFlags |= POLICY_FLAG_PASS_TO_USER; } } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 606dd6d14f..2509c60573 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2166,6 +2166,69 @@ TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) { window->assertNoEvents(); } +/** + * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers. + * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not + * interactive, it might stop sending this flag. + * We've already ensured the consistency of the touch event in this case, and we should also ensure + * the consistency of the hover event in this case. + * + * Test procedure: + * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT + * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT + * + * We expect to receive two full streams of hover events. + */ +TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) { + std::shared_ptr application = std::make_shared(); + + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 300, 300)); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); + + // Send hover exit without the default policy flags. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .policyFlags(0) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) + .build()); + + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + + // Send a simple hover event stream, ensure dispatcher not crashed and window can receive + // right event. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); +} + /** * Two windows: a window on the left and a window on the right. * Mouse is hovered from the right window into the left window. -- cgit v1.2.3-59-g8ed1b