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

Commit 9a53b55a authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

MotionEvent: Differentiate directional support for AXIS_ORIENTATION

We have three cases for handling AXIS_ORIENTATION:
1. Orientation is not supported by the input device, so the value for
   AXIS_ORIENTATION should always be 0, regardless of display rotation.
2. Orientation is supported, but a "direction" is not specified, like
   for touchscreens and touchpads. The orientation must be in the range
   [-pi/2, pi/2] for all display rotations.
3. Orientation is fully supported, and the value is in the range [-pi,
   pi] for all display rotations.

It is insufficient to rely on whether or not the PointerCoords has the
bit for AXIS_ORIENTATION set to determine whether the event has a valid
orientation. This is because we always skip setting values of 0 for any
axis in PointerCoords to save space during serialization.

To support these three cases, we introduce two new MotionEvent private
flags. These are flags that are not exposed to Java and to the public
APIs.

Bug: 263310669
Test: atest TouchScreenTest libinput_tests inputflinger_tests
Change-Id: Iaa38afe35b00de74fbc5eefce25191bea52c2ea6
parent 9ddc39d8
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -99,6 +99,18 @@ enum {

    /* Motion event is inconsistent with previously sent motion events. */
    AMOTION_EVENT_FLAG_TAINTED = android::os::IInputConstants::INPUT_EVENT_FLAG_TAINTED,

    /** Private flag, not used in Java. */
    AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION =
            android::os::IInputConstants::MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION,

    /** Private flag, not used in Java. */
    AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION = android::os::IInputConstants::
            MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION,

    /** Mask for all private flags that are not used in Java. */
    AMOTION_EVENT_PRIVATE_FLAG_MASK = AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION |
            AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION,
};

/**
@@ -209,8 +221,12 @@ vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy)
 * Transform an angle on the x-y plane. An angle of 0 radians corresponds to "north" or
 * pointing upwards in the negative Y direction, a positive angle points towards the right, and a
 * negative angle points towards the left.
 *
 * If the angle represents a direction that needs to be preserved, set isDirectional to true to get
 * an output range of [-pi, pi]. If the angle's direction does not need to be preserved, set
 * isDirectional to false to get an output range of [-pi/2, pi/2].
 */
float transformAngle(const ui::Transform& transform, float angleRadians);
float transformAngle(const ui::Transform& transform, float angleRadians, bool isDirectional);

/**
 * The type of the InputEvent.
@@ -462,7 +478,7 @@ struct PointerCoords {
    // axes, however the window scaling will not.
    void scale(float globalScale, float windowXScale, float windowYScale);

    void transform(const ui::Transform& transform);
    void transform(const ui::Transform& transform, int32_t motionEventFlags);

    inline float getX() const {
        return getAxisValue(AMOTION_EVENT_AXIS_X);
@@ -930,10 +946,10 @@ public:
    // relative mouse device (since SOURCE_RELATIVE_MOUSE is a non-pointer source). These methods
    // are used to apply these transformations for different axes.
    static vec2 calculateTransformedXY(uint32_t source, const ui::Transform&, const vec2& xy);
    static float calculateTransformedAxisValue(int32_t axis, uint32_t source, const ui::Transform&,
                                               const PointerCoords&);
    static PointerCoords calculateTransformedCoords(uint32_t source, const ui::Transform&,
                                                    const PointerCoords&);
    static float calculateTransformedAxisValue(int32_t axis, uint32_t source, int32_t flags,
                                               const ui::Transform&, const PointerCoords&);
    static PointerCoords calculateTransformedCoords(uint32_t source, int32_t flags,
                                                    const ui::Transform&, const PointerCoords&);
    // The rounding precision for transformed motion events.
    static constexpr float ROUNDING_PRECISION = 0.001f;

+30 −13
Original line number Diff line number Diff line
@@ -96,6 +96,19 @@ int32_t resolveActionForSplitMotionEvent(
    return AMOTION_EVENT_ACTION_DOWN;
}

float transformOrientation(const ui::Transform& transform, const PointerCoords& coords,
                           int32_t motionEventFlags) {
    if ((motionEventFlags & AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION) == 0) {
        return 0;
    }

    const bool isDirectionalAngle =
            (motionEventFlags & AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION) != 0;

    return transformAngle(transform, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
                          isDirectionalAngle);
}

} // namespace

const char* motionClassificationToString(MotionClassification classification) {
@@ -187,7 +200,7 @@ vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy)
    return roundTransformedCoords(transformedXy - transformedOrigin);
}

float transformAngle(const ui::Transform& transform, float angleRadians) {
float transformAngle(const ui::Transform& transform, float angleRadians, bool isDirectional) {
    // Construct and transform a vector oriented at the specified clockwise angle from vertical.
    // Coordinate system: down is increasing Y, right is increasing X.
    float x = sinf(angleRadians);
@@ -201,6 +214,11 @@ float transformAngle(const ui::Transform& transform, float angleRadians) {
    transformedPoint.x -= origin.x;
    transformedPoint.y -= origin.y;

    if (!isDirectional && transformedPoint.y > 0) {
        // Limit the range of atan2f to [-pi/2, pi/2] by reversing the direction of the vector.
        transformedPoint *= -1;
    }

    // Derive the transformed vector's clockwise angle from vertical.
    // The return value of atan2f is in range [-pi, pi] which conforms to the orientation API.
    return atan2f(transformedPoint.x, -transformedPoint.y);
@@ -530,7 +548,7 @@ bool PointerCoords::operator==(const PointerCoords& other) const {
    return true;
}

void PointerCoords::transform(const ui::Transform& transform) {
void PointerCoords::transform(const ui::Transform& transform, int32_t motionEventFlags) {
    const vec2 xy = transform.transform(getXYValue());
    setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
    setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);
@@ -544,9 +562,9 @@ void PointerCoords::transform(const ui::Transform& transform) {
        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));
    if ((motionEventFlags & AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION) != 0) {
        setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
                     transformOrientation(transform, *this, motionEventFlags));
    }
}

@@ -723,13 +741,13 @@ const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
                                             size_t historicalIndex) const {
    const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
    return calculateTransformedAxisValue(axis, mSource, mRawTransform, coords);
    return calculateTransformedAxisValue(axis, mSource, mFlags, mRawTransform, coords);
}

float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
                                          size_t historicalIndex) const {
    const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
    return calculateTransformedAxisValue(axis, mSource, mTransform, coords);
    return calculateTransformedAxisValue(axis, mSource, mFlags, mTransform, coords);
}

ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
@@ -787,7 +805,7 @@ 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); });
                  [&](PointerCoords& c) { c.transform(transform, mFlags); });

    if (mRawXCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION &&
        mRawYCursorPosition != AMOTION_EVENT_INVALID_CURSOR_POSITION) {
@@ -1059,7 +1077,7 @@ vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& t
}

// Keep in sync with calculateTransformedCoords.
float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source,
float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source, int32_t flags,
                                                 const ui::Transform& transform,
                                                 const PointerCoords& coords) {
    if (shouldDisregardTransformation(source)) {
@@ -1081,7 +1099,7 @@ float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source,
    }

    if (axis == AMOTION_EVENT_AXIS_ORIENTATION) {
        return transformAngle(transform, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
        return transformOrientation(transform, coords, flags);
    }

    return coords.getAxisValue(axis);
@@ -1089,7 +1107,7 @@ float MotionEvent::calculateTransformedAxisValue(int32_t axis, uint32_t source,

// Keep in sync with calculateTransformedAxisValue. This is an optimization of
// calculateTransformedAxisValue for all PointerCoords axes.
PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source,
PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source, int32_t flags,
                                                      const ui::Transform& transform,
                                                      const PointerCoords& coords) {
    if (shouldDisregardTransformation(source)) {
@@ -1109,8 +1127,7 @@ PointerCoords MotionEvent::calculateTransformedCoords(uint32_t source,
    out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, relativeXy.y);

    out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
                     transformAngle(transform,
                                    coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)));
                     transformOrientation(transform, coords, flags));

    return out;
}
+25 −0
Original line number Diff line number Diff line
@@ -115,6 +115,31 @@ interface IInputConstants
     */
    const int MOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40;

    /**
     * This flag indicates that the event has a valid value for AXIS_ORIENTATION.
     *
     * This is a private flag that is not used in Java.
     * @hide
     */
    const int MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION = 0x80;

    /**
     * This flag indicates that the pointers' AXIS_ORIENTATION can be used to precisely determine
     * the direction in which the tool is pointing. The value of the orientation axis will be in
     * the range [-pi, pi], which represents a full circle. This is usually supported by devices
     * like styluses.
     *
     * Conversely, AXIS_ORIENTATION cannot be used to tell which direction the tool is pointing
     * when this flag is not set. In this case, the axis value will have a range of [-pi/2, pi/2],
     * which represents half a circle. This is usually the case for devices like touchscreens and
     * touchpads, for which it is difficult to tell which direction along the major axis of the
     * touch ellipse the finger is pointing.
     *
     * This is a private flag that is not used in Java.
     * @hide
     */
    const int MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION = 0x100;

    /**
     * The input event was generated or modified by accessibility service.
     * Shared by both KeyEvent and MotionEvent flags, so this value should not overlap with either
+125 −14
Original line number Diff line number Diff line
@@ -26,23 +26,39 @@

namespace android {

namespace {

// Default display id.
static constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;

static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;
constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;

static constexpr auto POINTER_0_DOWN =
constexpr auto POINTER_0_DOWN =
        AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);

static constexpr auto POINTER_1_DOWN =
constexpr auto POINTER_1_DOWN =
        AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);

static constexpr auto POINTER_0_UP =
constexpr auto POINTER_0_UP =
        AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);

static constexpr auto POINTER_1_UP =
constexpr auto POINTER_1_UP =
        AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);

std::array<float, 9> asFloat9(const ui::Transform& t) {
    std::array<float, 9> mat{};
    mat[0] = t[0][0];
    mat[1] = t[1][0];
    mat[2] = t[2][0];
    mat[3] = t[0][1];
    mat[4] = t[1][1];
    mat[5] = t[2][1];
    mat[6] = t[0][2];
    mat[7] = t[1][2];
    mat[8] = t[2][2];
    return mat;
}

class BaseTest : public testing::Test {
protected:
    static constexpr std::array<uint8_t, 32> HMAC = {0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10,
@@ -50,6 +66,8 @@ protected:
                                                     22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
};

} // namespace

// --- PointerCoordsTest ---

class PointerCoordsTest : public BaseTest {
@@ -344,13 +362,15 @@ void MotionEventTest::SetUp() {
}

void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
    const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
            AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION |
            AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION;
    event->initialize(mId, 2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, HMAC,
                      AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
                      AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
                      MotionClassification::NONE, mTransform, 2.0f, 2.1f,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      mRawTransform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2,
                      mPointerProperties, mSamples[0].pointerCoords);
                      AMOTION_EVENT_ACTION_MOVE, 0, flags, AMOTION_EVENT_EDGE_FLAG_TOP,
                      AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE,
                      mTransform, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, mRawTransform, ARBITRARY_DOWN_TIME,
                      ARBITRARY_EVENT_TIME, 2, mPointerProperties, mSamples[0].pointerCoords);
    event->addSample(ARBITRARY_EVENT_TIME + 1, mSamples[1].pointerCoords);
    event->addSample(ARBITRARY_EVENT_TIME + 2, mSamples[2].pointerCoords);
}
@@ -364,7 +384,10 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
    ASSERT_EQ(DISPLAY_ID, event->getDisplayId());
    EXPECT_EQ(HMAC, event->getHmac());
    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
    ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
    ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
                      AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION |
                      AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION,
              event->getFlags());
    ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
    ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
@@ -799,8 +822,10 @@ TEST_F(MotionEventTest, Transform) {
    }
    MotionEvent event;
    ui::Transform identityTransform;
    const int32_t flags = AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION |
            AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION;
    event.initialize(InputEvent::nextId(), /*deviceId=*/0, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
                     INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, /*actionButton=*/0, /*flags=*/0,
                     INVALID_HMAC, AMOTION_EVENT_ACTION_MOVE, /*actionButton=*/0, flags,
                     AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, /*buttonState=*/0,
                     MotionClassification::NONE, identityTransform, /*xPrecision=*/0,
                     /*yPrecision=*/0, /*xCursorPosition=*/3 + RADIUS, /*yCursorPosition=*/2,
@@ -1087,4 +1112,90 @@ TEST_F(MotionEventTest, CoordinatesAreRoundedAppropriately) {
    ASSERT_EQ(EXPECTED.y, event.getYCursorPosition());
}

TEST_F(MotionEventTest, InvalidOrientationNotRotated) {
    // This touch event does not have a value for AXIS_ORIENTATION, and the flags are implicitly
    // set to 0. The transform is set to a 90-degree rotation.
    MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
                                .downTime(ARBITRARY_DOWN_TIME)
                                .pointer(PointerBuilder(/*id=*/4, ToolType::FINGER).x(4).y(4))
                                .transform(ui::Transform(ui::Transform::ROT_90, 100, 100))
                                .rawTransform(ui::Transform(ui::Transform::FLIP_H, 50, 50))
                                .build();
    ASSERT_EQ(event.getOrientation(/*pointerIndex=*/0), 0.f);
    event.transform(asFloat9(ui::Transform(ui::Transform::ROT_90, 100, 100)));
    ASSERT_EQ(event.getOrientation(/*pointerIndex=*/0), 0.f);
    event.transform(asFloat9(ui::Transform(ui::Transform::ROT_180, 100, 100)));
    ASSERT_EQ(event.getOrientation(/*pointerIndex=*/0), 0.f);
    event.applyTransform(asFloat9(ui::Transform(ui::Transform::ROT_270, 100, 100)));
    ASSERT_EQ(event.getOrientation(/*pointerIndex=*/0), 0.f);
}

TEST_F(MotionEventTest, ValidZeroOrientationRotated) {
    // This touch events will implicitly have a value of 0 for its AXIS_ORIENTATION.
    auto builder = MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
                           .downTime(ARBITRARY_DOWN_TIME)
                           .pointer(PointerBuilder(/*id=*/4, ToolType::FINGER).x(4).y(4))
                           .transform(ui::Transform(ui::Transform::ROT_90, 100, 100))
                           .rawTransform(ui::Transform(ui::Transform::FLIP_H, 50, 50))
                           .addFlag(AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION);
    MotionEvent nonDirectionalEvent = builder.build();
    MotionEvent directionalEvent =
            builder.addFlag(AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION).build();

    // The angle is rotated by the initial transform, a 90-degree rotation.
    ASSERT_NEAR(fabs(nonDirectionalEvent.getOrientation(/*pointerIndex=*/0)), M_PI_2, EPSILON);
    ASSERT_NEAR(directionalEvent.getOrientation(/*pointerIndex=*/0), M_PI_2, EPSILON);

    nonDirectionalEvent.transform(asFloat9(ui::Transform(ui::Transform::ROT_90, 100, 100)));
    directionalEvent.transform(asFloat9(ui::Transform(ui::Transform::ROT_90, 100, 100)));
    ASSERT_NEAR(nonDirectionalEvent.getOrientation(/*pointerIndex=*/0), 0.f, EPSILON);
    ASSERT_NEAR(fabs(directionalEvent.getOrientation(/*pointerIndex=*/0)), M_PI, EPSILON);

    nonDirectionalEvent.transform(asFloat9(ui::Transform(ui::Transform::ROT_180, 100, 100)));
    directionalEvent.transform(asFloat9(ui::Transform(ui::Transform::ROT_180, 100, 100)));
    ASSERT_NEAR(nonDirectionalEvent.getOrientation(/*pointerIndex=*/0), 0.f, EPSILON);
    ASSERT_NEAR(directionalEvent.getOrientation(/*pointerIndex=*/0), 0.f, EPSILON);

    nonDirectionalEvent.applyTransform(asFloat9(ui::Transform(ui::Transform::ROT_270, 100, 100)));
    directionalEvent.applyTransform(asFloat9(ui::Transform(ui::Transform::ROT_270, 100, 100)));
    ASSERT_NEAR(fabs(nonDirectionalEvent.getOrientation(/*pointerIndex=*/0)), M_PI_2, EPSILON);
    ASSERT_NEAR(directionalEvent.getOrientation(/*pointerIndex=*/0), -M_PI_2, EPSILON);
}

TEST_F(MotionEventTest, ValidNonZeroOrientationRotated) {
    const float initial = 1.f;
    auto builder = MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
                           .downTime(ARBITRARY_DOWN_TIME)
                           .pointer(PointerBuilder(/*id=*/4, ToolType::FINGER)
                                            .x(4)
                                            .y(4)
                                            .axis(AMOTION_EVENT_AXIS_ORIENTATION, initial))
                           .transform(ui::Transform(ui::Transform::ROT_90, 100, 100))
                           .rawTransform(ui::Transform(ui::Transform::FLIP_H, 50, 50))
                           .addFlag(AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION);

    MotionEvent nonDirectionalEvent = builder.build();
    MotionEvent directionalEvent =
            builder.addFlag(AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION).build();

    // The angle is rotated by the initial transform, a 90-degree rotation.
    ASSERT_NEAR(nonDirectionalEvent.getOrientation(/*pointerIndex=*/0), initial - M_PI_2, EPSILON);
    ASSERT_NEAR(directionalEvent.getOrientation(/*pointerIndex=*/0), initial + M_PI_2, EPSILON);

    nonDirectionalEvent.transform(asFloat9(ui::Transform(ui::Transform::ROT_90, 100, 100)));
    directionalEvent.transform(asFloat9(ui::Transform(ui::Transform::ROT_90, 100, 100)));
    ASSERT_NEAR(nonDirectionalEvent.getOrientation(/*pointerIndex=*/0), initial, EPSILON);
    ASSERT_NEAR(directionalEvent.getOrientation(/*pointerIndex=*/0), initial - M_PI, EPSILON);

    nonDirectionalEvent.transform(asFloat9(ui::Transform(ui::Transform::ROT_180, 100, 100)));
    directionalEvent.transform(asFloat9(ui::Transform(ui::Transform::ROT_180, 100, 100)));
    ASSERT_NEAR(nonDirectionalEvent.getOrientation(/*pointerIndex=*/0), initial, EPSILON);
    ASSERT_NEAR(directionalEvent.getOrientation(/*pointerIndex=*/0), initial, EPSILON);

    nonDirectionalEvent.applyTransform(asFloat9(ui::Transform(ui::Transform::ROT_270, 100, 100)));
    directionalEvent.applyTransform(asFloat9(ui::Transform(ui::Transform::ROT_270, 100, 100)));
    ASSERT_NEAR(nonDirectionalEvent.getOrientation(/*pointerIndex=*/0), initial - M_PI_2, EPSILON);
    ASSERT_NEAR(directionalEvent.getOrientation(/*pointerIndex=*/0), initial - M_PI_2, EPSILON);
}

} // namespace android
+3 −1
Original line number Diff line number Diff line
@@ -96,7 +96,9 @@ PublishMotionArgs::PublishMotionArgs(int32_t inAction, nsecs_t inDownTime,
    hmac = {0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};

    flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
    flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
            AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION |
            AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION;
    if (action == AMOTION_EVENT_ACTION_CANCEL) {
        flags |= AMOTION_EVENT_FLAG_CANCELED;
    }
Loading