summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Siarhei Vishniakou <svv@google.com> 2024-12-27 16:59:46 -0800
committer Siarhei Vishniakou <svv@google.com> 2025-01-06 17:38:56 -0800
commit2b5d249b08efd4fbd9e6c28362f33b11a963780b (patch)
tree3348033bac909129e88f4770a125a3b3036d1537
parenta5bbaad8cb105fa87553c50f97659992db52a780 (diff)
Remove non-split touch from input code
The behaviour was changed to permanently split since 24Q4. Therefore, all of the existing complexity around supporting non-split can now be removed. Bug: 239934827 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Flag: NONE removing flag Change-Id: I8ca23d502a4c23de2dfafbd7653318b8909912ce
-rw-r--r--libs/gui/WindowInfo.cpp4
-rw-r--r--libs/gui/include/gui/WindowInfo.h2
-rw-r--r--libs/input/android/os/InputConfig.aidl13
-rw-r--r--libs/input/input_flags.aconfig4
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp111
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h4
-rw-r--r--services/inputflinger/tests/FakeWindows.h4
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp208
-rw-r--r--services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp1
9 files changed, 103 insertions, 248 deletions
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 82d2554340..e1a7ac9b18 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -73,10 +73,6 @@ void WindowInfo::addTouchableRegion(const Rect& region) {
touchableRegion.orSelf(region);
}
-bool WindowInfo::supportsSplitTouch() const {
- return !inputConfig.test(InputConfig::PREVENT_SPLITTING);
-}
-
bool WindowInfo::isSpy() const {
return inputConfig.test(InputConfig::SPY);
}
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index eb3be5588a..f7e6084eef 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -150,8 +150,6 @@ struct WindowInfo : public Parcelable {
static_cast<uint32_t>(os::InputConfig::NOT_FOCUSABLE),
NOT_TOUCHABLE =
static_cast<uint32_t>(os::InputConfig::NOT_TOUCHABLE),
- PREVENT_SPLITTING =
- static_cast<uint32_t>(os::InputConfig::PREVENT_SPLITTING),
DUPLICATE_TOUCH_TO_WALLPAPER =
static_cast<uint32_t>(os::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER),
IS_WALLPAPER =
diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl
index da62e03821..e5f7b56561 100644
--- a/libs/input/android/os/InputConfig.aidl
+++ b/libs/input/android/os/InputConfig.aidl
@@ -57,16 +57,9 @@ enum InputConfig {
NOT_TOUCHABLE = 1 << 3,
/**
- * Indicates that this window will not accept a touch event that is split between
- * more than one window. When set:
- * - If this window receives a DOWN event with the first pointer, all successive
- * pointers that go down, regardless of their location on the screen, will be
- * directed to this window;
- * - If the DOWN event lands outside the touchable bounds of this window, no
- * successive pointers that go down, regardless of their location on the screen,
- * will be directed to this window.
- */
- PREVENT_SPLITTING = 1 << 4,
+ * This flag is now deprecated and should not be used.
+ */
+ DEPRECATED_PREVENT_SPLITTING = 1 << 4,
/**
* Indicates that this window shows the wallpaper behind it, so all touch events
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 6cdd249b9e..feff096720 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -37,9 +37,9 @@ flag {
}
flag {
- name: "split_all_touches"
+ name: "deprecate_split_touch_apis"
namespace: "input"
- description: "Set FLAG_SPLIT_TOUCHES to true for all windows, regardless of what they specify. This is essentially deprecating this flag by forcefully enabling the split functionality"
+ description: "Deprecate all public APIs related to split touch because now all windows behave as if split touch is permanently enabled and there's no way for a window to disable split touch."
bug: "239934827"
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 0b1e849bc7..ee31f1e308 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -788,38 +788,14 @@ void filterUntrustedTargets(TouchState& touchState, std::vector<InputTarget>& ta
});
}
-/**
- * In general, touch should be always split between windows. Some exceptions:
- * 1. Don't split touch if all of the below is true:
- * (a) we have an active pointer down *and*
- * (b) a new pointer is going down that's from the same device *and*
- * (c) the window that's receiving the current pointer does not support split touch.
- * 2. Don't split mouse events
- */
-bool shouldSplitTouch(const TouchState& touchState, const MotionEntry& entry) {
- if (isFromSource(entry.source, AINPUT_SOURCE_MOUSE)) {
- // We should never split mouse events
- return false;
- }
- for (const TouchedWindow& touchedWindow : touchState.windows) {
- if (touchedWindow.windowHandle->getInfo()->isSpy()) {
- // Spy windows should not affect whether or not touch is split.
- continue;
- }
- if (touchedWindow.windowHandle->getInfo()->supportsSplitTouch()) {
- continue;
- }
- if (touchedWindow.windowHandle->getInfo()->inputConfig.test(
- gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
- // Wallpaper window should not affect whether or not touch is split
- continue;
- }
-
- if (touchedWindow.hasTouchingPointers(entry.deviceId)) {
- return false;
- }
- }
- return true;
+bool shouldSplitTouch(int32_t source) {
+ // We should never split mouse events. This is because the events that are produced by touchpad
+ // are sent to InputDispatcher as two fingers (for example, pinch zoom), but they need to be
+ // dispatched to the same window. In those cases, the behaviour is also slightly different from
+ // default because the events should be sent to the cursor position rather than the x,y values
+ // of each of the fingers.
+ // The "normal" (uncaptured) events produced by touchpad and by mouse have SOURCE_MOUSE.
+ return !isFromSource(source, AINPUT_SOURCE_MOUSE);
}
/**
@@ -1528,20 +1504,8 @@ std::vector<sp<WindowInfoHandle>> InputDispatcher::DispatcherWindowInfo::findTou
const WindowInfo& info = *windowHandle->getInfo();
if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus,
getDisplayTransform(displayId))) {
- // Generally, we would skip any pointer that's outside of the window. However, if the
- // spy prevents splitting, and already has some of the pointers from this device, then
- // it should get more pointers from the same device, even if they are outside of that
- // window
- if (info.supportsSplitTouch()) {
- continue;
- }
-
- // We know that split touch is not supported. Skip this window only if it doesn't have
- // any touching pointers for this device already.
- if (!windowHasTouchingPointers(windowHandle, deviceId, touchStatesByDisplay)) {
- continue;
- }
- // If it already has pointers down for this device, then give it this pointer, too.
+ // Skip if the pointer is outside of the window.
+ continue;
}
if (!info.isSpy()) {
// The first touched non-spy window was found, so return the spy windows touched so far.
@@ -2448,7 +2412,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio
tempTouchState = *oldState;
}
- bool isSplit = shouldSplitTouch(tempTouchState, entry);
+ bool isSplit = shouldSplitTouch(entry.source);
const bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE ||
maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
@@ -2501,17 +2465,6 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio
LOG_IF(INFO, newTouchedWindowHandle == nullptr)
<< "No new touched window at (" << std::format("{:.1f}, {:.1f}", x, y)
<< ") in display " << displayId;
- // Handle the case where we did not find a window.
- if (!input_flags::split_all_touches()) {
- // If we are force splitting all touches, then touches outside of the window should
- // be dropped, even if this device already has pointers down in another window.
- if (newTouchedWindowHandle == nullptr) {
- // Try to assign the pointer to the first foreground window we find, if there is
- // one.
- newTouchedWindowHandle =
- tempTouchState.getFirstForegroundWindowHandle(entry.deviceId);
- }
- }
// Verify targeted injection.
if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
@@ -2519,24 +2472,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio
return injectionError(InputEventInjectionResult::TARGET_MISMATCH);
}
- // Figure out whether splitting will be allowed for this window.
- if (newTouchedWindowHandle != nullptr) {
- if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
- // New window supports splitting, but we should never split mouse events.
- isSplit = !isFromMouse;
- } else if (isSplit) {
- // New window does not support splitting but we have already split events.
- // Ignore the new window.
- LOG(INFO) << "Skipping " << newTouchedWindowHandle->getName()
- << " because it doesn't support split touch";
- newTouchedWindowHandle = nullptr;
- }
- } else {
- // No window is touched, so set split to true. This will allow the next pointer down to
- // be delivered to a new window which supports split touch. Pointers from a mouse device
- // should never be split.
- isSplit = !isFromMouse;
- }
+ isSplit = !isFromMouse;
std::vector<sp<WindowInfoHandle>> newTouchedWindows =
mWindowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId,
@@ -2711,9 +2647,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio
targets);
// Make a slippery entrance into the new window.
- if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
- isSplit = !isFromMouse;
- }
+ isSplit = !isFromMouse;
ftl::Flags<InputTarget::Flags> targetFlags;
if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) {
@@ -5835,18 +5769,6 @@ InputDispatcher::findTouchStateWindowAndDisplay(
const_cast<TouchedWindow*>(constTouchedWindow), displayId);
}
-bool InputDispatcher::windowHasTouchingPointers(
- const sp<WindowInfoHandle>& windowHandle, DeviceId deviceId,
- const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) {
- const auto& [touchState, touchedWindow, _] =
- findTouchStateWindowAndDisplay(windowHandle->getToken(), touchStatesByDisplay);
- if (touchState == nullptr) {
- // No touching pointers at all
- return false;
- }
- return touchState->hasTouchingPointers(deviceId);
-}
-
bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
bool isDragDrop) {
if (fromToken == toToken) {
@@ -7168,13 +7090,6 @@ void InputDispatcher::onWindowInfosChanged(const gui::WindowInfosUpdate& update)
for (const auto& info : update.windowInfos) {
handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
handlesPerDisplay[info.displayId].push_back(sp<WindowInfoHandle>::make(info));
- if (input_flags::split_all_touches()) {
- handlesPerDisplay[info.displayId]
- .back()
- ->editInfo()
- ->setInputConfig(android::gui::WindowInfo::InputConfig::PREVENT_SPLITTING,
- false);
- }
}
{ // acquire lock
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index fd550dd396..a88e4a3787 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -734,10 +734,6 @@ private:
const sp<IBinder>& token,
const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay);
- static bool windowHasTouchingPointers(
- const sp<android::gui::WindowInfoHandle>& windowHandle, DeviceId deviceId,
- const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay);
-
// Statistics gathering.
nsecs_t mLastStatisticPushTime = 0;
std::unique_ptr<InputEventTimelineProcessor> mInputEventTimelineProcessor GUARDED_BY(mLock);
diff --git a/services/inputflinger/tests/FakeWindows.h b/services/inputflinger/tests/FakeWindows.h
index 3a3238a6ad..54dc25aaa0 100644
--- a/services/inputflinger/tests/FakeWindows.h
+++ b/services/inputflinger/tests/FakeWindows.h
@@ -144,10 +144,6 @@ public:
mInfo.setInputConfig(InputConfig::PAUSE_DISPATCHING, paused);
}
- inline void setPreventSplitting(bool preventSplitting) {
- mInfo.setInputConfig(InputConfig::PREVENT_SPLITTING, preventSplitting);
- }
-
inline void setSlippery(bool slippery) {
mInfo.setInputConfig(InputConfig::SLIPPERY, slippery);
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index fb67cebf29..c160ca6aa8 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1215,22 +1215,17 @@ TEST_F(InputDispatcherTest, MultiDeviceTouchTransferWithWallpaperWindows) {
WithFlags(EXPECTED_WALLPAPER_FLAGS | AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
}
-class ShouldSplitTouchFixture : public InputDispatcherTest,
- public ::testing::WithParamInterface<bool> {};
-INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
- ::testing::Values(true, false));
/**
* A single window that receives touch (on top), and a wallpaper window underneath it.
* The top window gets a multitouch gesture.
* Ensure that wallpaper gets the same gesture.
*/
-TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
+TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> foregroundWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground",
ui::LogicalDisplayId::DEFAULT);
foregroundWindow->setDupTouchToWallpaper(true);
- foregroundWindow->setPreventSplitting(GetParam());
sp<FakeWindowHandle> wallpaperWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper",
@@ -4260,17 +4255,15 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
}
/**
- * When events are not split, the downTime should be adjusted such that the downTime corresponds
+ * When events are split, the downTime should be adjusted such that the downTime corresponds
* to the event time of the first ACTION_DOWN. If a new window appears, it should not affect
- * the event routing because the first window prevents splitting.
+ * the event routing unless pointers are delivered to the new window.
*/
TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) {
- SCOPED_FLAG_OVERRIDE(split_all_touches, false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window1 =
sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
window1->setTouchableRegion(Region{{0, 0, 100, 100}});
- window1->setPreventSplitting(true);
sp<FakeWindowHandle> window2 =
sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
@@ -4290,13 +4283,18 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) {
// Second window is added
mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
- // Now touch down on the window with another pointer
- mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
- .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
- .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
- .downTime(downArgs.downTime)
- .build());
- window1->consumeMotionPointerDown(1, AllOf(WithDownTime(downArgs.downTime)));
+ // Now touch down on the new window with another pointer
+ NotifyMotionArgs pointerDownArgs =
+ MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
+ .downTime(downArgs.downTime)
+ .build();
+ mDispatcher->notifyMotion(pointerDownArgs);
+ window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerCount(1),
+ WithDownTime(downArgs.downTime)));
+ window2->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(pointerDownArgs.eventTime)));
// Finish the gesture
mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
@@ -4304,11 +4302,16 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) {
.pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
.downTime(downArgs.downTime)
.build());
+ window1->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_MOVE), WithDownTime(downArgs.downTime)));
+ window2->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_UP), WithDownTime(pointerDownArgs.eventTime)));
+
mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
.pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
.downTime(downArgs.downTime)
.build());
- window1->consumeMotionPointerUp(1, AllOf(WithDownTime(downArgs.downTime)));
+
window1->consumeMotionEvent(
AllOf(WithMotionAction(ACTION_UP), WithDownTime(downArgs.downTime)));
window2->assertNoEvents();
@@ -4317,13 +4320,12 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) {
/**
* When splitting touch events, the downTime should be adjusted such that the downTime corresponds
* to the event time of the first ACTION_DOWN sent to the new window.
- * If a new window that does not support split appears on the screen and gets touched with the
- * second finger, it should not get any events because it doesn't want split touches. At the same
- * time, the first window should not get the pointer_down event because it supports split touches
- * (and the touch occurred outside of the bounds of window1).
+ * If a new window appears on the screen and gets touched with the
+ * second finger, it should get the new event. At the same
+ * time, the first window should not get the pointer_down event because
+ * the touch occurred outside of its bounds.
*/
-TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow) {
- SCOPED_FLAG_OVERRIDE(split_all_touches, false);
+TEST_F(InputDispatcherTest, SplitTouchesWhenWindowIsAdded) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window1 =
sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
@@ -4345,16 +4347,16 @@ TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow)
AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(downArgs.downTime)));
// Second window is added
- window2->setPreventSplitting(true);
mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0});
- // Now touch down on the window with another pointer
+ // Now touch down on the new window with another pointer
mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
.pointer(PointerBuilder(1, ToolType::FINGER).x(150).y(50))
.downTime(downArgs.downTime)
.build());
- // Event is dropped because window2 doesn't support split touch, and window1 does.
+ window1->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerCount(1)));
+ window2->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
// Complete the gesture
mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
@@ -4365,6 +4367,8 @@ TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow)
// A redundant MOVE event is generated that doesn't carry any new information
window1->consumeMotionEvent(
AllOf(WithMotionAction(ACTION_MOVE), WithDownTime(downArgs.downTime)));
+ window2->consumeMotionEvent(WithMotionAction(ACTION_UP));
+
mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
.pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
.downTime(downArgs.downTime)
@@ -4584,22 +4588,20 @@ TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
* A spy window sits above a window with NO_INPUT_CHANNEL. Ensure that the spy receives events even
* though the window underneath should not get any events.
*/
-TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowSinglePointer) {
+TEST_F(InputDispatcherTest, SpyAboveNoInputChannelWindowSinglePointer) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
ui::LogicalDisplayId::DEFAULT);
spyWindow->setFrame(Rect(0, 0, 100, 100));
spyWindow->setTrustedOverlay(true);
- spyWindow->setPreventSplitting(true);
spyWindow->setSpy(true);
- // Another window below spy that has both NO_INPUT_CHANNEL and PREVENT_SPLITTING
+ // Another window below spy that has NO_INPUT_CHANNEL
sp<FakeWindowHandle> inputSinkWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
ui::LogicalDisplayId::DEFAULT);
inputSinkWindow->setFrame(Rect(0, 0, 100, 100));
inputSinkWindow->setTrustedOverlay(true);
- inputSinkWindow->setPreventSplitting(true);
inputSinkWindow->setNoInputChannel(true);
mDispatcher->onWindowInfosChanged(
@@ -4624,22 +4626,20 @@ TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowSinglePoint
* though the window underneath should not get any events.
* Same test as above, but with two pointers touching instead of one.
*/
-TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowTwoPointers) {
+TEST_F(InputDispatcherTest, SpyAboveNoInputChannelWindowTwoPointers) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
ui::LogicalDisplayId::DEFAULT);
spyWindow->setFrame(Rect(0, 0, 100, 100));
spyWindow->setTrustedOverlay(true);
- spyWindow->setPreventSplitting(true);
spyWindow->setSpy(true);
- // Another window below spy that would have both NO_INPUT_CHANNEL and PREVENT_SPLITTING
+ // Another window below spy that would have NO_INPUT_CHANNEL
sp<FakeWindowHandle> inputSinkWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
ui::LogicalDisplayId::DEFAULT);
inputSinkWindow->setFrame(Rect(0, 0, 100, 100));
inputSinkWindow->setTrustedOverlay(true);
- inputSinkWindow->setPreventSplitting(true);
inputSinkWindow->setNoInputChannel(true);
mDispatcher->onWindowInfosChanged(
@@ -4671,15 +4671,10 @@ TEST_F(InputDispatcherTest, NonSplittableSpyAboveNoInputChannelWindowTwoPointers
inputSinkWindow->assertNoEvents();
}
-/** Check the behaviour for cases where input sink prevents or doesn't prevent splitting. */
-class SpyThatPreventsSplittingWithApplicationFixture : public InputDispatcherTest,
- public ::testing::WithParamInterface<bool> {
-};
-
/**
* Three windows:
* - An application window (app window)
- * - A spy window that does not overlap the app window. Has PREVENT_SPLITTING flag
+ * - A spy window that does not overlap the app window.
* - A window below the spy that has NO_INPUT_CHANNEL (call it 'inputSink')
*
* The spy window is side-by-side with the app window. The inputSink is below the spy.
@@ -4687,34 +4682,31 @@ class SpyThatPreventsSplittingWithApplicationFixture : public InputDispatcherTes
* Only the SPY window should get the DOWN event.
* The spy pilfers after receiving the first DOWN event.
* Next, we touch the app window.
- * The spy should receive POINTER_DOWN(1) (since spy is preventing splits).
- * Also, since the spy is already pilfering the first pointer, it will be sent the remaining new
- * pointers automatically, as well.
+ * The spy should not receive POINTER_DOWN(1) (since the pointer is outside of the spy).
* Next, the first pointer (from the spy) is lifted.
- * Spy should get POINTER_UP(0).
+ * Spy should get ACTION_UP.
* This event should not go to the app because the app never received this pointer to begin with.
- * Now, lift the remaining pointer and check that the spy receives UP event.
+ * However, due to the current implementation, this would still cause an ACTION_MOVE event in the
+ * app.
+ * Now, lift the remaining pointer and check that the app receives UP event.
*
- * Finally, send a new ACTION_DOWN event to the spy and check that it's received.
+ * Finally, send a new ACTION_DOWN event to the spy and check that it gets received.
* This test attempts to reproduce a crash in the dispatcher.
*/
-TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingWithApplication) {
- SCOPED_FLAG_OVERRIDE(split_all_touches, false);
+TEST_F(InputDispatcherTest, SpyThatPilfersAfterFirstPointerWithTwoOtherWindows) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> spyWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Spy",
ui::LogicalDisplayId::DEFAULT);
spyWindow->setFrame(Rect(100, 100, 200, 200));
spyWindow->setTrustedOverlay(true);
- spyWindow->setPreventSplitting(true);
spyWindow->setSpy(true);
- // Another window below spy that has both NO_INPUT_CHANNEL and PREVENT_SPLITTING
+ // Another window below spy that has NO_INPUT_CHANNEL
sp<FakeWindowHandle> inputSinkWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Input sink below spy",
ui::LogicalDisplayId::DEFAULT);
inputSinkWindow->setFrame(Rect(100, 100, 200, 200)); // directly below the spy
inputSinkWindow->setTrustedOverlay(true);
- inputSinkWindow->setPreventSplitting(GetParam());
inputSinkWindow->setNoInputChannel(true);
sp<FakeWindowHandle> appWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "App",
@@ -4736,16 +4728,15 @@ TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingW
mDispatcher->pilferPointers(spyWindow->getToken());
- // Second finger lands in the app, and goes to the spy window. It doesn't go to the app because
- // the spy is already pilfering the first pointer, and this automatically grants the remaining
- // new pointers to the spy, as well.
+ // Second finger lands in the app. It goes to the app as ACTION_DOWN.
mDispatcher->notifyMotion(
MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
.pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
.build());
- spyWindow->consumeMotionPointerDown(1, WithPointerCount(2));
+ spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerCount(1)));
+ appWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
// Now lift up the first pointer
mDispatcher->notifyMotion(
@@ -4753,14 +4744,15 @@ TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingW
.pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150))
.pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
.build());
- spyWindow->consumeMotionPointerUp(0, WithPointerCount(2));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
+ appWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerCount(1)));
// And lift the remaining pointer!
mDispatcher->notifyMotion(
MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
.pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
.build());
- spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithPointerCount(1)));
+ appWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithPointerCount(1)));
// Now send a new DOWN, which should again go to spy.
mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
@@ -4772,10 +4764,6 @@ TEST_P(SpyThatPreventsSplittingWithApplicationFixture, SpyThatPreventsSplittingW
appWindow->assertNoEvents();
}
-// Behaviour should be the same regardless of whether inputSink supports splitting.
-INSTANTIATE_TEST_SUITE_P(SpyThatPreventsSplittingWithApplication,
- SpyThatPreventsSplittingWithApplicationFixture, testing::Bool());
-
TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -5729,14 +5717,12 @@ TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
window->assertNoEvents();
}
-TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
- SCOPED_FLAG_OVERRIDE(split_all_touches, false);
+TEST_F(InputDispatcherTest, WindowDoesNotReceiveSecondPointerOutsideOfItsBounds) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
ui::LogicalDisplayId::DEFAULT);
- // Ensure window is non-split and have some transform.
- window->setPreventSplitting(true);
+ // Ensure window has a non-trivial transform.
window->setWindowOffset(20, 40);
mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
@@ -5744,7 +5730,10 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
ui::LogicalDisplayId::DEFAULT, {50, 50}))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
+ window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN),
+ WithCoords(70, // 50 + 20
+ 90 // 50 + 40
+ )));
const MotionEvent secondFingerDownEvent =
MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
@@ -5753,45 +5742,32 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) {
.pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
.pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50))
.build();
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ ASSERT_EQ(InputEventInjectionResult::FAILED,
injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
InputEventInjectionSync::WAIT_FOR_RESULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-
- std::unique_ptr<MotionEvent> event = window->consumeMotionEvent();
- ASSERT_NE(nullptr, event);
- EXPECT_EQ(POINTER_1_DOWN, event->getAction());
- EXPECT_EQ(70, event->getX(0)); // 50 + 20
- EXPECT_EQ(90, event->getY(0)); // 50 + 40
- EXPECT_EQ(-10, event->getX(1)); // -30 + 20
- EXPECT_EQ(-10, event->getY(1)); // -50 + 40
+ << "Injection should fail because the second finger is outside of any window on the "
+ "screen.";
}
/**
- * Two windows: a splittable and a non-splittable.
- * The non-splittable window shouldn't receive any "incomplete" gestures.
- * Send the first pointer to the splittable window, and then touch the non-splittable window.
- * The second pointer should be dropped because the initial window is splittable, so it won't get
- * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
- * "incomplete" gestures.
+ * Two windows.
+ * Send the first pointer to the left window, and then touch the right window.
+ * The second pointer should generate an ACTION_DOWN in the right window.
*/
-TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
- SCOPED_FLAG_OVERRIDE(split_all_touches, false);
+TEST_F(InputDispatcherTest, TwoWindowsTwoPointers) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> leftWindow =
- sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
ui::LogicalDisplayId::DEFAULT);
- leftWindow->setPreventSplitting(false);
leftWindow->setFrame(Rect(0, 0, 100, 100));
sp<FakeWindowHandle> rightWindow =
- sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right Window",
ui::LogicalDisplayId::DEFAULT);
- rightWindow->setPreventSplitting(true);
rightWindow->setFrame(Rect(100, 100, 200, 200));
mDispatcher->onWindowInfosChanged(
{{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
- // Touch down on left, splittable window
+ // Touch down on left window
mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
.build());
@@ -5802,8 +5778,8 @@ TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
.pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
.pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
.build());
- leftWindow->assertNoEvents();
- rightWindow->assertNoEvents();
+ leftWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
+ rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
}
/**
@@ -5826,7 +5802,6 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch)
sp<FakeWindowHandle>::make(application1, mDispatcher, "wallpaper",
ui::LogicalDisplayId::DEFAULT);
wallpaper->setIsWallpaper(true);
- wallpaper->setPreventSplitting(true);
wallpaper->setTouchable(false);
sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application2, mDispatcher, "Left",
@@ -5960,7 +5935,6 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_
sp<FakeWindowHandle>::make(application1, mDispatcher, "wallpaper",
ui::LogicalDisplayId::DEFAULT);
wallpaper->setIsWallpaper(true);
- wallpaper->setPreventSplitting(true);
wallpaper->setTouchable(false);
sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application2, mDispatcher, "Left",
@@ -6074,20 +6048,18 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_
}
/**
- * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a
- * down event to the right window. Device B sends a down event to the left window, and then a
- * POINTER_DOWN event to the right window. However, since the left window prevents splitting, the
- * POINTER_DOWN event should only go to the left window, and not to the right window.
+ * Two windows: left and right. Device A sends a DOWN event to the right window. Device B sends a
+ * DOWN event to the left window, and then a POINTER_DOWN event outside of all windows.
+ * The POINTER_DOWN event should be dropped.
* This test attempts to reproduce a crash.
*/
-TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
- SCOPED_FLAG_OVERRIDE(split_all_touches, false);
+TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsTwoPointers) {
+ SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> leftWindow =
- sp<FakeWindowHandle>::make(application, mDispatcher, "Left window (prevent splitting)",
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left window",
ui::LogicalDisplayId::DEFAULT);
leftWindow->setFrame(Rect(0, 0, 100, 100));
- leftWindow->setPreventSplitting(true);
sp<FakeWindowHandle> rightWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
@@ -6111,14 +6083,14 @@ TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
.deviceId(deviceB)
.build());
leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
- // Send a second pointer from device B to the right window. It shouldn't go to the right window
- // because the left window prevents splitting.
+
+ // Send a second pointer from device B to an area outside of all windows.
mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
.deviceId(deviceB)
.pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
.pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
.build());
- leftWindow->consumeMotionPointerDown(1, WithDeviceId(deviceB));
+ // This is dropped because there's no touchable window at the location (120, 120)
// Finish the gesture for both devices
mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
@@ -6126,7 +6098,8 @@ TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
.pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
.pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
.build());
- leftWindow->consumeMotionPointerUp(1, WithDeviceId(deviceB));
+ leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithPointerId(0, 0)));
+
mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
.pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
.deviceId(deviceB)
@@ -6953,7 +6926,7 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) {
AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
}
-TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
+TEST_P(TransferTouchFixture, TransferTouch_TwoPointers) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
PointF touchPoint = {10, 10};
@@ -6962,11 +6935,9 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
sp<FakeWindowHandle> firstWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
ui::LogicalDisplayId::DEFAULT);
- firstWindow->setPreventSplitting(true);
sp<FakeWindowHandle> secondWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
ui::LogicalDisplayId::DEFAULT);
- secondWindow->setPreventSplitting(true);
// Add the windows to the dispatcher
mDispatcher->onWindowInfosChanged(
@@ -8823,12 +8794,10 @@ TEST_F(InputDispatcherTest, HoverEnterExitSynthesisUsesNewEventId) {
}
/**
- * When a device reports a DOWN event, which lands in a window that supports splits, and then the
- * device then reports a POINTER_DOWN, which lands in the location of a non-existing window, then
- * the previous window should receive this event and not be dropped.
+ * First finger lands into a window, and then the second finger lands in the location of a
+ * non-existent window. The second finger should be dropped.
*/
TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWithoutWindowTarget) {
- SCOPED_FLAG_OVERRIDE(split_all_touches, false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
ui::LogicalDisplayId::DEFAULT);
@@ -8846,13 +8815,13 @@ TEST_F(InputDispatcherMultiDeviceTest, SingleDevicePointerDownEventRetentionWith
.pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200))
.build());
- window->consumeMotionEvent(AllOf(WithMotionAction(POINTER_1_DOWN)));
+ window->assertNoEvents();
}
/**
* When deviceA reports a DOWN event, which lands in a window that supports splits, and then deviceB
* also reports a DOWN event, which lands in the location of a non-existing window, then the
- * previous window should receive deviceB's event and it should be dropped.
+ * previous window should not receive deviceB's event and it should be dropped.
*/
TEST_F(InputDispatcherMultiDeviceTest, SecondDeviceDownEventDroppedWithoutWindowTarget) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -12653,9 +12622,6 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
}
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,
ui::LogicalDisplayId::DEFAULT, {50, 50}))
@@ -13555,14 +13521,10 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) {
}
/**
- * The spy window should not be able to affect whether or not touches are split. Only the foreground
- * windows should be allowed to control split touch.
+ * The spy window should not be able to affect whether or not touches are split.
*/
TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
- // This spy window prevents touch splitting. However, we still expect to split touches
- // because a foreground window has not disabled splitting.
auto spy = createSpy();
- spy->setPreventSplitting(true);
auto window = createForeground();
window->setFrame(Rect(0, 0, 100, 100));
diff --git a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp
index 79a5ff6e5f..31db2fedc7 100644
--- a/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp
@@ -76,7 +76,6 @@ void scrambleWindow(FuzzedDataProvider& fdp, FakeWindowHandle& window) {
window.setDupTouchToWallpaper(fdp.ConsumeBool());
window.setIsWallpaper(fdp.ConsumeBool());
window.setVisible(fdp.ConsumeBool());
- window.setPreventSplitting(fdp.ConsumeBool());
const bool isTrustedOverlay = fdp.ConsumeBool();
window.setTrustedOverlay(isTrustedOverlay);
if (isTrustedOverlay) {