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

Commit 20f55671 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topics "motion-event-offset-pointer-sources",...

Merge changes from topics "motion-event-offset-pointer-sources", "motionevent-rotate-relative-xy-sv2" into sc-v2-dev

* changes:
  MotionEvent: Transform mouse cursor position
  MotionEvent: Rotate relative axes according to window orientation
  InputDispatcher: Remove transform only for joysticks and touchpads
  Apply translation/offset to events from pointer sources only
  Use sysprop APIs for InputFlinger: per_window_input_rotation
parents aafd7661 4b19bd0d
Loading
Loading
Loading
Loading
+58 −4
Original line number Diff line number Diff line
@@ -91,6 +91,19 @@ vec2 rotatePoint(const ui::Transform& transform, float x, float y, int32_t displ
    return xy;
}

vec2 applyTransformWithoutTranslation(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;
}

bool shouldDisregardWindowTranslation(uint32_t source) {
    // Pointer events are the only type of events that refer to absolute coordinates on the display,
    // so we should apply the entire window transform. For other types of events, we should make
    // sure to not apply the window translation/offset.
    return (source & AINPUT_SOURCE_CLASS_POINTER) == 0;
}

} // namespace

const char* motionClassificationToString(MotionClassification classification) {
@@ -305,6 +318,8 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor);
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor);
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor);
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_X, windowXScale);
    scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale);
}

void PointerCoords::scale(float globalScaleFactor) {
@@ -373,6 +388,15 @@ void PointerCoords::transform(const ui::Transform& transform) {
    setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
    setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);

    if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_X) ||
        BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_RELATIVE_Y)) {
        const ui::Transform rotation(transform.getOrientation());
        const vec2 relativeXy = rotation.transform(getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
                                                   getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
        setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, relativeXy.x);
        setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, relativeXy.y);
    }

    if (BitSet64::hasBit(bits, AMOTION_EVENT_AXIS_ORIENTATION)) {
        const float val = getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
        setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(transform, val));
@@ -509,12 +533,23 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
    if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
        // For compatibility, convert raw coordinates into "oriented screen space". Once app
        // developers are educated about getRaw, we can consider removing this.
        const vec2 xy = rotatePoint(mTransform, coords->getX(), coords->getY(), mDisplayWidth,
        const vec2 xy = shouldDisregardWindowTranslation(mSource)
                ? rotatePoint(mTransform, coords->getX(), coords->getY())
                : rotatePoint(mTransform, coords->getX(), coords->getY(), mDisplayWidth,
                              mDisplayHeight);
        static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
        return xy[axis];
    }

    if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
        // For compatibility, since we convert raw coordinates into "oriented screen space", we
        // need to convert the relative axes into the same orientation for consistency.
        const vec2 relativeXy =
                rotatePoint(mTransform, coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
                            coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
        return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
    }

    return coords->getAxisValue(axis);
}

@@ -523,11 +558,23 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
    const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);

    if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
        const vec2 xy = mTransform.transform(coords->getXYValue());
        const vec2 xy = shouldDisregardWindowTranslation(mSource)
                ? applyTransformWithoutTranslation(mTransform, coords->getX(), coords->getY())
                : mTransform.transform(coords->getXYValue());
        static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
        return xy[axis];
    }

    if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
        const vec2 relativeXy =
                applyTransformWithoutTranslation(mTransform,
                                                 coords->getAxisValue(
                                                         AMOTION_EVENT_AXIS_RELATIVE_X),
                                                 coords->getAxisValue(
                                                         AMOTION_EVENT_AXIS_RELATIVE_Y));
        return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
    }

    return coords->getAxisValue(axis);
}

@@ -583,6 +630,13 @@ void MotionEvent::applyTransform(const std::array<float, 9>& matrix) {
    // Apply the transformation to all samples.
    std::for_each(mSamplePointerCoords.begin(), mSamplePointerCoords.end(),
                  [&transform](PointerCoords& c) { c.transform(transform); });

    if (mRawXCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION &&
        mRawYCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION) {
        const vec2 cursor = transform.transform(mRawXCursorPosition, mRawYCursorPosition);
        mRawXCursorPosition = cursor.x;
        mRawYCursorPosition = cursor.y;
    }
}

#ifdef __linux__
+55 −10
Original line number Diff line number Diff line
@@ -588,7 +588,7 @@ TEST_F(MotionEventTest, Transform) {
    }
    MotionEvent event;
    ui::Transform identityTransform;
    event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID,
    event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
                     INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
                     AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                     MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
@@ -636,13 +636,16 @@ TEST_F(MotionEventTest, Transform) {
    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
}

MotionEvent createTouchDownEvent(int x, int y, ui::Transform transform) {
MotionEvent createTouchDownEvent(float x, float y, float dx, float dy,
                                 const ui::Transform& transform) {
    std::vector<PointerProperties> pointerProperties;
    pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER});
    std::vector<PointerCoords> pointerCoords;
    pointerCoords.emplace_back().clear();
    pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, x);
    pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, y);
    pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx);
    pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy);
    nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
    MotionEvent event;
    event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN,
@@ -661,26 +664,56 @@ TEST_F(MotionEventTest, ApplyTransform) {
    ui::Transform identity;
    ui::Transform xform(ui::Transform::ROT_90, 800, 400);
    xform.set(xform.tx() + 20, xform.ty() + 40);
    MotionEvent event = createTouchDownEvent(60, 100, xform);
    MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
    ASSERT_EQ(700, event.getRawX(0));
    ASSERT_EQ(60, event.getRawY(0));
    ASSERT_NE(event.getRawX(0), event.getX(0));
    ASSERT_NE(event.getRawY(0), event.getY(0));
    // Relative values should be rotated but not translated.
    ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
    ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));

    MotionEvent changedEvent = createTouchDownEvent(60, 100, identity);
    MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity);
    const std::array<float, 9> rowMajor{xform[0][0], xform[1][0], xform[2][0],
                                        xform[0][1], xform[1][1], xform[2][1],
                                        xform[0][2], xform[1][2], xform[2][2]};
    changedEvent.applyTransform(rowMajor);

    // transformContent effectively rotates the raw coordinates, so those should now include
    // both rotation AND offset
    // both rotation AND offset.
    ASSERT_EQ(720, changedEvent.getRawX(0));
    ASSERT_EQ(100, changedEvent.getRawY(0));
    // Relative values should be rotated but not translated.
    ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
    ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));

    // The transformed output should be the same then
    // The transformed output should be the same then.
    ASSERT_NEAR(event.getX(0), changedEvent.getX(0), 0.001);
    ASSERT_NEAR(event.getY(0), changedEvent.getY(0), 0.001);
    ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0),
                changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0), 0.001);
    ASSERT_NEAR(event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0),
                changedEvent.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0), 0.001);
}

TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) {
    constexpr static auto NON_POINTER_SOURCES = {AINPUT_SOURCE_TRACKBALL,
                                                 AINPUT_SOURCE_MOUSE_RELATIVE,
                                                 AINPUT_SOURCE_JOYSTICK};
    for (uint32_t source : NON_POINTER_SOURCES) {
        // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
        ui::Transform xform(ui::Transform::ROT_90, 800, 400);
        xform.set(xform.tx() + 20, xform.ty() + 40);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        event.setSource(source);

        // Since this event comes from a non-pointer source, it should include rotation but not
        // translation/offset.
        ASSERT_EQ(-100, event.getX(0));
        ASSERT_EQ(60, event.getY(0));
        ASSERT_EQ(event.getRawX(0), event.getX(0));
        ASSERT_EQ(event.getRawY(0), event.getY(0));
    }
}

TEST_F(MotionEventTest, RawCompatTransform) {
@@ -688,11 +721,14 @@ TEST_F(MotionEventTest, RawCompatTransform) {
        // Make sure raw is raw regardless of transform translation.
        ui::Transform xform;
        xform.set(20, 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        ASSERT_EQ(60, event.getRawX(0));
        ASSERT_EQ(100, event.getRawY(0));
        ASSERT_NE(event.getRawX(0), event.getX(0));
        ASSERT_NE(event.getRawY(0), event.getY(0));
        // Relative values should not be modified.
        ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
        ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
    }

    // Next check that getRaw contains rotation (for compatibility) but otherwise is still
@@ -701,29 +737,38 @@ TEST_F(MotionEventTest, RawCompatTransform) {
        // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
        ui::Transform xform(ui::Transform::ROT_90, 800, 400);
        xform.set(xform.tx() + 20, xform.ty() + 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        ASSERT_EQ(700, event.getRawX(0));
        ASSERT_EQ(60, event.getRawY(0));
        ASSERT_NE(event.getRawX(0), event.getX(0));
        ASSERT_NE(event.getRawY(0), event.getY(0));
        // Relative values should be rotated but not translated.
        ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
        ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
    }

    {
        // Same as above, but check rotate-180.
        ui::Transform xform(ui::Transform::ROT_180, 400, 800);
        xform.set(xform.tx() + 20, xform.ty() + 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        ASSERT_EQ(340, event.getRawX(0));
        ASSERT_EQ(700, event.getRawY(0));
        // Relative values should be rotated but not translated.
        ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
        ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
    }

    {
        // Same as above, but check rotate-270.
        ui::Transform xform(ui::Transform::ROT_270, 800, 400);
        xform.set(xform.tx() + 20, xform.ty() + 40);
        MotionEvent event = createTouchDownEvent(60, 100, xform);
        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
        ASSERT_EQ(100, event.getRawX(0));
        ASSERT_EQ(340, event.getRawY(0));
        // Relative values should be rotated but not translated.
        ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
        ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
    }
}

+1 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ cc_defaults {
        "libui",
        "lib-platform-compat-native-api",
        "server_configurable_flags",
        "InputFlingerProperties",
    ],
    static_libs: [
        "libattestation",
+1 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ cc_defaults {
        "libutils",
        "lib-platform-compat-native-api",
        "server_configurable_flags",
        "InputFlingerProperties",
    ],
    static_libs: [
        "libattestation",
+7 −5
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ static constexpr bool DEBUG_TOUCH_OCCLUSION = true;
// Log debug messages about hover events.
#define DEBUG_HOVER 0

#include <InputFlingerProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -93,7 +94,8 @@ namespace android::inputdispatcher {
// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
static bool isPerWindowInputRotationEnabled() {
    static const bool PER_WINDOW_INPUT_ROTATION =
            base::GetBoolProperty("persist.debug.per_window_input_rotation", false);
            sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);

    return PER_WINDOW_INPUT_ROTATION;
}

@@ -319,11 +321,11 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp
                                                          int32_t inputTargetFlags) {
    if (eventEntry->type == EventEntry::Type::MOTION) {
        const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
        if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) == 0) {
        if ((motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) ||
            (motionEntry.source & AINPUT_SOURCE_CLASS_POSITION)) {
            const ui::Transform identityTransform;
            // Use identity transform for events that are not pointer events because their axes
            // values do not represent on-screen coordinates, so they should not have any window
            // transformations applied to them.
            // Use identity transform for joystick and position-based (touchpad) events because they
            // don't depend on the window transform.
            return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform,
                                                   1.0f /*globalScaleFactor*/,
                                                   inputTarget.displaySize);
Loading