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

Commit 923373d5 authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

Reland "Input injection: Assume transformed values are i..."

Revert submission 16306432-revert-16295572-ORWQJPYRMQ

Reason for revert: The broken test was fixed in ag/16365181, so
this should be safe to re-land now.

Reverted Changes:
Iab395d41d:Revert "Remove x/y offset from MotionEntry"
I7beca684d:Revert "Input injection: Assume transformed values...

Change-Id: I68b5619bf52d999a653bb246e1acb02f5d07991e
parent e1e23f40
Loading
Loading
Loading
Loading
+20 −35
Original line number Diff line number Diff line
@@ -506,12 +506,6 @@ bool isConnectionResponsive(const Connection& connection) {
    return true;
}

vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) {
    const vec2 transformedXy = transform.transform(x, y);
    const vec2 transformedOrigin = transform.transform(0, 0);
    return transformedXy - transformedOrigin;
}

// Returns true if the event type passed as argument represents a user activity.
bool isUserActivityEvent(const EventEntry& eventEntry) {
    switch (eventEntry.type) {
@@ -4214,10 +4208,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
                                                  motionEvent.getRawXCursorPosition(),
                                                  motionEvent.getRawYCursorPosition(),
                                                  motionEvent.getDownTime(), uint32_t(pointerCount),
                                                  pointerProperties, samplePointerCoords,
                                                  motionEvent.getXOffset(),
                                                  motionEvent.getYOffset());
            transformMotionEntryForInjectionLocked(*injectedEntry);
                                                  pointerProperties, samplePointerCoords, 0, 0);
            transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform());
            injectedEntries.push(std::move(injectedEntry));
            for (size_t i = motionEvent.getHistorySize(); i > 0; i--) {
                sampleEventTimes += 1;
@@ -4236,9 +4228,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
                                                      motionEvent.getRawYCursorPosition(),
                                                      motionEvent.getDownTime(),
                                                      uint32_t(pointerCount), pointerProperties,
                                                      samplePointerCoords, motionEvent.getXOffset(),
                                                      motionEvent.getYOffset());
                transformMotionEntryForInjectionLocked(*nextInjectedEntry);
                                                      samplePointerCoords, 0, 0);
                transformMotionEntryForInjectionLocked(*nextInjectedEntry,
                                                       motionEvent.getTransform());
                injectedEntries.push(std::move(nextInjectedEntry));
            }
            break;
@@ -4402,35 +4394,28 @@ void InputDispatcher::setInjectionResult(EventEntry& entry,
    }
}

void InputDispatcher::transformMotionEntryForInjectionLocked(MotionEntry& entry) const {
    const bool isRelativeMouseEvent = isFromSource(entry.source, AINPUT_SOURCE_MOUSE_RELATIVE);
    if (!isRelativeMouseEvent && !isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) {
        return;
    }

void InputDispatcher::transformMotionEntryForInjectionLocked(
        MotionEntry& entry, const ui::Transform& injectedTransform) const {
    // Input injection works in the logical display coordinate space, but the input pipeline works
    // display space, so we need to transform the injected events accordingly.
    const auto it = mDisplayInfos.find(entry.displayId);
    if (it == mDisplayInfos.end()) return;
    const auto& transformToDisplay = it->second.transform.inverse();
    const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform;

    for (uint32_t i = 0; i < entry.pointerCount; i++) {
        PointerCoords& pc = entry.pointerCoords[i];
        const auto xy = isRelativeMouseEvent
                ? transformWithoutTranslation(transformToDisplay, pc.getX(), pc.getY())
                : transformToDisplay.transform(pc.getXYValue());
        pc.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
        pc.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);

        // Axes with relative values never represent points on a screen, so they should never have
        // translation applied. If a device does not report relative values, these values are always
        // 0, and will remain unaffected by the following operation.
        const auto rel =
                transformWithoutTranslation(transformToDisplay,
                                            pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
                                            pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
        pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, rel.x);
        pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, rel.y);
        // Make a copy of the injected coords. We cannot change them in place because some of them
        // are interdependent (for example, X coordinate might depend on the Y coordinate).
        PointerCoords injectedCoords = entry.pointerCoords[i];

        BitSet64 bits(injectedCoords.bits);
        while (!bits.isEmpty()) {
            const auto axis = static_cast<int32_t>(bits.clearFirstMarkedBit());
            const float value =
                    MotionEvent::calculateTransformedAxisValue(axis, entry.source,
                                                               transformToDisplay, injectedCoords);
            pc.setAxisValue(axis, value);
        }
    }
}

+3 −1
Original line number Diff line number Diff line
@@ -280,7 +280,9 @@ private:
    bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
    void setInjectionResult(EventEntry& entry,
                            android::os::InputEventInjectionResult injectionResult);
    void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock);
    void transformMotionEntryForInjectionLocked(MotionEntry&,
                                                const ui::Transform& injectedTransform) const
            REQUIRES(mLock);

    std::condition_variable mInjectionSyncFinished;
    void incrementPendingForegroundDispatches(EventEntry& entry);
+27 −0
Original line number Diff line number Diff line
@@ -2079,6 +2079,33 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
    secondWindow->assertNoEvents();
}

// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
// event should be treated as being in the logical display space.
TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
    auto [firstWindow, secondWindow] = setupScaledDisplayScenario();

    const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
    ui::Transform injectedEventTransform;
    injectedEventTransform.set(matrix);
    const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
    const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);

    MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                .displayId(ADISPLAY_ID_DEFAULT)
                                .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
                                .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
                                                 .x(untransformedPoint.x)
                                                 .y(untransformedPoint.y))
                                .build();
    event.transform(matrix);

    injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT,
                      InputEventInjectionSync::WAIT_FOR_RESULT);

    firstWindow->consumeMotionDown();
    secondWindow->assertNoEvents();
}

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