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

Commit 33a10a64 authored by Arpit Singh's avatar Arpit Singh
Browse files

Cancel ongoing touchpad move gesture if user starts typing

To improve touchpad palm rejection while typing, this change will cancel
any ongoing touchpad move gesture if user starts typing on keyboard. In
this change we:
1. Introduce a new flag to gaurd this change
2. Add behaviour to cancel ongoing gesture

Bug: 301055381
Test: atest inputflinger_tests
Change-Id: I0830cb24f2046380e140cddd71096b8a611c51de
parent 639a2f2f
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -52,7 +52,14 @@ flag {
flag {
  name: "enable_touchpad_typing_palm_rejection"
  namespace: "input"
  description: "Enable additional palm rejection on touchpad while typing"
  description: "Enabling additional touchpad palm rejection will disable the tap to click while the user is typing on a physical keyboard"
  bug: "301055381"
}

flag {
  name: "enable_v2_touchpad_typing_palm_rejection"
  namespace: "input"
  description: "In addition to touchpad palm rejection v1, v2 will also cancel ongoing move gestures while typing and add delay in re-enabling the tap to click."
  bug: "301055381"
}

+4 −1
Original line number Diff line number Diff line
@@ -449,6 +449,9 @@ std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent* rawEvent) {
    if (mPointerCaptured) {
        return mCapturedEventConverter.process(*rawEvent);
    }
    if (mMotionAccumulator.getActiveSlotsCount() == 0) {
        mGestureStartTime = rawEvent->when;
    }
    std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent);
    if (state) {
        updatePalmDetectionMetrics();
@@ -514,7 +517,7 @@ std::list<NotifyArgs> TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t
    if (mDisplayId) {
        MetricsAccumulator& metricsAccumulator = MetricsAccumulator::getInstance();
        for (Gesture& gesture : mGesturesToProcess) {
            out += mGestureConverter.handleGesture(when, readTime, gesture);
            out += mGestureConverter.handleGesture(when, readTime, mGestureStartTime, gesture);
            metricsAccumulator.processGesture(mMetricsId, gesture);
        }
    }
+2 −0
Original line number Diff line number Diff line
@@ -113,6 +113,8 @@ private:
    // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e.
    // std::nullopt), all events will be ignored.
    std::optional<int32_t> mDisplayId;

    nsecs_t mGestureStartTime{0};
};

} // namespace android
+49 −17
Original line number Diff line number Diff line
@@ -35,8 +35,14 @@ namespace android {

namespace {

// This will disable the tap to click while the user is typing on a physical keyboard
const bool ENABLE_TOUCHPAD_PALM_REJECTION = input_flags::enable_touchpad_typing_palm_rejection();

// In addition to v1, v2 will also cancel ongoing move gestures while typing and add delay in
// re-enabling the tap to click.
const bool ENABLE_TOUCHPAD_PALM_REJECTION_V2 =
        input_flags::enable_v2_touchpad_typing_palm_rejection();

uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) {
    switch (gesturesButton) {
        case GESTURES_BUTTON_LEFT:
@@ -131,6 +137,7 @@ void GestureConverter::populateMotionRanges(InputDeviceInfo& info) const {
}

std::list<NotifyArgs> GestureConverter::handleGesture(nsecs_t when, nsecs_t readTime,
                                                      nsecs_t gestureStartTime,
                                                      const Gesture& gesture) {
    if (!mDisplayId) {
        // Ignore gestures when there is no target display configured.
@@ -139,13 +146,13 @@ std::list<NotifyArgs> GestureConverter::handleGesture(nsecs_t when, nsecs_t read

    switch (gesture.type) {
        case kGestureTypeMove:
            return {handleMove(when, readTime, gesture)};
            return handleMove(when, readTime, gestureStartTime, gesture);
        case kGestureTypeButtonsChange:
            return handleButtonsChange(when, readTime, gesture);
        case kGestureTypeScroll:
            return handleScroll(when, readTime, gesture);
        case kGestureTypeFling:
            return handleFling(when, readTime, gesture);
            return handleFling(when, readTime, gestureStartTime, gesture);
        case kGestureTypeSwipe:
            return handleMultiFingerSwipe(when, readTime, 3, gesture.details.swipe.dx,
                                          gesture.details.swipe.dy);
@@ -162,18 +169,40 @@ std::list<NotifyArgs> GestureConverter::handleGesture(nsecs_t when, nsecs_t read
    }
}

NotifyMotionArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime,
std::list<NotifyArgs> GestureConverter::handleMove(nsecs_t when, nsecs_t readTime,
                                                   nsecs_t gestureStartTime,
                                                   const Gesture& gesture) {
    float deltaX = gesture.details.move.dx;
    float deltaY = gesture.details.move.dy;
    if (ENABLE_TOUCHPAD_PALM_REJECTION && (std::abs(deltaX) > 0 || std::abs(deltaY) > 0)) {
        enableTapToClick();
    if (ENABLE_TOUCHPAD_PALM_REJECTION_V2) {
        bool wasHoverCancelled = mIsHoverCancelled;
        // Gesture will be cancelled if it started before the user started typing and
        // there is a active IME connection.
        mIsHoverCancelled = gestureStartTime <= mReaderContext.getLastKeyDownTimestamp() &&
                mReaderContext.getPolicy()->isInputMethodConnectionActive();

        if (!wasHoverCancelled && mIsHoverCancelled) {
            // This is the first event of the cancelled gesture, we won't return because we need to
            // generate a HOVER_EXIT event
            mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
        } else if (mIsHoverCancelled) {
            return {};
        }
    }

    rotateDelta(mOrientation, &deltaX, &deltaY);

    // Update the cursor, and enable tap to click if the gesture is not cancelled
    if (!mIsHoverCancelled) {
        // handleFling calls hoverMove with zero delta on FLING_TAP_DOWN. Don't enable tap to click
        // for this case as subsequent handleButtonsChange may choose to ignore this tap.
        if (ENABLE_TOUCHPAD_PALM_REJECTION && (std::abs(deltaX) > 0 || std::abs(deltaY) > 0)) {
            enableTapToClick();
        }
        mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
        mPointerController->move(deltaX, deltaY);
        mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
    }

    const auto [xCursorPosition, yCursorPosition] =
            mEnablePointerChoreographer ? FloatPoint{0, 0} : mPointerController->getPosition();
@@ -187,10 +216,12 @@ NotifyMotionArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime,
    const bool down = isPointerDown(mButtonState);
    coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);

    const int32_t action = down ? AMOTION_EVENT_ACTION_MOVE : AMOTION_EVENT_ACTION_HOVER_MOVE;
    return makeMotionArgs(when, readTime, action, /* actionButton= */ 0, mButtonState,
    const int32_t action = mIsHoverCancelled
            ? AMOTION_EVENT_ACTION_HOVER_EXIT
            : (down ? AMOTION_EVENT_ACTION_MOVE : AMOTION_EVENT_ACTION_HOVER_MOVE);
    return {makeMotionArgs(when, readTime, action, /* actionButton= */ 0, mButtonState,
                           /* pointerCount= */ 1, mFingerProps.data(), &coords, xCursorPosition,
                          yCursorPosition);
                           yCursorPosition)};
}

std::list<NotifyArgs> GestureConverter::handleButtonsChange(nsecs_t when, nsecs_t readTime,
@@ -348,6 +379,7 @@ std::list<NotifyArgs> GestureConverter::handleScroll(nsecs_t when, nsecs_t readT
}

std::list<NotifyArgs> GestureConverter::handleFling(nsecs_t when, nsecs_t readTime,
                                                    nsecs_t gestureStartTime,
                                                    const Gesture& gesture) {
    switch (gesture.details.fling.fling_state) {
        case GESTURES_FLING_START:
@@ -369,10 +401,10 @@ std::list<NotifyArgs> GestureConverter::handleFling(nsecs_t when, nsecs_t readTi
                if (!mReaderContext.isPreventingTouchpadTaps()) {
                    enableTapToClick();
                }
                return {handleMove(when, readTime,
                return handleMove(when, readTime, gestureStartTime,
                                  Gesture(kGestureMove, gesture.start_time, gesture.end_time,
                                          /*dx=*/0.f,
                                           /*dy=*/0.f))};
                                          /*dy=*/0.f));
            }
            break;
        default:
+6 −2
Original line number Diff line number Diff line
@@ -53,10 +53,12 @@ public:
    void populateMotionRanges(InputDeviceInfo& info) const;

    [[nodiscard]] std::list<NotifyArgs> handleGesture(nsecs_t when, nsecs_t readTime,
                                                      nsecs_t gestureStartTime,
                                                      const Gesture& gesture);

private:
    [[nodiscard]] NotifyMotionArgs handleMove(nsecs_t when, nsecs_t readTime,
    [[nodiscard]] std::list<NotifyArgs> handleMove(nsecs_t when, nsecs_t readTime,
                                                   nsecs_t gestureStartTime,
                                                   const Gesture& gesture);
    [[nodiscard]] std::list<NotifyArgs> handleButtonsChange(nsecs_t when, nsecs_t readTime,
                                                            const Gesture& gesture);
@@ -64,6 +66,7 @@ private:
    [[nodiscard]] std::list<NotifyArgs> handleScroll(nsecs_t when, nsecs_t readTime,
                                                     const Gesture& gesture);
    [[nodiscard]] std::list<NotifyArgs> handleFling(nsecs_t when, nsecs_t readTime,
                                                    nsecs_t gestureStartTime,
                                                    const Gesture& gesture);
    [[nodiscard]] NotifyMotionArgs endScroll(nsecs_t when, nsecs_t readTime);

@@ -83,6 +86,7 @@ private:
                                    float yCursorPosition);

    void enableTapToClick();
    bool mIsHoverCancelled{false};

    const int32_t mDeviceId;
    InputReaderContext& mReaderContext;
Loading