Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac42d24c authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Add more dispatcher tests for appearing windows

It has been suggested that a window that appears while the gesture is
active may cause incorrect behaviour in dispatcher if it then touched
with additional new pointers.

These tests attempt to check some of those scenarios. Currently, there's
no evidence that this could lead to a crash.

Flag: TEST_ONLY
Bug: 341869464
Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST --gtest_break_on_failure --gtest_filter="*SplitTouches*"
Change-Id: I856907958684e84d08858aa4b92199a28095e58a
parent 57225986
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -2497,9 +2497,8 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked(
        }

        if (newTouchedWindows.empty()) {
            ALOGI("Dropping event because there is no touchable window at (%.1f, %.1f) on display "
                  "%s.",
                  x, y, displayId.toString().c_str());
            LOG(INFO) << "Dropping event because there is no touchable window at (" << x << ", "
                      << y << ") on display " << displayId << ": " << entry;
            outInjectionResult = InputEventInjectionResult::FAILED;
            return {};
        }
+7 −0
Original line number Diff line number Diff line
@@ -304,6 +304,13 @@ public:
                                          WithFlags(expectedFlags)));
    }

    inline void consumeMotionPointerDown(int32_t pointerIdx,
                                         const ::testing::Matcher<MotionEvent>& matcher) {
        const int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
                (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
        consumeMotionEvent(testing::AllOf(WithMotionAction(action), matcher));
    }

    inline void consumeMotionPointerUp(int32_t pointerIdx,
                                       const ::testing::Matcher<MotionEvent>& matcher) {
        const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
+115 −0
Original line number Diff line number Diff line
@@ -4172,6 +4172,121 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
    window2->consumeMotionEvent(WithDownTime(secondDown->getDownTime()));
}
/**
 * When events are not 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.
 */
TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTimeForNewWindow) {
    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);
    window2->setTouchableRegion(Region{{100, 0, 200, 100}});
    mDispatcher->onWindowInfosChanged({{*window1->getInfo()}, {}, 0, 0});
    // Touch down on the first window
    NotifyMotionArgs downArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                        .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                        .build();
    mDispatcher->notifyMotion(downArgs);
    window1->consumeMotionEvent(
            AllOf(WithMotionAction(ACTION_DOWN), WithDownTime(downArgs.downTime)));
    // 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)));
    // Finish the gesture
    mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, 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(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();
}
/**
 * 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).
 */
TEST_F(InputDispatcherTest, SplitTouchesDropsEventForNonSplittableSecondWindow) {
    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}});
    sp<FakeWindowHandle> window2 =
            sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
    window2->setTouchableRegion(Region{{100, 0, 200, 100}});
    mDispatcher->onWindowInfosChanged({{*window1->getInfo()}, {}, 0, 0});
    // Touch down on the first window
    NotifyMotionArgs downArgs = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                        .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                        .build();
    mDispatcher->notifyMotion(downArgs);
    window1->consumeMotionEvent(
            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
    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.
    // Complete the gesture
    mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, 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());
    // A redundant MOVE event is generated that doesn't carry any new information
    window1->consumeMotionEvent(
            AllOf(WithMotionAction(ACTION_MOVE), WithDownTime(downArgs.downTime)));
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                      .downTime(downArgs.downTime)
                                      .build());
    window1->consumeMotionEvent(
            AllOf(WithMotionAction(ACTION_UP), WithDownTime(downArgs.downTime)));
    window1->assertNoEvents();
    window2->assertNoEvents();
}
TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> windowLeft = sp<FakeWindowHandle>::make(application, mDispatcher, "Left",