Loading services/inputflinger/dispatcher/InputDispatcher.cpp +6 −4 Original line number Original line Diff line number Diff line Loading @@ -2683,7 +2683,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio // Check if the wallpaper window should deliver the corresponding event. // Check if the wallpaper window should deliver the corresponding event. slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, tempTouchState, entry.deviceId, pointer, targets); tempTouchState, entry, targets); tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointer.id, tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointer.id, oldTouchedWindowHandle); oldTouchedWindowHandle); } } Loading Loading @@ -7100,9 +7100,11 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<WindowInfoHandle>& oldWindowHandle, const sp<WindowInfoHandle>& oldWindowHandle, const sp<WindowInfoHandle>& newWindowHandle, const sp<WindowInfoHandle>& newWindowHandle, TouchState& state, DeviceId deviceId, TouchState& state, const MotionEntry& entry, const PointerProperties& pointerProperties, std::vector<InputTarget>& targets) const { std::vector<InputTarget>& targets) const { LOG_IF(FATAL, entry.getPointerCount() != 1) << "Entry not eligible for slip: " << entry; const DeviceId deviceId = entry.deviceId; const PointerProperties& pointerProperties = entry.pointerProperties[0]; std::vector<PointerProperties> pointers{pointerProperties}; std::vector<PointerProperties> pointers{pointerProperties}; const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test( const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); Loading @@ -7129,7 +7131,7 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::SLIPPERY_ENTER, state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::SLIPPERY_ENTER, InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED, InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED, deviceId, pointers); deviceId, pointers, entry.eventTime); } } } } Loading services/inputflinger/dispatcher/InputDispatcher.h +14 −2 Original line number Original line Diff line number Diff line Loading @@ -709,11 +709,23 @@ private: sp<InputReporterInterface> mReporter; sp<InputReporterInterface> mReporter; /** * Slip the wallpaper touch if necessary. * * @param targetFlags the target flags * @param oldWindowHandle the old window that the touch slipped out of * @param newWindowHandle the new window that the touch is slipping into * @param state the current touch state. This will be updated if necessary to reflect the new * windows that are receiving touch. * @param deviceId the device id of the current motion being processed * @param pointerProperties the pointer properties of the current motion being processed * @param targets the current targets to add the walpaper ones to * @param eventTime the new downTime for the wallpaper target */ void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<android::gui::WindowInfoHandle>& oldWindowHandle, const sp<android::gui::WindowInfoHandle>& oldWindowHandle, const sp<android::gui::WindowInfoHandle>& newWindowHandle, const sp<android::gui::WindowInfoHandle>& newWindowHandle, TouchState& state, DeviceId deviceId, TouchState& state, const MotionEntry& entry, const PointerProperties& pointerProperties, std::vector<InputTarget>& targets) const REQUIRES(mLock); std::vector<InputTarget>& targets) const REQUIRES(mLock); void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, ftl::Flags<InputTarget::Flags> newTargetFlags, ftl::Flags<InputTarget::Flags> newTargetFlags, Loading services/inputflinger/dispatcher/TouchState.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -47,7 +47,7 @@ struct TouchState { const sp<android::gui::WindowInfoHandle>& windowHandle, const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers, DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers, std::optional<nsecs_t> firstDownTimeInTarget = std::nullopt); std::optional<nsecs_t> firstDownTimeInTarget); void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, DeviceId deviceId, const PointerProperties& pointer); DeviceId deviceId, const PointerProperties& pointer); void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); Loading services/inputflinger/tests/InputDispatcher_test.cpp +267 −0 Original line number Original line Diff line number Diff line Loading @@ -5710,6 +5710,273 @@ TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) { rightWindow->assertNoEvents(); rightWindow->assertNoEvents(); } } /** * Three windows: * 1) A window on the left, with flag dup_to_wallpaper * 2) A window on the right, with flag slippery * 3) A wallpaper window under the left window * When touch slips from right window to left, the wallpaper should receive a similar slippery * enter event. Later on, when another device becomes active, the wallpaper should receive * consistent streams from the new device, and also from the old device. * This test attempts to reproduce a crash in the dispatcher where the wallpaper target's downTime * was not getting set during slippery entrance. */ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch) { SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>(); std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>(); std::shared_ptr<FakeApplicationHandle> application3 = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> wallpaper = 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", ui::LogicalDisplayId::DEFAULT); leftWindow->setTouchableRegion(Region{{0, 0, 100, 100}}); leftWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application3, mDispatcher, "Right", ui::LogicalDisplayId::DEFAULT); rightWindow->setTouchableRegion(Region{{100, 0, 200, 100}}); rightWindow->setSlippery(true); rightWindow->setWatchOutsideTouch(true); rightWindow->setTrustedOverlay(true); mDispatcher->onWindowInfosChanged( {{*rightWindow->getInfo(), *leftWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0}); const DeviceId deviceA = 3; const DeviceId deviceB = 9; // First finger from device A into right window NotifyMotionArgs deviceADownArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) .deviceId(deviceA) .build(); mDispatcher->notifyMotion(deviceADownArgs); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Move the finger of device A from right window into left window. It should slip. mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(80).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); wallpaper->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Finger from device B down into left window NotifyMotionArgs deviceBDownArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40)) .deviceId(deviceB) .build(); mDispatcher->notifyMotion(deviceBDownArgs); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN))); rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_OUTSIDE))); // Move finger from device B, still keeping it in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50)) .deviceId(deviceB) .downTime(deviceBDownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE))); // Lift the finger from device B mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50)) .deviceId(deviceB) .downTime(deviceBDownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP))); // Move the finger of device A, keeping it in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE))); // Second finger down from device A, into the right window. It should be split into: // MOVE for the left window (due to existing implementation) + a DOWN into the right window // Wallpaper will not receive this new pointer, and it will only get the MOVE event. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); auto firstFingerMoveFromDeviceA = AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE), WithPointerCount(1), WithPointerId(0, 0)); leftWindow->consumeMotionEvent(firstFingerMoveFromDeviceA); wallpaper->consumeMotionEvent(firstFingerMoveFromDeviceA); rightWindow->consumeMotionEvent( AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_DOWN), WithPointerId(0, 1))); // Lift up the second finger. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP))); leftWindow->consumeMotionEvent(firstFingerMoveFromDeviceA); wallpaper->consumeMotionEvent(firstFingerMoveFromDeviceA); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP))); rightWindow->assertNoEvents(); } /** * Same test as above, but with enable_multi_device_same_window_stream flag set to false. */ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_legacy) { SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>(); std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>(); std::shared_ptr<FakeApplicationHandle> application3 = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> wallpaper = 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", ui::LogicalDisplayId::DEFAULT); leftWindow->setTouchableRegion(Region{{0, 0, 100, 100}}); leftWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application3, mDispatcher, "Right", ui::LogicalDisplayId::DEFAULT); rightWindow->setTouchableRegion(Region{{100, 0, 200, 100}}); rightWindow->setSlippery(true); rightWindow->setWatchOutsideTouch(true); rightWindow->setTrustedOverlay(true); mDispatcher->onWindowInfosChanged( {{*rightWindow->getInfo(), *leftWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0}); const DeviceId deviceA = 3; const DeviceId deviceB = 9; // First finger from device A into right window NotifyMotionArgs deviceADownArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) .deviceId(deviceA) .build(); mDispatcher->notifyMotion(deviceADownArgs); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Move the finger of device A from right window into left window. It should slip. mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(80).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); wallpaper->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Finger from device B down into left window NotifyMotionArgs deviceBDownArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40)) .deviceId(deviceB) .build(); mDispatcher->notifyMotion(deviceBDownArgs); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_CANCEL))); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_CANCEL))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN))); rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_OUTSIDE))); // Move finger from device B, still keeping it in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50)) .deviceId(deviceB) .downTime(deviceBDownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE))); // Lift the finger from device B mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50)) .deviceId(deviceB) .downTime(deviceBDownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP))); // Move the finger of device A, keeping it in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); // This device was already canceled, so MOVE events will not be arriving to the windows from it. // Second finger down from device A, into the right window. It should be split into: // MOVE for the left window (due to existing implementation) + a DOWN into the right window // Wallpaper will not receive this new pointer, and it will only get the MOVE event. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); rightWindow->consumeMotionEvent( AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_DOWN), WithPointerId(0, 1))); // Lift up the second finger. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP))); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); rightWindow->assertNoEvents(); } /** /** * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a * 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 * down event to the right window. Device B sends a down event to the left window, and then a Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +6 −4 Original line number Original line Diff line number Diff line Loading @@ -2683,7 +2683,7 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio // Check if the wallpaper window should deliver the corresponding event. // Check if the wallpaper window should deliver the corresponding event. slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, tempTouchState, entry.deviceId, pointer, targets); tempTouchState, entry, targets); tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointer.id, tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointer.id, oldTouchedWindowHandle); oldTouchedWindowHandle); } } Loading Loading @@ -7100,9 +7100,11 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<WindowInfoHandle>& oldWindowHandle, const sp<WindowInfoHandle>& oldWindowHandle, const sp<WindowInfoHandle>& newWindowHandle, const sp<WindowInfoHandle>& newWindowHandle, TouchState& state, DeviceId deviceId, TouchState& state, const MotionEntry& entry, const PointerProperties& pointerProperties, std::vector<InputTarget>& targets) const { std::vector<InputTarget>& targets) const { LOG_IF(FATAL, entry.getPointerCount() != 1) << "Entry not eligible for slip: " << entry; const DeviceId deviceId = entry.deviceId; const PointerProperties& pointerProperties = entry.pointerProperties[0]; std::vector<PointerProperties> pointers{pointerProperties}; std::vector<PointerProperties> pointers{pointerProperties}; const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test( const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); Loading @@ -7129,7 +7131,7 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFl state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::SLIPPERY_ENTER, state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::SLIPPERY_ENTER, InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_OBSCURED | InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED, InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED, deviceId, pointers); deviceId, pointers, entry.eventTime); } } } } Loading
services/inputflinger/dispatcher/InputDispatcher.h +14 −2 Original line number Original line Diff line number Diff line Loading @@ -709,11 +709,23 @@ private: sp<InputReporterInterface> mReporter; sp<InputReporterInterface> mReporter; /** * Slip the wallpaper touch if necessary. * * @param targetFlags the target flags * @param oldWindowHandle the old window that the touch slipped out of * @param newWindowHandle the new window that the touch is slipping into * @param state the current touch state. This will be updated if necessary to reflect the new * windows that are receiving touch. * @param deviceId the device id of the current motion being processed * @param pointerProperties the pointer properties of the current motion being processed * @param targets the current targets to add the walpaper ones to * @param eventTime the new downTime for the wallpaper target */ void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, const sp<android::gui::WindowInfoHandle>& oldWindowHandle, const sp<android::gui::WindowInfoHandle>& oldWindowHandle, const sp<android::gui::WindowInfoHandle>& newWindowHandle, const sp<android::gui::WindowInfoHandle>& newWindowHandle, TouchState& state, DeviceId deviceId, TouchState& state, const MotionEntry& entry, const PointerProperties& pointerProperties, std::vector<InputTarget>& targets) const REQUIRES(mLock); std::vector<InputTarget>& targets) const REQUIRES(mLock); void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags, ftl::Flags<InputTarget::Flags> newTargetFlags, ftl::Flags<InputTarget::Flags> newTargetFlags, Loading
services/inputflinger/dispatcher/TouchState.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -47,7 +47,7 @@ struct TouchState { const sp<android::gui::WindowInfoHandle>& windowHandle, const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers, DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers, std::optional<nsecs_t> firstDownTimeInTarget = std::nullopt); std::optional<nsecs_t> firstDownTimeInTarget); void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, DeviceId deviceId, const PointerProperties& pointer); DeviceId deviceId, const PointerProperties& pointer); void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); Loading
services/inputflinger/tests/InputDispatcher_test.cpp +267 −0 Original line number Original line Diff line number Diff line Loading @@ -5710,6 +5710,273 @@ TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) { rightWindow->assertNoEvents(); rightWindow->assertNoEvents(); } } /** * Three windows: * 1) A window on the left, with flag dup_to_wallpaper * 2) A window on the right, with flag slippery * 3) A wallpaper window under the left window * When touch slips from right window to left, the wallpaper should receive a similar slippery * enter event. Later on, when another device becomes active, the wallpaper should receive * consistent streams from the new device, and also from the old device. * This test attempts to reproduce a crash in the dispatcher where the wallpaper target's downTime * was not getting set during slippery entrance. */ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch) { SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, true); std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>(); std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>(); std::shared_ptr<FakeApplicationHandle> application3 = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> wallpaper = 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", ui::LogicalDisplayId::DEFAULT); leftWindow->setTouchableRegion(Region{{0, 0, 100, 100}}); leftWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application3, mDispatcher, "Right", ui::LogicalDisplayId::DEFAULT); rightWindow->setTouchableRegion(Region{{100, 0, 200, 100}}); rightWindow->setSlippery(true); rightWindow->setWatchOutsideTouch(true); rightWindow->setTrustedOverlay(true); mDispatcher->onWindowInfosChanged( {{*rightWindow->getInfo(), *leftWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0}); const DeviceId deviceA = 3; const DeviceId deviceB = 9; // First finger from device A into right window NotifyMotionArgs deviceADownArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) .deviceId(deviceA) .build(); mDispatcher->notifyMotion(deviceADownArgs); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Move the finger of device A from right window into left window. It should slip. mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(80).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); wallpaper->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Finger from device B down into left window NotifyMotionArgs deviceBDownArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40)) .deviceId(deviceB) .build(); mDispatcher->notifyMotion(deviceBDownArgs); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN))); rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_OUTSIDE))); // Move finger from device B, still keeping it in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50)) .deviceId(deviceB) .downTime(deviceBDownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE))); // Lift the finger from device B mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50)) .deviceId(deviceB) .downTime(deviceBDownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP))); // Move the finger of device A, keeping it in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE))); // Second finger down from device A, into the right window. It should be split into: // MOVE for the left window (due to existing implementation) + a DOWN into the right window // Wallpaper will not receive this new pointer, and it will only get the MOVE event. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); auto firstFingerMoveFromDeviceA = AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_MOVE), WithPointerCount(1), WithPointerId(0, 0)); leftWindow->consumeMotionEvent(firstFingerMoveFromDeviceA); wallpaper->consumeMotionEvent(firstFingerMoveFromDeviceA); rightWindow->consumeMotionEvent( AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_DOWN), WithPointerId(0, 1))); // Lift up the second finger. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP))); leftWindow->consumeMotionEvent(firstFingerMoveFromDeviceA); wallpaper->consumeMotionEvent(firstFingerMoveFromDeviceA); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP))); rightWindow->assertNoEvents(); } /** * Same test as above, but with enable_multi_device_same_window_stream flag set to false. */ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlipperyAndMultiWindowMultiTouch_legacy) { SCOPED_FLAG_OVERRIDE(enable_multi_device_same_window_stream, false); std::shared_ptr<FakeApplicationHandle> application1 = std::make_shared<FakeApplicationHandle>(); std::shared_ptr<FakeApplicationHandle> application2 = std::make_shared<FakeApplicationHandle>(); std::shared_ptr<FakeApplicationHandle> application3 = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> wallpaper = 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", ui::LogicalDisplayId::DEFAULT); leftWindow->setTouchableRegion(Region{{0, 0, 100, 100}}); leftWindow->setDupTouchToWallpaper(true); sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application3, mDispatcher, "Right", ui::LogicalDisplayId::DEFAULT); rightWindow->setTouchableRegion(Region{{100, 0, 200, 100}}); rightWindow->setSlippery(true); rightWindow->setWatchOutsideTouch(true); rightWindow->setTrustedOverlay(true); mDispatcher->onWindowInfosChanged( {{*rightWindow->getInfo(), *leftWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0}); const DeviceId deviceA = 3; const DeviceId deviceB = 9; // First finger from device A into right window NotifyMotionArgs deviceADownArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) .deviceId(deviceA) .build(); mDispatcher->notifyMotion(deviceADownArgs); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Move the finger of device A from right window into left window. It should slip. mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(80).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); wallpaper->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Finger from device B down into left window NotifyMotionArgs deviceBDownArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40)) .deviceId(deviceB) .build(); mDispatcher->notifyMotion(deviceBDownArgs); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_CANCEL))); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_CANCEL))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_DOWN))); rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_OUTSIDE))); // Move finger from device B, still keeping it in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50)) .deviceId(deviceB) .downTime(deviceBDownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_MOVE))); // Lift the finger from device B mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(50)) .deviceId(deviceB) .downTime(deviceBDownArgs.downTime) .build()); leftWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP))); wallpaper->consumeMotionEvent(AllOf(WithDeviceId(deviceB), WithMotionAction(ACTION_UP))); // Move the finger of device A, keeping it in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); // This device was already canceled, so MOVE events will not be arriving to the windows from it. // Second finger down from device A, into the right window. It should be split into: // MOVE for the left window (due to existing implementation) + a DOWN into the right window // Wallpaper will not receive this new pointer, and it will only get the MOVE event. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); rightWindow->consumeMotionEvent( AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_DOWN), WithPointerId(0, 1))); // Lift up the second finger. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .pointer(PointerBuilder(1, ToolType::FINGER).x(140).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); rightWindow->consumeMotionEvent(AllOf(WithDeviceId(deviceA), WithMotionAction(ACTION_UP))); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(70).y(50)) .deviceId(deviceA) .downTime(deviceADownArgs.downTime) .build()); rightWindow->assertNoEvents(); } /** /** * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a * 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 * down event to the right window. Device B sends a down event to the left window, and then a Loading