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

Commit e1e309ac authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

TouchInputMapper: Consume hovering pointers outside physical frame

Similar to how we consume pointers that touch outside the physical
frame, we consume the hovering pointers when all the hovering pointers
are outside the physical frame.

This means hovering over the unmapped area of an external drawing
tablet will no longer produce hover events at the edge of the display.

Bug: 236798672
Test: atest inputflinger_tests
Test: manual with Wacom Intuos S
Change-Id: I6a2deb90311a2c9a98789ccd8318297cb2346208
parent e71e5706
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -1855,6 +1855,27 @@ std::list<NotifyArgs> TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t
        }
    }

    if (!mCurrentRawState.rawPointerData.hoveringIdBits.isEmpty() &&
        mCurrentRawState.rawPointerData.touchingIdBits.isEmpty() &&
        mDeviceMode != DeviceMode::UNSCALED) {
        // We have hovering pointers, and there are no touching pointers.
        bool hoveringPointersInFrame = false;
        auto hoveringIds = mCurrentRawState.rawPointerData.hoveringIdBits;
        while (!hoveringIds.isEmpty()) {
            uint32_t id = hoveringIds.clearFirstMarkedBit();
            const auto& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
            if (isPointInsidePhysicalFrame(pointer.x, pointer.y)) {
                hoveringPointersInFrame = true;
                break;
            }
        }
        if (!hoveringPointersInFrame) {
            // All hovering pointers are outside the physical frame.
            outConsumed = true;
            return out;
        }
    }

    if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() &&
        !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
        // Pointer just went down.  Check for virtual key press or off-screen touches.
@@ -1865,7 +1886,7 @@ std::list<NotifyArgs> TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t
        if (!isPointInsidePhysicalFrame(pointer.x, pointer.y) &&
            mDeviceMode != DeviceMode::UNSCALED) {
            // If exactly one pointer went down, check for virtual key hit.
            // Otherwise we will drop the entire stroke.
            // Otherwise, we will drop the entire stroke.
            if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
                const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
                if (virtualKey) {
+48 −0
Original line number Diff line number Diff line
@@ -6735,6 +6735,54 @@ TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsChangedToTouchNavigation_upda
    ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION, mDevice->getSources());
}
TEST_F(SingleTouchInputMapperTest, HoverEventsOutsidePhysicalFrameAreIgnored) {
    // Initialize the device without setting device source to touch navigation.
    addConfigurationProperty("touch.deviceType", "touchScreen");
    prepareDisplay(ui::ROTATION_0);
    prepareButtons();
    prepareAxes(POSITION);
    mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0);
    // Set a physical frame in the display viewport.
    auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
    viewport->physicalLeft = 0;
    viewport->physicalTop = 0;
    viewport->physicalRight = DISPLAY_WIDTH / 2;
    viewport->physicalBottom = DISPLAY_HEIGHT / 2;
    mFakePolicy->updateViewport(*viewport);
    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
    SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
    // Hovering inside the physical frame produces events.
    processKey(mapper, BTN_TOOL_PEN, 1);
    processMove(mapper, RAW_X_MIN + 1, RAW_Y_MIN + 1);
    processSync(mapper);
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
            WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)));
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
            WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)));
    // Leaving the physical frame ends the hovering gesture.
    processMove(mapper, RAW_X_MAX - 1, RAW_Y_MAX - 1);
    processSync(mapper);
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
            WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)));
    // Moving outside the physical frame does not produce events.
    processMove(mapper, RAW_X_MAX - 2, RAW_Y_MAX - 2);
    processSync(mapper);
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
    // Re-entering the physical frame produces events.
    processMove(mapper, RAW_X_MIN, RAW_Y_MIN);
    processSync(mapper);
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
            WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)));
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
            WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)));
}
// --- TouchDisplayProjectionTest ---
class TouchDisplayProjectionTest : public SingleTouchInputMapperTest {