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

Commit 3a0b26df authored by Harry Cutts's avatar Harry Cutts Committed by Automerger Merge Worker
Browse files

Merge changes Iefe84120,I482cce6d into udc-dev am: b7db5076 am: bf5dddca

parents 1c11be2a bf5dddca
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ filegroup {
        "Macros.cpp",
        "TouchVideoDevice.cpp",
        "controller/PeripheralController.cpp",
        "mapper/CapturedTouchpadEventConverter.cpp",
        "mapper/CursorInputMapper.cpp",
        "mapper/ExternalStylusInputMapper.cpp",
        "mapper/InputMapper.cpp",
+310 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CapturedTouchpadEventConverter.h"

#include <sstream>

#include <android-base/stringprintf.h>
#include <gui/constants.h>
#include <input/PrintTools.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>

namespace android {

namespace {

int32_t actionWithIndex(int32_t action, int32_t index) {
    return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
}

template <typename T>
size_t firstUnmarkedBit(T set) {
    // TODO: replace with std::countr_one from <bit> when that's available
    LOG_ALWAYS_FATAL_IF(set.all());
    size_t i = 0;
    while (set.test(i)) {
        i++;
    }
    return i;
}

} // namespace

CapturedTouchpadEventConverter::CapturedTouchpadEventConverter(
        InputReaderContext& readerContext, const InputDeviceContext& deviceContext,
        MultiTouchMotionAccumulator& motionAccumulator, int32_t deviceId)
      : mDeviceId(deviceId),
        mReaderContext(readerContext),
        mDeviceContext(deviceContext),
        mMotionAccumulator(motionAccumulator),
        mHasTouchMinor(deviceContext.hasAbsoluteAxis(ABS_MT_TOUCH_MINOR)),
        mHasToolMinor(deviceContext.hasAbsoluteAxis(ABS_MT_WIDTH_MINOR)) {
    RawAbsoluteAxisInfo orientationInfo;
    deviceContext.getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &orientationInfo);
    if (orientationInfo.valid) {
        if (orientationInfo.maxValue > 0) {
            mOrientationScale = M_PI_2 / orientationInfo.maxValue;
        } else if (orientationInfo.minValue < 0) {
            mOrientationScale = -M_PI_2 / orientationInfo.minValue;
        }
    }

    // TODO(b/275369880): support touch.pressure.calibration and .scale properties when captured.
    RawAbsoluteAxisInfo pressureInfo;
    deviceContext.getAbsoluteAxisInfo(ABS_MT_PRESSURE, &pressureInfo);
    if (pressureInfo.valid && pressureInfo.maxValue > 0) {
        mPressureScale = 1.0 / pressureInfo.maxValue;
    }

    RawAbsoluteAxisInfo touchMajorInfo, toolMajorInfo;
    deviceContext.getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &touchMajorInfo);
    deviceContext.getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &toolMajorInfo);
    mHasTouchMajor = touchMajorInfo.valid;
    mHasToolMajor = toolMajorInfo.valid;
    if (mHasTouchMajor && touchMajorInfo.maxValue != 0) {
        mSizeScale = 1.0f / touchMajorInfo.maxValue;
    } else if (mHasToolMajor && toolMajorInfo.maxValue != 0) {
        mSizeScale = 1.0f / toolMajorInfo.maxValue;
    }
}

std::string CapturedTouchpadEventConverter::dump() const {
    std::stringstream out;
    out << "Orientation scale: " << mOrientationScale << "\n";
    out << "Pressure scale: " << mPressureScale << "\n";
    out << "Size scale: " << mSizeScale << "\n";

    out << "Dimension axes:";
    if (mHasTouchMajor) out << " touch major";
    if (mHasTouchMinor) out << ", touch minor";
    if (mHasToolMajor) out << ", tool major";
    if (mHasToolMinor) out << ", tool minor";
    out << "\n";

    out << "Down time: " << mDownTime << "\n";
    out << StringPrintf("Button state: 0x%08x\n", mButtonState);

    out << StringPrintf("Pointer IDs in use: %s\n", mPointerIdsInUse.to_string().c_str());

    out << "Pointer IDs for slot numbers:\n";
    out << addLinePrefix(dumpMap(mPointerIdForSlotNumber), "  ") << "\n";
    return out.str();
}

void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const {
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR);
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR);
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR);
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MINOR, ABS_MT_WIDTH_MINOR);

    RawAbsoluteAxisInfo pressureInfo;
    mDeviceContext.getAbsoluteAxisInfo(ABS_MT_PRESSURE, &pressureInfo);
    if (pressureInfo.valid) {
        info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, SOURCE, 0, 1, 0, 0, 0);
    }

    RawAbsoluteAxisInfo orientationInfo;
    mDeviceContext.getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &orientationInfo);
    if (orientationInfo.valid && (orientationInfo.maxValue > 0 || orientationInfo.minValue < 0)) {
        info.addMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, SOURCE, -M_PI_2, M_PI_2, 0, 0, 0);
    }

    if (mHasTouchMajor || mHasToolMajor) {
        info.addMotionRange(AMOTION_EVENT_AXIS_SIZE, SOURCE, 0, 1, 0, 0, 0);
    }
}

void CapturedTouchpadEventConverter::tryAddRawMotionRange(InputDeviceInfo& deviceInfo,
                                                          int32_t androidAxis,
                                                          int32_t evdevAxis) const {
    RawAbsoluteAxisInfo info;
    mDeviceContext.getAbsoluteAxisInfo(evdevAxis, &info);
    if (info.valid) {
        deviceInfo.addMotionRange(androidAxis, SOURCE, info.minValue, info.maxValue, info.flat,
                                  info.fuzz, info.resolution);
    }
}

void CapturedTouchpadEventConverter::reset() {
    mCursorButtonAccumulator.reset(mDeviceContext);
    mDownTime = 0;
    mPointerIdsInUse.reset();
    mPointerIdForSlotNumber.clear();
}

std::list<NotifyArgs> CapturedTouchpadEventConverter::process(const RawEvent& rawEvent) {
    std::list<NotifyArgs> out;
    if (rawEvent.type == EV_SYN && rawEvent.code == SYN_REPORT) {
        out = sync(rawEvent.when, rawEvent.readTime);
        mMotionAccumulator.finishSync();
    }

    mCursorButtonAccumulator.process(&rawEvent);
    mMotionAccumulator.process(&rawEvent);
    return out;
}

std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t readTime) {
    std::list<NotifyArgs> out;
    std::vector<PointerCoords> coords;
    std::vector<PointerProperties> properties;
    std::map<size_t, size_t> coordsIndexForSlotNumber;

    // For all the touches that were already down, send a MOVE event with their updated coordinates.
    // A convention of the MotionEvent API is that pointer coordinates in UP events match the
    // pointer's coordinates from the previous MOVE, so we still include touches here even if
    // they've been lifted in this evdev frame.
    if (!mPointerIdForSlotNumber.empty()) {
        for (const auto [slotNumber, pointerId] : mPointerIdForSlotNumber) {
            // Note that we don't check whether the touch has actually moved — it's rare for a touch
            // to stay perfectly still between frames, and if it does the worst that can happen is
            // an extra MOVE event, so it's not worth the overhead of checking for changes.
            coordsIndexForSlotNumber[slotNumber] = coords.size();
            coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
            properties.push_back({.id = pointerId, .toolType = ToolType::FINGER});
        }
        out.push_back(
                makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties));
    }

    std::vector<size_t> upSlots, downSlots;
    for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) {
        const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(i);
        // Some touchpads continue to report contacts even after they've identified them as palms.
        // We don't currently have a way to mark these as palms when reporting to apps, so don't
        // report them at all.
        const bool isInUse = slot.isInUse() && slot.getToolType() != ToolType::PALM;
        const bool wasInUse = mPointerIdForSlotNumber.find(i) != mPointerIdForSlotNumber.end();
        if (isInUse && !wasInUse) {
            downSlots.push_back(i);
        } else if (!isInUse && wasInUse) {
            upSlots.push_back(i);
        }
    }

    // For any touches that were lifted, send UP or POINTER_UP events.
    for (size_t slotNumber : upSlots) {
        const size_t indexToRemove = coordsIndexForSlotNumber.at(slotNumber);
        const bool cancel = mMotionAccumulator.getSlot(slotNumber).getToolType() == ToolType::PALM;
        int32_t action;
        if (coords.size() == 1) {
            action = cancel ? AMOTION_EVENT_ACTION_CANCEL : AMOTION_EVENT_ACTION_UP;
        } else {
            action = actionWithIndex(AMOTION_EVENT_ACTION_POINTER_UP, indexToRemove);
        }
        out.push_back(makeMotionArgs(when, readTime, action, coords, properties, /*actionButton=*/0,
                                     /*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));

        freePointerIdForSlot(slotNumber);
        coords.erase(coords.begin() + indexToRemove);
        properties.erase(properties.begin() + indexToRemove);
        // Now that we've removed some coords and properties, we might have to update the slot
        // number to coords index mapping.
        coordsIndexForSlotNumber.erase(slotNumber);
        for (auto& [_, index] : coordsIndexForSlotNumber) {
            if (index > indexToRemove) {
                index--;
            }
        }
    }

    // For new touches, send DOWN or POINTER_DOWN events.
    for (size_t slotNumber : downSlots) {
        const size_t coordsIndex = coords.size();
        const int32_t action = coords.empty()
                ? AMOTION_EVENT_ACTION_DOWN
                : actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex);

        coordsIndexForSlotNumber[slotNumber] = coordsIndex;
        coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
        properties.push_back(
                {.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER});

        out.push_back(makeMotionArgs(when, readTime, action, coords, properties));
    }

    const uint32_t newButtonState = mCursorButtonAccumulator.getButtonState();
    for (uint32_t button = 1; button <= AMOTION_EVENT_BUTTON_FORWARD; button <<= 1) {
        if (newButtonState & button && !(mButtonState & button)) {
            mButtonState |= button;
            out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_PRESS, coords,
                                         properties, /*actionButton=*/button));
        } else if (!(newButtonState & button) && mButtonState & button) {
            mButtonState &= ~button;
            out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
                                         coords, properties, /*actionButton=*/button));
        }
    }
    return out;
}

NotifyMotionArgs CapturedTouchpadEventConverter::makeMotionArgs(
        nsecs_t when, nsecs_t readTime, int32_t action, const std::vector<PointerCoords>& coords,
        const std::vector<PointerProperties>& properties, int32_t actionButton, int32_t flags) {
    LOG_ALWAYS_FATAL_IF(coords.size() != properties.size(),
                        "Mismatched coords and properties arrays.");
    return NotifyMotionArgs(mReaderContext.getNextId(), when, readTime, mDeviceId, SOURCE,
                            ADISPLAY_ID_NONE, /*policyFlags=*/POLICY_FLAG_WAKE, action,
                            /*actionButton=*/actionButton, flags,
                            mReaderContext.getGlobalMetaState(), mButtonState,
                            MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, coords.size(),
                            properties.data(), coords.data(), /*xPrecision=*/1.0f,
                            /*yPrecision=*/1.0f, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                            AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{});
}

PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(
        const MultiTouchMotionAccumulator::Slot& slot) const {
    PointerCoords coords;
    coords.clear();
    coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX());
    coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY());
    coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor());
    coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor());
    coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor());
    coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, slot.getToolMinor());
    coords.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, slot.getOrientation() * mOrientationScale);
    coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, slot.getPressure() * mPressureScale);
    float size = 0;
    // TODO(b/275369880): support touch.size.calibration and .isSummed properties when captured.
    if (mHasTouchMajor) {
        size = mHasTouchMinor ? (slot.getTouchMajor() + slot.getTouchMinor()) / 2
                              : slot.getTouchMajor();
    } else if (mHasToolMajor) {
        size = mHasToolMinor ? (slot.getToolMajor() + slot.getToolMinor()) / 2
                             : slot.getToolMajor();
    }
    coords.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size * mSizeScale);
    return coords;
}

int32_t CapturedTouchpadEventConverter::allocatePointerIdToSlot(size_t slotNumber) {
    const int32_t pointerId = firstUnmarkedBit(mPointerIdsInUse);
    mPointerIdsInUse.set(pointerId);
    mPointerIdForSlotNumber[slotNumber] = pointerId;
    return pointerId;
}

void CapturedTouchpadEventConverter::freePointerIdForSlot(size_t slotNumber) {
    mPointerIdsInUse.reset(mPointerIdForSlotNumber.at(slotNumber));
    mPointerIdForSlotNumber.erase(slotNumber);
}

} // namespace android
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <bitset>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>

#include <android/input.h>
#include <input/Input.h>
#include <utils/Timers.h>

#include "EventHub.h"
#include "InputDevice.h"
#include "accumulator/CursorButtonAccumulator.h"
#include "accumulator/MultiTouchMotionAccumulator.h"
#include "accumulator/TouchButtonAccumulator.h"

namespace android {

class CapturedTouchpadEventConverter {
public:
    explicit CapturedTouchpadEventConverter(InputReaderContext& readerContext,
                                            const InputDeviceContext& deviceContext,
                                            MultiTouchMotionAccumulator& motionAccumulator,
                                            int32_t deviceId);
    std::string dump() const;
    void populateMotionRanges(InputDeviceInfo& info) const;
    void reset();
    [[nodiscard]] std::list<NotifyArgs> process(const RawEvent& rawEvent);

private:
    void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
                              int32_t evdevAxis) const;
    [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
    [[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
                                                  const std::vector<PointerCoords>& coords,
                                                  const std::vector<PointerProperties>& properties,
                                                  int32_t actionButton = 0, int32_t flags = 0);
    PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const;
    int32_t allocatePointerIdToSlot(size_t slotNumber);
    void freePointerIdForSlot(size_t slotNumber);

    const int32_t mDeviceId;
    InputReaderContext& mReaderContext;
    const InputDeviceContext& mDeviceContext;
    CursorButtonAccumulator mCursorButtonAccumulator;
    MultiTouchMotionAccumulator& mMotionAccumulator;

    float mOrientationScale = 0;
    float mPressureScale = 1;
    float mSizeScale = 0;
    bool mHasTouchMajor;
    const bool mHasTouchMinor;
    bool mHasToolMajor;
    const bool mHasToolMinor;
    nsecs_t mDownTime = 0;
    uint32_t mButtonState = 0;

    std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse;
    std::map<size_t, int32_t> mPointerIdForSlotNumber;

    static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
};

} // namespace android
+67 −4
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

#include "../Macros.h"

#include <chrono>
#include <limits>
#include <optional>

#include <android-base/stringprintf.h>
#include <android/input.h>
#include <ftl/enum.h>
#include <input/PrintTools.h>
@@ -174,8 +176,18 @@ TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext,
      : InputMapper(deviceContext, readerConfig),
        mGestureInterpreter(NewGestureInterpreter(), DeleteGestureInterpreter),
        mPointerController(getContext()->getPointerController(getDeviceId())),
        mStateConverter(deviceContext),
        mGestureConverter(*getContext(), deviceContext, getDeviceId()) {
        mStateConverter(deviceContext, mMotionAccumulator),
        mGestureConverter(*getContext(), deviceContext, getDeviceId()),
        mCapturedEventConverter(*getContext(), deviceContext, mMotionAccumulator, getDeviceId()) {
    RawAbsoluteAxisInfo slotAxisInfo;
    deviceContext.getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo);
    if (!slotAxisInfo.valid || slotAxisInfo.maxValue <= 0) {
        ALOGW("Touchpad \"%s\" doesn't have a valid ABS_MT_SLOT axis, and probably won't work "
              "properly.",
              deviceContext.getName().c_str());
    }
    mMotionAccumulator.configure(deviceContext, slotAxisInfo.maxValue + 1, true);

    mGestureInterpreter->Initialize(GESTURES_DEVCLASS_TOUCHPAD);
    mGestureInterpreter->SetHardwareProperties(createHardwareProperties(deviceContext));
    // Even though we don't explicitly delete copy/move semantics, it's safe to
@@ -209,15 +221,28 @@ uint32_t TouchpadInputMapper::getSources() const {

void TouchpadInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
    InputMapper::populateDeviceInfo(info);
    if (mPointerCaptured) {
        mCapturedEventConverter.populateMotionRanges(info);
    } else {
        mGestureConverter.populateMotionRanges(info);
    }
}

void TouchpadInputMapper::dump(std::string& dump) {
    dump += INDENT2 "Touchpad Input Mapper:\n";
    if (mProcessing) {
        dump += INDENT3 "Currently processing a hardware state\n";
    }
    if (mResettingInterpreter) {
        dump += INDENT3 "Currently resetting gesture interpreter\n";
    }
    dump += StringPrintf(INDENT3 "Pointer captured: %s\n", toString(mPointerCaptured));
    dump += INDENT3 "Gesture converter:\n";
    dump += addLinePrefix(mGestureConverter.dump(), INDENT4);
    dump += INDENT3 "Gesture properties:\n";
    dump += addLinePrefix(mPropertyProvider.dump(), INDENT4);
    dump += INDENT3 "Captured event converter:\n";
    dump += addLinePrefix(mCapturedEventConverter.dump(), INDENT4);
}

std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when,
@@ -252,17 +277,50 @@ std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when,
        mPropertyProvider.getProperty("Button Right Click Zone Enable")
                .setBoolValues({config.touchpadRightClickZoneEnabled});
    }
    return {};
    std::list<NotifyArgs> out;
    if ((!changes.any() && config.pointerCaptureRequest.enable) ||
        changes.test(InputReaderConfiguration::Change::POINTER_CAPTURE)) {
        mPointerCaptured = config.pointerCaptureRequest.enable;
        // The motion ranges are going to change, so bump the generation to clear the cached ones.
        bumpGeneration();
        if (mPointerCaptured) {
            // The touchpad is being captured, so we need to tidy up any fake fingers etc. that are
            // still being reported for a gesture in progress.
            out += reset(when);
            mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
        } else {
            // We're transitioning from captured to uncaptured.
            mCapturedEventConverter.reset();
        }
        if (changes.any()) {
            out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
        }
    }
    return out;
}

std::list<NotifyArgs> TouchpadInputMapper::reset(nsecs_t when) {
    mStateConverter.reset();
    resetGestureInterpreter(when);
    std::list<NotifyArgs> out = mGestureConverter.reset(when);
    out += InputMapper::reset(when);
    return out;
}

void TouchpadInputMapper::resetGestureInterpreter(nsecs_t when) {
    // The GestureInterpreter has no official reset method, but sending a HardwareState with no
    // fingers down or buttons pressed should get it into a clean state.
    HardwareState state;
    state.timestamp = std::chrono::duration<stime_t>(std::chrono::nanoseconds(when)).count();
    mResettingInterpreter = true;
    mGestureInterpreter->PushHardwareState(&state);
    mResettingInterpreter = false;
}

std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent* rawEvent) {
    if (mPointerCaptured) {
        return mCapturedEventConverter.process(*rawEvent);
    }
    std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent);
    if (state) {
        return sendHardwareState(rawEvent->when, rawEvent->readTime, *state);
@@ -283,6 +341,11 @@ std::list<NotifyArgs> TouchpadInputMapper::sendHardwareState(nsecs_t when, nsecs

void TouchpadInputMapper::consumeGesture(const Gesture* gesture) {
    ALOGD_IF(DEBUG_TOUCHPAD_GESTURES, "Gesture ready: %s", gesture->String().c_str());
    if (mResettingInterpreter) {
        // We already handle tidying up fake fingers etc. in GestureConverter::reset, so we should
        // ignore any gestures produced from the interpreter while we're resetting it.
        return;
    }
    if (!mProcessing) {
        ALOGE("Received gesture outside of the normal processing flow; ignoring it.");
        return;
+13 −0
Original line number Diff line number Diff line
@@ -21,12 +21,15 @@
#include <vector>

#include <PointerControllerInterface.h>
#include <utils/Timers.h>

#include "CapturedTouchpadEventConverter.h"
#include "EventHub.h"
#include "InputDevice.h"
#include "InputMapper.h"
#include "InputReaderBase.h"
#include "NotifyArgs.h"
#include "accumulator/MultiTouchMotionAccumulator.h"
#include "gestures/GestureConverter.h"
#include "gestures/HardwareStateConverter.h"
#include "gestures/PropertyProvider.h"
@@ -54,6 +57,7 @@ public:
    void consumeGesture(const Gesture* gesture);

private:
    void resetGestureInterpreter(nsecs_t when);
    [[nodiscard]] std::list<NotifyArgs> sendHardwareState(nsecs_t when, nsecs_t readTime,
                                                          SelfContainedHardwareState schs);
    [[nodiscard]] std::list<NotifyArgs> processGestures(nsecs_t when, nsecs_t readTime);
@@ -64,10 +68,19 @@ private:

    PropertyProvider mPropertyProvider;

    // The MultiTouchMotionAccumulator is shared between the HardwareStateConverter and
    // CapturedTouchpadEventConverter, so that if the touchpad is captured or released while touches
    // are down, the relevant converter can still benefit from the current axis values stored in the
    // accumulator.
    MultiTouchMotionAccumulator mMotionAccumulator;

    HardwareStateConverter mStateConverter;
    GestureConverter mGestureConverter;
    CapturedTouchpadEventConverter mCapturedEventConverter;

    bool mPointerCaptured = false;
    bool mProcessing = false;
    bool mResettingInterpreter = false;
    std::vector<Gesture> mGesturesToProcess;
};

Loading