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

Commit 6de91ec5 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou Committed by Android (Google) Code Review
Browse files

Merge "Ignore hover events while pointers are already down"

parents e59a9559 2e3e443f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ struct CancelationOptions {
        CANCEL_POINTER_EVENTS = 1,
        CANCEL_NON_POINTER_EVENTS = 2,
        CANCEL_FALLBACK_EVENTS = 3,
        ftl_last = CANCEL_FALLBACK_EVENTS,
    };

    // The criterion to use to determine which events should be canceled.
+5 −4
Original line number Diff line number Diff line
@@ -2185,8 +2185,9 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked(
    const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);

    if (newGesture) {
        bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
        if (switchedDevice && tempTouchState.isDown() && !down && !isHoverAction) {
        // If pointers are already down, let's finish the current gesture and ignore the new events
        // from another device.
        if (switchedDevice && wasDown) {
            ALOGI("Dropping event because a pointer for a different device is already down "
                  "in display %" PRId32,
                  displayId);
@@ -3761,9 +3762,9 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
    }
    if (DEBUG_OUTBOUND_EVENT_DETAILS) {
        ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
              "with reality: %s, mode=%d.",
              "with reality: %s, mode=%s.",
              connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
              options.mode);
              ftl::enum_string(options.mode).c_str());
    }

    std::string reason = std::string("reason=").append(options.reason);
+80 −0
Original line number Diff line number Diff line
@@ -2460,6 +2460,86 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) {
    rightWindow->assertNoEvents();
}

/**
 * Start hovering with a stylus device, and then tap with a touch device. Ensure no crash occurs.
 * While the touch is down, new hover events from the stylus device should be ignored. After the
 * touch is gone, stylus hovering should start working again.
 */
TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) {
    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, 200, 200));

    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});

    const int32_t stylusDeviceId = 5;
    const int32_t touchDeviceId = 4;
    // Start hovering with stylus
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher,
                                MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
                                                   AINPUT_SOURCE_STYLUS)
                                        .deviceId(stylusDeviceId)
                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS)
                                                         .x(50)
                                                         .y(50))
                                        .build()));
    window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));

    // Finger down on the window
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher,
                                MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
                                                   AINPUT_SOURCE_TOUCHSCREEN)
                                        .deviceId(touchDeviceId)
                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER)
                                                         .x(100)
                                                         .y(100))
                                        .build()));
    window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
    window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN));

    // Try to continue hovering with stylus. Since we are already down, injection should fail
    ASSERT_EQ(InputEventInjectionResult::FAILED,
              injectMotionEvent(mDispatcher,
                                MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
                                                   AINPUT_SOURCE_STYLUS)
                                        .deviceId(stylusDeviceId)
                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS)
                                                         .x(50)
                                                         .y(50))
                                        .build()));
    // No event should be sent. This event should be ignored because a pointer from another device
    // is already down.

    // Lift up the finger
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher,
                                MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
                                                   AINPUT_SOURCE_TOUCHSCREEN)
                                        .deviceId(touchDeviceId)
                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER)
                                                         .x(100)
                                                         .y(100))
                                        .build()));
    window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP));

    // Now that the touch is gone, stylus hovering should start working again
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher,
                                MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
                                                   AINPUT_SOURCE_STYLUS)
                                        .deviceId(stylusDeviceId)
                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS)
                                                         .x(50)
                                                         .y(50))
                                        .build()));
    window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
    // No more events
    window->assertNoEvents();
}

/**
 * On the display, have a single window, and also an area where there's no window.
 * First pointer touches the "no window" area of the screen. Second pointer touches the window.