diff options
-rw-r--r-- | libs/gui/WindowInfo.cpp | 4 | ||||
-rw-r--r-- | libs/gui/include/gui/WindowInfo.h | 2 | ||||
-rw-r--r-- | libs/input/android/os/InputConfig.aidl | 13 | ||||
-rw-r--r-- | libs/input/input_flags.aconfig | 4 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 111 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 4 | ||||
-rw-r--r-- | services/inputflinger/tests/FakeWindows.h | 4 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 208 | ||||
-rw-r--r-- | services/inputflinger/tests/fuzzers/InputDispatcherFuzzer.cpp | 1 |
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) { |