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

Commit 13519f94 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge changes I6987619c,Ic82f87c5 into main

* changes:
  InputDispatcher: Use correct coordinate space when synthesizing down
  InputDispatcher: Use correct coordinate space when canceling motions
parents 659d410a 1c29a09b
Loading
Loading
Loading
Loading
+55 −24
Original line number Diff line number Diff line
@@ -3944,7 +3944,6 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
    android_log_event_list(LOGTAG_INPUT_CANCEL)
            << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS;

    InputTarget target;
    sp<WindowInfoHandle> windowHandle;
    if (options.displayId) {
        windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(),
@@ -3952,27 +3951,47 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
    } else {
        windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken());
    }
    if (windowHandle != nullptr) {
        const WindowInfo* windowInfo = windowHandle->getInfo();
        target.setDefaultPointerTransform(windowInfo->transform);
        target.globalScaleFactor = windowInfo->globalScaleFactor;
    }
    target.inputChannel = connection->inputChannel;
    target.flags = InputTarget::Flags::DISPATCH_AS_IS;

    const bool wasEmpty = connection->outboundQueue.empty();

    for (size_t i = 0; i < cancelationEvents.size(); i++) {
        std::unique_ptr<EventEntry> cancelationEventEntry = std::move(cancelationEvents[i]);
        std::vector<InputTarget> targets{};
        // The target to use if we don't find a window associated with the channel.
        const InputTarget fallbackTarget{.inputChannel = connection->inputChannel,
                                         .flags = InputTarget::Flags::DISPATCH_AS_IS};

        switch (cancelationEventEntry->type) {
            case EventEntry::Type::KEY: {
                logOutboundKeyDetails("cancel - ",
                                      static_cast<const KeyEntry&>(*cancelationEventEntry));
                const auto& keyEntry = static_cast<const KeyEntry&>(*cancelationEventEntry);
                if (windowHandle != nullptr) {
                    addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS,
                                          /*pointerIds=*/{}, keyEntry.downTime, targets);
                } else {
                    targets.emplace_back(fallbackTarget);
                }
                logOutboundKeyDetails("cancel - ", keyEntry);
                break;
            }
            case EventEntry::Type::MOTION: {
                logOutboundMotionDetails("cancel - ",
                                         static_cast<const MotionEntry&>(*cancelationEventEntry));
                const auto& motionEntry = static_cast<const MotionEntry&>(*cancelationEventEntry);
                if (windowHandle != nullptr) {
                    std::bitset<MAX_POINTER_ID + 1> pointerIds;
                    for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount;
                         pointerIndex++) {
                        pointerIds.set(motionEntry.pointerProperties[pointerIndex].id);
                    }
                    addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS,
                                          pointerIds, motionEntry.downTime, targets);
                } else {
                    targets.emplace_back(fallbackTarget);
                    const auto it = mDisplayInfos.find(motionEntry.displayId);
                    if (it != mDisplayInfos.end()) {
                        targets.back().displayTransform = it->second.transform;
                        targets.back().setDefaultPointerTransform(it->second.transform);
                    }
                }
                logOutboundMotionDetails("cancel - ", motionEntry);
                break;
            }
            case EventEntry::Type::FOCUS:
@@ -3992,7 +4011,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
            }
        }

        enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), target,
        if (targets.size() != 1) LOG(FATAL) << __func__ << ": InputTarget not created";
        enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), targets[0],
                                   InputTarget::Flags::DISPATCH_AS_IS);
    }

@@ -4021,23 +4041,33 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
              connection->getInputChannelName().c_str(), downEvents.size());
    }

    InputTarget target;
    sp<WindowInfoHandle> windowHandle =
            getWindowHandleLocked(connection->inputChannel->getConnectionToken());
    if (windowHandle != nullptr) {
        const WindowInfo* windowInfo = windowHandle->getInfo();
        target.setDefaultPointerTransform(windowInfo->transform);
        target.globalScaleFactor = windowInfo->globalScaleFactor;
    }
    target.inputChannel = connection->inputChannel;
    target.flags = targetFlags;

    const bool wasEmpty = connection->outboundQueue.empty();
    for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
        std::vector<InputTarget> targets{};
        switch (downEventEntry->type) {
            case EventEntry::Type::MOTION: {
                logOutboundMotionDetails("down - ",
                        static_cast<const MotionEntry&>(*downEventEntry));
                const auto& motionEntry = static_cast<const MotionEntry&>(*downEventEntry);
                if (windowHandle != nullptr) {
                    std::bitset<MAX_POINTER_ID + 1> pointerIds;
                    for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount;
                         pointerIndex++) {
                        pointerIds.set(motionEntry.pointerProperties[pointerIndex].id);
                    }
                    addWindowTargetLocked(windowHandle, targetFlags, pointerIds,
                                          motionEntry.downTime, targets);
                } else {
                    targets.emplace_back(InputTarget{.inputChannel = connection->inputChannel,
                                                     .flags = targetFlags});
                    const auto it = mDisplayInfos.find(motionEntry.displayId);
                    if (it != mDisplayInfos.end()) {
                        targets.back().displayTransform = it->second.transform;
                        targets.back().setDefaultPointerTransform(it->second.transform);
                    }
                }
                logOutboundMotionDetails("down - ", motionEntry);
                break;
            }

@@ -4055,7 +4085,8 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
            }
        }

        enqueueDispatchEntryLocked(connection, std::move(downEventEntry), target,
        if (targets.size() != 1) LOG(FATAL) << __func__ << ": InputTarget not created";
        enqueueDispatchEntryLocked(connection, std::move(downEventEntry), targets[0],
                                   InputTarget::Flags::DISPATCH_AS_IS);
    }

+108 −59
Original line number Diff line number Diff line
@@ -1451,6 +1451,69 @@ private:

std::atomic<int32_t> FakeWindowHandle::sId{1};

class FakeMonitorReceiver {
public:
    FakeMonitorReceiver(const std::unique_ptr<InputDispatcher>& dispatcher, const std::string name,
                        int32_t displayId) {
        base::Result<std::unique_ptr<InputChannel>> channel =
                dispatcher->createInputMonitor(displayId, name, MONITOR_PID);
        mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
    }

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

    void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
                                     expectedFlags);
    }

    std::optional<int32_t> receiveEvent() {
        return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
    }

    void finishEvent(uint32_t consumeSeq) { return mInputReceiver->finishEvent(consumeSeq); }

    void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
                                     expectedDisplayId, expectedFlags);
    }

    void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
                                     expectedDisplayId, expectedFlags);
    }

    void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
                                     expectedDisplayId, expectedFlags);
    }

    void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeMotionEvent(
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
                      WithDisplayId(expectedDisplayId),
                      WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
    }

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

    void consumeMotionEvent(const ::testing::Matcher<MotionEvent>& matcher) {
        mInputReceiver->consumeMotionEvent(matcher);
    }

    MotionEvent* consumeMotion() { return mInputReceiver->consumeMotion(); }

    void assertNoEvents() { mInputReceiver->assertNoEvents(); }

private:
    std::unique_ptr<FakeInputReceiver> mInputReceiver;
};

static InputEventInjectionResult injectKey(
        InputDispatcher& dispatcher, int32_t action, int32_t repeatCount,
        int32_t displayId = ADISPLAY_ID_NONE,
@@ -4607,6 +4670,51 @@ TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinate
    EXPECT_EQ(80, event->getY(0));
}

TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) {
    auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
    // The monitor will always receive events in the logical display's coordinate space, because
    // it does not have a window.
    FakeMonitorReceiver monitor{mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT};

    // Send down to the first window.
    mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                                 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
    firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));
    monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));

    // Second pointer goes down on second window.
    mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                                 ADISPLAY_ID_DEFAULT,
                                                 {PointF{50, 100}, PointF{150, 220}}));
    secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80)));
    const std::map<int32_t, PointF> expectedMonitorPointers{{0, PointF{100, 400}},
                                                            {1, PointF{300, 880}}};
    monitor.consumeMotionEvent(
            AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers)));

    mDispatcher->cancelCurrentTouch();

    firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
    secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80)));
    monitor.consumeMotionEvent(
            AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers)));
}

TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) {
    auto [firstWindow, secondWindow] = setupScaledDisplayScenario();

    // Send down to the first window.
    mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                                 ADISPLAY_ID_DEFAULT, {PointF{50, 100}}));
    firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400)));

    // The pointer is transferred to the second window, and the second window receives it in the
    // correct coordinate space.
    mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken());
    firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400)));
    secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400)));
}

/** Ensure consistent behavior of InputDispatcher in all orientations. */
class InputDispatcherDisplayOrientationFixture
      : public InputDispatcherDisplayProjectionTest,
@@ -5389,65 +5497,6 @@ TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) {
    mDispatcher->waitForIdle();
}

class FakeMonitorReceiver {
public:
    FakeMonitorReceiver(const std::unique_ptr<InputDispatcher>& dispatcher, const std::string name,
                        int32_t displayId) {
        base::Result<std::unique_ptr<InputChannel>> channel =
                dispatcher->createInputMonitor(displayId, name, MONITOR_PID);
        mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
    }

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

    void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
                                     expectedFlags);
    }

    std::optional<int32_t> receiveEvent() {
        return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED);
    }

    void finishEvent(uint32_t consumeSeq) { return mInputReceiver->finishEvent(consumeSeq); }

    void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN,
                                     expectedDisplayId, expectedFlags);
    }

    void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE,
                                     expectedDisplayId, expectedFlags);
    }

    void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP,
                                     expectedDisplayId, expectedFlags);
    }

    void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
        mInputReceiver->consumeMotionEvent(
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
                      WithDisplayId(expectedDisplayId),
                      WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED)));
    }

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

    MotionEvent* consumeMotion() { return mInputReceiver->consumeMotion(); }

    void assertNoEvents() { mInputReceiver->assertNoEvents(); }

private:
    std::unique_ptr<FakeInputReceiver> mInputReceiver;
};

using InputDispatcherMonitorTest = InputDispatcherTest;

/**