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

Commit 3a240c44 authored by Michael Wright's avatar Michael Wright
Browse files

Check whether channel has been removed before sending cancelation.

When a gesture monitor pilfers pointers we synthesize cancelation
events for all currently active windows. It's possible, however, that a
window may have been removed between the beginning of the touch stream
and now, so we have to check whether the corresponding channel still
exists.

Bug: 145891806
Test: atest InputDispatcher_test.cpp
Change-Id: If16191b02bbb35886171c402b9bb74f547bdf94a
parent 0d4bd95f
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -4115,8 +4115,10 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
        options.displayId = displayId;
        for (const TouchedWindow& window : state.windows) {
            sp<InputChannel> channel = getInputChannelLocked(window.windowHandle->getToken());
            if (channel != nullptr) {
                synthesizeCancelationEventsForInputChannelLocked(channel, options);
            }
        }
        // Then clear the current touch state so we stop dispatching to them as well.
        state.filterNonMonitors();
    }
+85 −9
Original line number Diff line number Diff line
@@ -488,6 +488,11 @@ public:
                     expectedFlags);
    }

    void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP, expectedDisplayId,
                     expectedFlags);
    }

    void assertNoEvents() {
        InputEvent* event = consume();
        ASSERT_EQ(nullptr, event)
@@ -639,6 +644,11 @@ static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t s
    return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, x, y);
}

static int32_t injectMotionUp(const sp<InputDispatcher>& dispatcher, int32_t source,
                              int32_t displayId, int32_t x = 100, int32_t y = 200) {
    return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, x, y);
}

static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
    nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
    // Define a valid key event.
@@ -847,6 +857,81 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
                         0 /*expectedFlags*/);
}

class FakeMonitorReceiver : public FakeInputReceiver, public RefBase {
public:
    FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
                        int32_t displayId, bool isGestureMonitor = false)
          : FakeInputReceiver(dispatcher, name, displayId) {
        mDispatcher->registerInputMonitor(mServerChannel, displayId, isGestureMonitor);
    }

    sp<IBinder> getToken() { return mServerChannel->getConnectionToken(); }
};

// Tests for gesture monitors
TEST_F(InputDispatcherTest, GestureMonitor_ReceivesMotionEvents) {
    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);

    sp<FakeMonitorReceiver> monitor =
            new FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
                                    true /*isGestureMonitor*/);

    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
    monitor->consumeMotionDown(ADISPLAY_ID_DEFAULT);
}

TEST_F(InputDispatcherTest, GestureMonitor_DoesNotReceiveKeyEvents) {
    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);

    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
    window->setFocus();

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

    sp<FakeMonitorReceiver> monitor =
            new FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
                                    true /*isGestureMonitor*/);

    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
    monitor->assertNoEvents();
}

TEST_F(InputDispatcherTest, GestureMonitor_CanPilferAfterWindowIsRemovedMidStream) {
    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
    sp<FakeWindowHandle> window =
            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
    mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);

    sp<FakeMonitorReceiver> monitor =
            new FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
                                    true /*isGestureMonitor*/);

    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
    monitor->consumeMotionDown(ADISPLAY_ID_DEFAULT);

    window->releaseChannel();

    mDispatcher->pilferPointers(monitor->getToken());

    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
              injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
    monitor->consumeMotionUp(ADISPLAY_ID_DEFAULT);
}

/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
@@ -934,15 +1019,6 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus)
    windowInSecondary->assertNoEvents();
}

class FakeMonitorReceiver : public FakeInputReceiver, public RefBase {
public:
    FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
            int32_t displayId, bool isGestureMonitor = false)
            : FakeInputReceiver(dispatcher, name, displayId) {
        mDispatcher->registerInputMonitor(mServerChannel, displayId, isGestureMonitor);
    }
};

// Test per-display input monitors for motion event.
TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) {
    sp<FakeMonitorReceiver> monitorInPrimary =