Call pilfer pointers when second pointer goes down during D&D
We added new functionality to pilferPointers API in ag/18234604.
Using it we can extend the functionality of drag and drop to
allow user to interact with the UI while using 1 pointer/finger
to drag. Pilfering pointers allows gesture monitors to restart
gesture detection with new pointers that down.
Avoid pilfering right after transferTouch on D&D to prevent
security bug: Apps can misuse startDragAndDrop() API to keep
pilfering pointers for gesture monitors and user can get stuck
in an app. Instead we will pilfer when a second pointer goes down
indicating user want to interact while using D&D.
DD: go/global_drag_and_drop
Bug: 220109830
Test: atest inputflinger_tests
Change-Id: I956f040ff307021bb2f74a06228c6addb90e2168
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0c0f9f8..8af7cc3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -6094,6 +6094,7 @@
sp<FakeWindowHandle> mWindow;
sp<FakeWindowHandle> mSecondWindow;
sp<FakeWindowHandle> mDragWindow;
+ sp<FakeWindowHandle> mSpyWindow;
void SetUp() override {
InputDispatcherTest::SetUp();
@@ -6104,8 +6105,13 @@
mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFrame(Rect(100, 0, 200, 100));
+ mSpyWindow = new FakeWindowHandle(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
+ mSpyWindow->setSpy(true);
+ mSpyWindow->setTrustedOverlay(true);
+ mSpyWindow->setFrame(Rect(0, 0, 200, 100));
+
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mSpyWindow, mWindow, mSecondWindow}}});
}
void injectDown() {
@@ -6116,6 +6122,8 @@
// Window should receive motion event.
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ // Spy window should also receive motion event
+ mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
}
// Start performing drag, we will create a drag window and transfer touch to it.
@@ -6128,8 +6136,9 @@
// The drag window covers the entire display
mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
+ mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
mDispatcher->setInputWindows(
- {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
+ {{ADISPLAY_ID_DEFAULT, {mDragWindow, mSpyWindow, mWindow, mSecondWindow}}});
// Transfer touch focus to the drag window
bool transferred =
@@ -6207,6 +6216,30 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
+ performDrag();
+
+ // No cancel event after drag start
+ mSpyWindow->assertNoEvents();
+
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(60).y(60))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Receives cancel for first pointer after next pointer down
+ mSpyWindow->consumeMotionCancel();
+ mSpyWindow->consumeMotionDown();
+
+ mSpyWindow->assertNoEvents();
+}
+
TEST_F(InputDispatcherDragTests, DragAndDrop) {
performDrag();