diff options
| -rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 3 | ||||
| -rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 40 |
2 files changed, 42 insertions, 1 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 326ca87c41..f3ada8e298 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2476,7 +2476,8 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( newTouchedWindowHandle = nullptr; } - if (!haveSameToken(oldTouchedWindowHandle, newTouchedWindowHandle)) { + if (newTouchedWindowHandle != nullptr && + !haveSameToken(oldTouchedWindowHandle, newTouchedWindowHandle)) { ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32, oldTouchedWindowHandle->getName().c_str(), newTouchedWindowHandle->getName().c_str(), displayId); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index a6cdee5fb1..f6f02d8241 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -5535,6 +5535,46 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); } +/** + * Two windows, one on the left and another on the right. The left window is slippery. The right + * window isn't eligible to receive touch because it specifies InputConfig::DROP_INPUT. When the + * touch moves from the left window into the right window, the gesture should continue to go to the + * left window. Touch shouldn't slip because the right window can't receive touches. This test + * reproduces a crash. + */ +TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + + sp<FakeWindowHandle> leftSlipperyWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftSlipperyWindow->setSlippery(true); + leftSlipperyWindow->setFrame(Rect(0, 0, 100, 100)); + + sp<FakeWindowHandle> rightDropTouchesWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100)); + rightDropTouchesWindow->setDropInput(true); + + mDispatcher->setInputWindows( + {{ADISPLAY_ID_DEFAULT, {leftSlipperyWindow, rightDropTouchesWindow}}}); + + // Start touch in the left window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + leftSlipperyWindow->consumeMotionDown(); + + // And move it into the right window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) + .build()); + + // Since the right window isn't eligible to receive input, touch does not slip. + // The left window continues to receive the gesture. + leftSlipperyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + rightDropTouchesWindow->assertNoEvents(); +} + class InputDispatcherKeyRepeatTest : public InputDispatcherTest { protected: static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms |