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

Commit a512a53e authored by Linnan Li's avatar Linnan Li
Browse files

Check the DeviceId for generating DragEvent



After introducing multi-device event stream handling in the Dispatcher,
the drag-and-drop logic was not compatible, leading to unexpected
crashes. This is being fixed here.

Bug: 372165513
Test: atest inputflinger_tests
Flag: EXEMPT bugfix

Change-Id: If5dee9023821a386265651bfdbe9c25d04cd5136
Signed-off-by: default avatarLinnan Li <lilinnan@xiaomi.corp-partner.google.com>
parent a75d99da
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once

#include <gui/WindowInfo.h>
#include <input/Input.h>
#include <utils/StrongPointer.h>
#include <string>

@@ -25,8 +26,9 @@ namespace android {
namespace inputdispatcher {

struct DragState {
    DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t pointerId)
          : dragWindow(windowHandle), pointerId(pointerId) {}
    DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, DeviceId deviceId,
              int32_t pointerId)
          : dragWindow(windowHandle), deviceId(deviceId), pointerId(pointerId) {}
    void dump(std::string& dump, const char* prefix = "");

    // The window being dragged.
@@ -37,6 +39,8 @@ struct DragState {
    bool isStartDrag = false;
    // Indicate if the stylus button is down at the start of the drag.
    bool isStylusButtonDownAtStart = false;
    // Indicate which device started this drag and drop.
    const DeviceId deviceId;
    // Indicate which pointer id is tracked by the drag and drop.
    const int32_t pointerId;
};
+3 −2
Original line number Diff line number Diff line
@@ -2870,7 +2870,8 @@ void InputDispatcher::finishDragAndDrop(ui::LogicalDisplayId displayId, float x,
}

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

@@ -5758,7 +5759,7 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s
            }
            // Track the pointer id for drag window and generate the drag state.
            const size_t id = pointers.begin()->id;
            mDragState = std::make_unique<DragState>(toWindowHandle, id);
            mDragState = std::make_unique<DragState>(toWindowHandle, deviceId, id);
        }

        // Synthesize cancel for old window and down for new window.
+81 −0
Original line number Diff line number Diff line
@@ -12192,6 +12192,87 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) {
            << "Drag and drop should not work with a hovering pointer";
}
/**
 * Two devices, we use the second pointer of Device A to start the drag, during the drag process, if
 * we perform a click using Device B, the dispatcher should work well.
 */
TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouchAndMultiDevice) {
    const DeviceId deviceA = 1;
    const DeviceId deviceB = 2;
    // First down on second window with deviceA.
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                      .deviceId(deviceA)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
                                      .build());
    mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA),
                                            WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
    // Second down on first window with deviceA
    mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                      .deviceId(deviceA)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
                                      .pointer(PointerBuilder(1, ToolType::FINGER).x(50).y(50))
                                      .build());
    mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA),
                                      WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
    mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
                                            WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
    // Perform drag and drop from first window.
    ASSERT_TRUE(startDrag(/*sendDown=*/false));
    // Click first window with device B, we should ensure dispatcher work well.
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
                                      .deviceId(deviceB)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                      .build());
    mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB),
                                      WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
                                      .deviceId(deviceB)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                      .build());
    mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB),
                                      WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
    // Move with device A.
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
                                      .deviceId(deviceA)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
                                      .pointer(PointerBuilder(1, ToolType::FINGER).x(51).y(51))
                                      .build());
    mDragWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
                                          WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                                          WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
    mWindow->consumeDragEvent(false, 51, 51);
    mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
                                            WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
    // Releasing the drag pointer should cause drop.
    mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
                                      .deviceId(deviceA)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
                                      .pointer(PointerBuilder(1, ToolType::FINGER).x(51).y(51))
                                      .build());
    mDragWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA),
                                          WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                                          WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
    mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
    mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
                                            WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
    // Release all pointers.
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
                                      .deviceId(deviceA)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
                                      .build());
    mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA),
                                            WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
    mWindow->assertNoEvents();
}
class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {