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

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

Merge changes from topic "move-input-rotation-to-native"

* changes:
  InputDispatcherPolicy: Transform incoming/outgoing events
  TouchInputMapper: Block touches outside logical display
parents 398640bc 81420cc4
Loading
Loading
Loading
Loading
+0 −13
Original line number Diff line number Diff line
@@ -20,10 +20,8 @@
#include <attestation/HmacKeyManager.h>
#include <cutils/compiler.h>
#include <inttypes.h>
#include <limits.h>
#include <string.h>

#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <gui/constants.h>
#include <input/Input.h>
@@ -43,15 +41,6 @@ namespace android {

namespace {

// When per-window-input-rotation is enabled, InputFlinger works in the un-rotated display
// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
bool isPerWindowInputRotationEnabled() {
    static const bool PER_WINDOW_INPUT_ROTATION =
            base::GetBoolProperty("persist.debug.per_window_input_rotation", false);

    return PER_WINDOW_INPUT_ROTATION;
}

float transformAngle(const ui::Transform& transform, float angleRadians) {
    // Construct and transform a vector oriented at the specified clockwise angle from vertical.
    // Coordinate system: down is increasing Y, right is increasing X.
@@ -511,8 +500,6 @@ float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
                                             size_t historicalIndex) const {
    const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);

    if (!isPerWindowInputRotationEnabled()) return coords->getAxisValue(axis);

    if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
        // For compatibility, convert raw coordinates into logical display space.
        const vec2 xy = shouldDisregardTranslation(mSource)
+0 −22
Original line number Diff line number Diff line
@@ -231,36 +231,14 @@ protected:
    static constexpr float RAW_X_OFFSET = 12;
    static constexpr float RAW_Y_OFFSET = -41.1;

    static const std::optional<bool> INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE;

    int32_t mId;
    ui::Transform mTransform;
    ui::Transform mRawTransform;

    void SetUp() override;
    void TearDown() override;

    void initializeEventWithHistory(MotionEvent* event);
    void assertEqualsEventWithHistory(const MotionEvent* event);
};

const std::optional<bool> MotionEventTest::INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE =
        !base::GetProperty("persist.debug.per_window_input_rotation", "").empty()
        ? std::optional(base::GetBoolProperty("persist.debug.per_window_input_rotation", false))
        : std::nullopt;

void MotionEventTest::SetUp() {
    // Ensure per_window_input_rotation is enabled.
    base::SetProperty("persist.debug.per_window_input_rotation", "true");
}

void MotionEventTest::TearDown() {
    const auto val = INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE.has_value()
            ? (*INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE ? "true" : "false")
            : "";
    base::SetProperty("persist.debug.per_window_input_rotation", val);
}

void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
    mId = InputEvent::nextId();
    mTransform.set({X_SCALE, 0, X_OFFSET, 0, Y_SCALE, Y_OFFSET, 0, 0, 1});
+51 −3
Original line number Diff line number Diff line
@@ -524,6 +524,16 @@ bool isConnectionResponsive(const Connection& connection) {
    return true;
}

bool isFromSource(uint32_t source, uint32_t test) {
    return (source & test) == test;
}

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;
}

} // namespace

// --- InputDispatcher ---
@@ -3962,15 +3972,19 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
        mLock.lock();

        if (shouldSendMotionToInputFilterLocked(args)) {
            ui::Transform displayTransform;
            if (const auto it = mDisplayInfos.find(args->displayId); it != mDisplayInfos.end()) {
                displayTransform = it->second.transform;
            }

            mLock.unlock();

            MotionEvent event;
            ui::Transform identityTransform;
            event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
                             args->action, args->actionButton, args->flags, args->edgeFlags,
                             args->metaState, args->buttonState, args->classification,
                             identityTransform, args->xPrecision, args->yPrecision,
                             args->xCursorPosition, args->yCursorPosition, identityTransform,
                             displayTransform, args->xPrecision, args->yPrecision,
                             args->xCursorPosition, args->yCursorPosition, displayTransform,
                             args->downTime, args->eventTime, args->pointerCount,
                             args->pointerProperties, args->pointerCoords);

@@ -4220,6 +4234,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
                                                  pointerProperties, samplePointerCoords,
                                                  motionEvent.getXOffset(),
                                                  motionEvent.getYOffset());
            transformMotionEntryForInjectionLocked(*injectedEntry);
            injectedEntries.push(std::move(injectedEntry));
            for (size_t i = motionEvent.getHistorySize(); i > 0; i--) {
                sampleEventTimes += 1;
@@ -4241,6 +4256,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
                                                      uint32_t(pointerCount), pointerProperties,
                                                      samplePointerCoords, motionEvent.getXOffset(),
                                                      motionEvent.getYOffset());
                transformMotionEntryForInjectionLocked(*nextInjectedEntry);
                injectedEntries.push(std::move(nextInjectedEntry));
            }
            break;
@@ -4404,6 +4420,38 @@ 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;
    }

    // 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();

    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);
    }
}

void InputDispatcher::incrementPendingForegroundDispatches(EventEntry& entry) {
    InjectionState* injectionState = entry.injectionState;
    if (injectionState) {
+1 −0
Original line number Diff line number Diff line
@@ -280,6 +280,7 @@ private:
    bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
    void setInjectionResult(EventEntry& entry,
                            android::os::InputEventInjectionResult injectionResult);
    void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock);

    std::condition_variable mInjectionSyncFinished;
    void incrementPendingForegroundDispatches(EventEntry& entry);
+24 −9
Original line number Diff line number Diff line
@@ -749,16 +749,17 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
            mPhysicalLeft = naturalPhysicalLeft;
            mPhysicalTop = naturalPhysicalTop;

            if (isPerWindowInputRotationEnabled()) {
                // When per-window input rotation is enabled, InputReader works in the display
                // space, so the surface bounds are the bounds of the display device.
                const int32_t oldSurfaceWidth = mRawSurfaceWidth;
                const int32_t oldSurfaceHeight = mRawSurfaceHeight;
            mRawSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
            mRawSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
            mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
            mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
            mSurfaceRight = mSurfaceLeft + naturalLogicalWidth;
            mSurfaceBottom = mSurfaceTop + naturalLogicalHeight;

            if (isPerWindowInputRotationEnabled()) {
                mRawSurfaceWidth = naturalDeviceWidth;
                mRawSurfaceHeight = naturalDeviceHeight;
                mSurfaceLeft = 0;
                mSurfaceTop = 0;
                mSurfaceRight = mRawSurfaceWidth;
                mSurfaceBottom = mRawSurfaceHeight;
                // When per-window input rotation is enabled, InputReader works in the un-rotated
                // coordinate space, so we don't need to do anything if the device is already
                // orientation-aware. If the device is not orientation-aware, then we need to apply
@@ -774,6 +775,14 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
                        mRawSurfaceWidth == oldSurfaceWidth &&
                        mRawSurfaceHeight == oldSurfaceHeight && viewportOrientationChanged;
            } else {
                mRawSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
                mRawSurfaceHeight =
                        naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
                mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
                mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
                mSurfaceRight = mSurfaceLeft + naturalLogicalWidth;
                mSurfaceBottom = mSurfaceTop + naturalLogicalHeight;

                mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation
                                                                   : DISPLAY_ORIENTATION_0;
            }
@@ -3772,6 +3781,12 @@ bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
    const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale;
    const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale;

    if (isPerWindowInputRotationEnabled()) {
        return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
                xScaled >= mPhysicalLeft && xScaled <= (mPhysicalLeft + mPhysicalWidth) &&
                y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
                yScaled >= mPhysicalTop && yScaled <= (mPhysicalTop + mPhysicalHeight);
    }
    return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
            xScaled >= mSurfaceLeft && xScaled <= mSurfaceRight &&
            y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
Loading