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

Commit e680f9bf authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

InputDispatcher: Allow spy window to receive entire gesture after pilfer

After a spy window pilfers pointers, it should be albe to receive any
new pointers within its touchable bounds.

Bug: 217376964
Test: atest inputflinger_tests
Change-Id: Iab8360f2f8e3db978cf6c68f19a538b28f7dfac1
parent b0977e0f
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -1987,7 +1987,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
    TouchState tempTouchState;
    if (const auto it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
        oldState = &(it->second);
        tempTouchState.copyFrom(*oldState);
        tempTouchState = *oldState;
    }

    bool isSplit = tempTouchState.split;
@@ -5510,9 +5510,9 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
    ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(),
          canceledWindows.c_str());

    // Then clear the current touch state so we stop dispatching to them as well.
    state.split = false;
    // Prevent the gesture from being sent to any other windows.
    state.filterWindowsExcept(token);
    state.preventNewTargets = true;
    return OK;
}

+3 −20
Original line number Diff line number Diff line
@@ -25,27 +25,8 @@ using android::gui::WindowInfoHandle;

namespace android::inputdispatcher {

TouchState::TouchState()
      : down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {}

TouchState::~TouchState() {}

void TouchState::reset() {
    down = false;
    split = false;
    deviceId = -1;
    source = 0;
    displayId = ADISPLAY_ID_NONE;
    windows.clear();
}

void TouchState::copyFrom(const TouchState& other) {
    down = other.down;
    split = other.split;
    deviceId = other.deviceId;
    source = other.source;
    displayId = other.displayId;
    windows = other.windows;
    *this = TouchState();
}

void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags,
@@ -66,6 +47,8 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int
        }
    }

    if (preventNewTargets) return; // Don't add new TouchedWindows.

    TouchedWindow touchedWindow;
    touchedWindow.windowHandle = windowHandle;
    touchedWindow.targetFlags = targetFlags;
+15 −8
Original line number Diff line number Diff line
@@ -29,17 +29,24 @@ class WindowInfoHandle;
namespace inputdispatcher {

struct TouchState {
    bool down;
    bool split;
    int32_t deviceId;  // id of the device that is currently down, others are rejected
    uint32_t source;   // source of the device that is current down, others are rejected
    int32_t displayId; // id to the display that currently has a touch, others are rejected
    bool down = false;
    bool split = false;
    bool preventNewTargets = false;

    // id of the device that is currently down, others are rejected
    int32_t deviceId = -1;
    // source of the device that is current down, others are rejected
    uint32_t source = 0;
    // id to the display that currently has a touch, others are rejected
    int32_t displayId = ADISPLAY_ID_NONE;

    std::vector<TouchedWindow> windows;

    TouchState();
    ~TouchState();
    TouchState() = default;
    ~TouchState() = default;
    TouchState& operator=(const TouchState&) = default;

    void reset();
    void copyFrom(const TouchState& other);
    void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
                           int32_t targetFlags, BitSet32 pointerIds);
    void removeWindowByToken(const sp<IBinder>& token);
+31 −16
Original line number Diff line number Diff line
@@ -6511,32 +6511,29 @@ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) {
}

/**
 * After a spy window pilfers pointers, new pointers that go down should not go to any foreground
 * windows.
 * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
 * the spy, but not to any other windows.
 */
TEST_F(InputDispatcherSpyWindowTest, NoSplitAfterPilfer) {
    // Create a touch modal spy that spies on the entire display.
    auto spy = createSpy(static_cast<WindowInfo::Flag>(0));

    // Create a non touch modal window that supports split touch.
TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) {
    auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
    auto window = createForeground();
    window->setFrame(Rect(0, 0, 100, 100));
    window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);

    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});

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

    // Spy window pilfer the pointers.
    // Spy window pilfers the pointers.
    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
    window->consumeMotionCancel();

    // Second finger down on window, the window should not receive touch down.
    // Second finger down on the window and spy, but the window should not receive the pointer down.
    const MotionEvent secondFingerDownEvent =
            MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
@@ -6553,10 +6550,28 @@ TEST_F(InputDispatcherSpyWindowTest, NoSplitAfterPilfer) {
                                InputEventInjectionSync::WAIT_FOR_RESULT))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";

    spy->consumeMotionPointerDown(1 /*pointerIndex*/);

    // Third finger goes down outside all windows, so injection should fail.
    const MotionEvent thirdFingerDownEvent =
            MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
                                       (2 << 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))
                    .pointer(PointerBuilder(/* id */ 2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(-5).y(-5))
                    .build();
    ASSERT_EQ(InputEventInjectionResult::FAILED,
              injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
                                InputEventInjectionSync::WAIT_FOR_RESULT))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";

    spy->assertNoEvents();
    window->assertNoEvents();
    // Since we no longer allow splitting, the spy will not receive new pointers.
    // TODO(b/217376964): Add a way for the pilfering window to receive the rest of the gesture.
    spy->consumeMotionMove();
}

/**