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

Commit d9213ec4 authored by Arthur Hung's avatar Arthur Hung Committed by Automerger Merge Worker
Browse files

Merge "Allow touch split enabled when no window touched" into sc-v2-dev am: c54964d3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/16342382

Change-Id: I33649ea2bca5ed0e65c78d23217d6f049d7c5936
parents bc4ca888 c54964d3
Loading
Loading
Loading
Loading
+12 −8
Original line number Diff line number Diff line
@@ -2026,10 +2026,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
                findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
                                          isDown /*addOutsideTargets*/, true /*addPortalWindows*/);

        std::vector<TouchedMonitor> newGestureMonitors = isDown
                ? findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows)
                : std::vector<TouchedMonitor>{};

        // Figure out whether splitting will be allowed for this window.
        if (newTouchedWindowHandle != nullptr &&
            newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2089,8 +2085,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
            newTouchedWindowHandle = nullptr;
        }

        // Also don't send the new touch event to unresponsive gesture monitors
        newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors);
        const std::vector<TouchedMonitor> newGestureMonitors = isDown
                ? selectResponsiveMonitorsLocked(
                          findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows))
                : tempTouchState.gestureMonitors;

        if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) {
            ALOGI("Dropping event because there is no touchable window or gesture monitor at "
@@ -2126,9 +2124,14 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
                pointerIds.markBit(pointerId);
            }
            tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
        } else if (tempTouchState.windows.empty()) {
            // If no window is touched, set split to true. This will allow the next pointer down to
            // be delivered to a new window which supports split touch.
            tempTouchState.split = true;
        }

        if (isDown) {
            tempTouchState.addGestureMonitors(newGestureMonitors);
        }
    } else {
        /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */

@@ -5426,6 +5429,7 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
              canceledWindows.c_str());

        // Then clear the current touch state so we stop dispatching to them as well.
        state.split = false;
        state.filterNonMonitors();
    }
    return OK;
+97 −0
Original line number Diff line number Diff line
@@ -2301,6 +2301,18 @@ public:
                                     expectedDisplayId, expectedFlags);
    }

    void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL,
                                     expectedDisplayId, expectedFlags);
    }

    void consumeMotionPointerDown(int32_t pointerIdx) {
        int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
                (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
        mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, ADISPLAY_ID_DEFAULT,
                                     0 /*expectedFlags*/);
    }

    MotionEvent* consumeMotion() {
        InputEvent* event = mInputReceiver->consume();
        if (!event) {
@@ -2447,6 +2459,91 @@ TEST_F(InputDispatcherTest, TestMoveEvent) {
                         0 /*expectedFlags*/);
}

TEST_F(InputDispatcherTest, GestureMonitor_SplitIfNoWindowTouched) {
    FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
                                                      true /*isGestureMonitor*/);

    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    // Create a non touch modal window that supports split touch
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
    window->setFrame(Rect(0, 0, 100, 100));
    window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});

    // First finger down, no window touched.
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               {100, 200}))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
    window->assertNoEvents();

    // Second finger down on window, the window should receive touch down.
    const MotionEvent secondFingerDownEvent =
            MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                               AINPUT_SOURCE_TOUCHSCREEN)
                    .displayId(ADISPLAY_ID_DEFAULT)
                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
                                     .x(100)
                                     .y(200))
                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
                    .build();
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
                                InputEventInjectionSync::WAIT_FOR_RESULT))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";

    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
    monitor.consumeMotionPointerDown(1 /* pointerIndex */);
}

TEST_F(InputDispatcherTest, GestureMonitor_NoSplitAfterPilfer) {
    FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
                                                      true /*isGestureMonitor*/);

    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    // Create a non touch modal window that supports split touch
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
    window->setFrame(Rect(0, 0, 100, 100));
    window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});

    // First finger down, no window touched.
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               {100, 200}))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
    window->assertNoEvents();

    // Gesture monitor pilfer the pointers.
    mDispatcher->pilferPointers(monitor.getToken());

    // Second finger down on window, the window should not receive touch down.
    const MotionEvent secondFingerDownEvent =
            MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                               AINPUT_SOURCE_TOUCHSCREEN)
                    .displayId(ADISPLAY_ID_DEFAULT)
                    .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
                    .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
                                     .x(100)
                                     .y(200))
                    .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
                    .build();
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
                                InputEventInjectionSync::WAIT_FOR_RESULT))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";

    window->assertNoEvents();
    monitor.consumeMotionPointerDown(1 /* pointerIndex */);
}

/**
 * Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
 * the device default right away. In the test scenario, we check both the default value,