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

Commit 3915c1fe authored by Arthur Hung's avatar Arthur Hung
Browse files

Fix drag surface may stuck in multi displays

Check the displayId to prevent the drag state could be reset due to
update input windows of another display or event from another display.

Test: atest inputflinger_tests
Bug: 234405420
Change-Id: I75c7e08594f4dd08b6a0103c2c5a54d8f3e3e09e
parent a4b0d8af
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -2507,7 +2507,7 @@ void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) {
}

void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
    if (!mDragState) {
    if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId) {
        return;
    }

@@ -4765,9 +4765,11 @@ void InputDispatcher::setInputWindowsLocked(

        // If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We
        // could just clear the state here.
        if (mDragState &&
        if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId &&
            std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) ==
                    windowHandles.end()) {
            ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str());
            sendDropWindowCommandLocked(nullptr, 0, 0);
            mDragState.reset();
        }
    }
+52 −0
Original line number Diff line number Diff line
@@ -6407,6 +6407,58 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
    mSecondWindow->consumeMotionMove();
}

TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
    performDrag();

    // Update window of second display.
    sp<FakeWindowHandle> windowInSecondary =
            new FakeWindowHandle(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
    mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});

    // Let second display has a touch state.
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher,
                                MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
                                                   AINPUT_SOURCE_TOUCHSCREEN)
                                        .displayId(SECOND_DISPLAY_ID)
                                        .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER)
                                                         .x(100)
                                                         .y(100))
                                        .build()));
    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN,
                                    SECOND_DISPLAY_ID, 0 /* expectedFlag */);
    // Update window again.
    mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});

    // Move on window.
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
                                ADISPLAY_ID_DEFAULT, {50, 50}))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
    mWindow->consumeDragEvent(false, 50, 50);
    mSecondWindow->assertNoEvents();

    // Move to another window.
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
                                ADISPLAY_ID_DEFAULT, {150, 50}))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
    mWindow->consumeDragEvent(true, 150, 50);
    mSecondWindow->consumeDragEvent(false, 50, 50);

    // drop to another window.
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                             {150, 50}))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
    mFakePolicy->assertDropTargetEquals(mSecondWindow->getToken());
    mWindow->assertNoEvents();
    mSecondWindow->assertNoEvents();
}

class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};

TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {