Merge "Fix drag and drop access wrong pointer id"
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4516558..23c9965 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2207,10 +2207,7 @@
// Update the temporary touch state.
BitSet32 pointerIds;
- if (isSplit) {
- uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
- pointerIds.markBit(pointerId);
- }
+ pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds,
entry.eventTime);
@@ -2297,9 +2294,7 @@
}
BitSet32 pointerIds;
- if (isSplit) {
- pointerIds.markBit(entry.pointerProperties[0].id);
- }
+ pointerIds.markBit(entry.pointerProperties[0].id);
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds,
entry.eventTime);
}
@@ -2477,21 +2472,28 @@
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
// One pointer went up.
- if (isSplit) {
- int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
+ int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
- for (size_t i = 0; i < tempTouchState.windows.size();) {
- TouchedWindow& touchedWindow = tempTouchState.windows[i];
- if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
- touchedWindow.pointerIds.clearBit(pointerId);
- if (touchedWindow.pointerIds.isEmpty()) {
- tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
- continue;
- }
- }
- i += 1;
+ for (size_t i = 0; i < tempTouchState.windows.size();) {
+ TouchedWindow& touchedWindow = tempTouchState.windows[i];
+ touchedWindow.pointerIds.clearBit(pointerId);
+ if (touchedWindow.pointerIds.isEmpty()) {
+ tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
+ continue;
}
+ i += 1;
+ }
+ } else if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+ // If no split, we suppose all touched windows should receive pointer down.
+ const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ for (size_t i = 0; i < tempTouchState.windows.size(); i++) {
+ TouchedWindow& touchedWindow = tempTouchState.windows[i];
+ // Ignore drag window for it should just track one pointer.
+ if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
+ continue;
+ }
+ touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
}
}
@@ -5121,14 +5123,13 @@
// Store the dragging window.
if (isDragDrop) {
- if (pointerIds.count() > 1) {
- ALOGW("The drag and drop cannot be started when there is more than 1 pointer on the"
- " window.");
+ if (pointerIds.count() != 1) {
+ ALOGW("The drag and drop cannot be started when there is no pointer or more than 1"
+ " pointer on the window.");
return false;
}
- // If the window didn't not support split or the source is mouse, the pointerIds count
- // would be 0, so we have to track the pointer 0.
- const int32_t id = pointerIds.count() == 0 ? 0 : pointerIds.firstMarkedBit();
+ // Track the pointer id for drag window and generate the drag state.
+ const int32_t id = pointerIds.firstMarkedBit();
mDragState = std::make_unique<DragState>(toWindowHandle, id);
}
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index d39113b..2df97d9 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -43,8 +43,8 @@
}
void InputTarget::addPointers(BitSet32 newPointerIds, const ui::Transform& transform) {
- // The pointerIds can be empty, but still a valid InputTarget. This can happen for Monitors
- // and non splittable windows since we will just use all the pointers from the input event.
+ // The pointerIds can be empty, but still a valid InputTarget. This can happen when there is no
+ // valid pointer property from the input event.
if (newPointerIds.isEmpty()) {
setDefaultPointerTransform(transform);
return;
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 0962d0c..a7839db 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -29,7 +29,7 @@
struct TouchedWindow {
sp<gui::WindowInfoHandle> windowHandle;
int32_t targetFlags;
- BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
+ BitSet32 pointerIds;
bool isPilferingPointers = false;
// Time at which the first action down occurred on this window.
// NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE scenario.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 8a2dea5..b2148ef 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -6173,6 +6173,8 @@
sp<FakeWindowHandle> mSecondWindow;
sp<FakeWindowHandle> mDragWindow;
sp<FakeWindowHandle> mSpyWindow;
+ // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
+ static constexpr int32_t MOUSE_POINTER_ID = 1;
void SetUp() override {
InputDispatcherTest::SetUp();
@@ -6192,11 +6194,41 @@
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mSpyWindow, mWindow, mSecondWindow}}});
}
- void injectDown() {
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {50, 50}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
+ switch (fromSource) {
+ case AINPUT_SOURCE_TOUCHSCREEN:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ break;
+ case AINPUT_SOURCE_STYLUS:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(
+ mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_STYLUS)
+ .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS)
+ .x(50)
+ .y(50))
+ .build()));
+ break;
+ case AINPUT_SOURCE_MOUSE:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(
+ mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(50)
+ .y(50))
+ .build()));
+ break;
+ default:
+ FAIL() << "Source " << fromSource << " doesn't support drag and drop";
+ }
// Window should receive motion event.
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
@@ -6207,9 +6239,9 @@
// Start performing drag, we will create a drag window and transfer touch to it.
// @param sendDown : if true, send a motion down on first window before perform drag and drop.
// Returns true on success.
- bool performDrag(bool sendDown = true) {
+ bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
if (sendDown) {
- injectDown();
+ injectDown(fromSource);
}
// The drag window covers the entire display
@@ -6228,36 +6260,10 @@
}
return transferred;
}
-
- // Start performing drag, we will create a drag window and transfer touch to it.
- void performStylusDrag() {
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher,
- MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
- AINPUT_SOURCE_STYLUS)
- .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
- .pointer(PointerBuilder(0,
- AMOTION_EVENT_TOOL_TYPE_STYLUS)
- .x(50)
- .y(50))
- .build()));
- mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
-
- // The drag window covers the entire display
- mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
- mDispatcher->setInputWindows(
- {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
-
- // Transfer touch focus to the drag window
- mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
- true /* isDragDrop */);
- mWindow->consumeMotionCancel();
- mDragWindow->consumeMotionDown();
- }
};
TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
- performDrag();
+ startDrag();
// Move on window.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6295,7 +6301,7 @@
}
TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
- performDrag();
+ startDrag();
// No cancel event after drag start
mSpyWindow->assertNoEvents();
@@ -6319,7 +6325,7 @@
}
TEST_F(InputDispatcherDragTests, DragAndDrop) {
- performDrag();
+ startDrag();
// Move on window.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6351,7 +6357,7 @@
}
TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
- performStylusDrag();
+ startDrag(true, AINPUT_SOURCE_STYLUS);
// Move on window and keep button pressed.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6398,7 +6404,7 @@
}
TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
- performDrag();
+ startDrag();
// Set second window invisible.
mSecondWindow->setVisible(false);
@@ -6434,6 +6440,9 @@
}
TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
+ // Ensure window could track pointerIds if it didn't support split touch.
+ mWindow->setPreventSplitting(true);
+
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
{50, 50}))
@@ -6454,7 +6463,7 @@
mWindow->consumeMotionPointerDown(1 /* pointerIndex */);
// Should not perform drag and drop when window has multi fingers.
- ASSERT_FALSE(performDrag(false));
+ ASSERT_FALSE(startDrag(false));
}
TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
@@ -6482,7 +6491,7 @@
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
// Perform drag and drop from first window.
- ASSERT_TRUE(performDrag(false));
+ ASSERT_TRUE(startDrag(false));
// Move on window.
const MotionEvent secondFingerMoveEvent =
@@ -6517,7 +6526,7 @@
}
TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
- performDrag();
+ startDrag();
// Update window of second display.
sp<FakeWindowHandle> windowInSecondary =
@@ -6568,6 +6577,55 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
+ startDrag(true, AINPUT_SOURCE_MOUSE);
+ // Move on window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(50)
+ .y(50))
+ .build()))
+ << "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,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(150)
+ .y(50))
+ .build()))
+ << "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,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
+ .buttonState(0)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(150)
+ .y(50))
+ .build()))
+ << "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) {