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

Commit 8d900636 authored by Arpit Singh's avatar Arpit Singh Committed by Android (Google) Code Review
Browse files

Merge changes Ibdd09f42,I624700a7 into main

* changes:
  [15/n Dispatcher refactor] Remove TouchState from setInputWindows
  [14/n Dispatcher refactor] Move TouchState methods
parents d6a93e93 24a00a93
Loading
Loading
Loading
Loading
+163 −111
Original line number Diff line number Diff line
@@ -1267,16 +1267,11 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t& nextWakeupTime) {
            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
                // The event is stale. However, only drop stale events if there isn't an ongoing
                // gesture. That would allow us to complete the processing of the current stroke.
                const auto touchStateIt =
                        mTouchStates.mTouchStatesByDisplay.find(motionEntry->displayId);
                if (touchStateIt != mTouchStates.mTouchStatesByDisplay.end()) {
                    const TouchState& touchState = touchStateIt->second;
                    if (!touchState.hasTouchingPointers(motionEntry->deviceId) &&
                        !touchState.hasHoveringPointers(motionEntry->deviceId)) {
                if (!mTouchStates.hasTouchingOrHoveringPointers(motionEntry->displayId,
                                                                motionEntry->deviceId)) {
                    dropReason = DropReason::STALE;
                }
            }
            }
            if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
                if (!isFromSource(motionEntry->source, AINPUT_SOURCE_CLASS_POINTER)) {
                    // Only drop events that are focus-dispatched.
@@ -1716,9 +1711,7 @@ bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime,
    synthesizeCancelationEventsForAllConnectionsLocked(options);

    // Remove all active pointers from this device
    for (auto& [_, touchState] : mTouchStates.mTouchStatesByDisplay) {
        touchState.removeAllPointersForDevice(entry.deviceId);
    }
    mTouchStates.removeAllPointersForDevice(entry.deviceId);
    return true;
}

@@ -4581,15 +4574,10 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) {
        if (!(policyFlags & POLICY_FLAG_PASS_TO_USER)) {
            // Set the flag anyway if we already have an ongoing gesture. That would allow us to
            // complete the processing of the current stroke.
            const auto touchStateIt = mTouchStates.mTouchStatesByDisplay.find(args.displayId);
            if (touchStateIt != mTouchStates.mTouchStatesByDisplay.end()) {
                const TouchState& touchState = touchStateIt->second;
                if (touchState.hasTouchingPointers(args.deviceId) ||
                    touchState.hasHoveringPointers(args.deviceId)) {
            if (mTouchStates.hasTouchingOrHoveringPointers(args.displayId, args.deviceId)) {
                policyFlags |= POLICY_FLAG_PASS_TO_USER;
            }
        }
        }

        if (shouldSendMotionToInputFilterLocked(args)) {
            ui::Transform displayTransform = mWindowInfos.getDisplayTransform(args.displayId);
@@ -4893,15 +4881,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev
            if (!(policyFlags & POLICY_FLAG_PASS_TO_USER)) {
                // Set the flag anyway if we already have an ongoing motion gesture. That
                // would allow us to complete the processing of the current stroke.
                const auto touchStateIt = mTouchStates.mTouchStatesByDisplay.find(displayId);
                if (touchStateIt != mTouchStates.mTouchStatesByDisplay.end()) {
                    const TouchState& touchState = touchStateIt->second;
                    if (touchState.hasTouchingPointers(resolvedDeviceId) ||
                        touchState.hasHoveringPointers(resolvedDeviceId)) {
                if (mTouchStates.hasTouchingOrHoveringPointers(displayId, resolvedDeviceId)) {
                    policyFlags |= POLICY_FLAG_PASS_TO_USER;
                }
            }
            }

            const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes();
            const size_t pointerCount = motionEvent.getPointerCount();
@@ -5470,86 +5453,122 @@ void InputDispatcher::setInputWindowsLocked(
        onFocusChangedLocked(*changes, traceContext.getTracker(), removedFocusedWindowHandle);
    }

    if (const auto& it = mTouchStates.mTouchStatesByDisplay.find(displayId);
        it != mTouchStates.mTouchStatesByDisplay.end()) {
    CancelationOptions pointerCancellationOptions(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
                                                  "touched window was removed",
                                                  traceContext.getTracker());
    CancelationOptions hoverCancellationOptions(CancelationOptions::Mode::CANCEL_HOVER_EVENTS,
                                                "WindowInfo changed", traceContext.getTracker());
    const std::list<DispatcherTouchState::CancellationArgs> cancellations =
            mTouchStates.updateFromWindowInfo(displayId, mWindowInfos);
    for (const auto& cancellationArgs : cancellations) {
        switch (cancellationArgs.mode) {
            case CancelationOptions::Mode::CANCEL_POINTER_EVENTS:
                pointerCancellationOptions.deviceId = cancellationArgs.deviceId;
                synthesizeCancelationEventsForWindowLocked(cancellationArgs.windowHandle,
                                                           pointerCancellationOptions);
                break;
            case CancelationOptions::Mode::CANCEL_HOVER_EVENTS:
                hoverCancellationOptions.deviceId = cancellationArgs.deviceId;
                synthesizeCancelationEventsForWindowLocked(cancellationArgs.windowHandle,
                                                           hoverCancellationOptions);
                break;
            default:
                LOG_ALWAYS_FATAL("Unexpected cancellation Mode");
        }
    }

    // If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We
    // could just clear the state here.
    if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId &&
        std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) ==
                windowHandles.end()) {
        ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str());
        sendDropWindowCommandLocked(nullptr, 0, 0);
        mDragState.reset();
    }

    // Release information for windows that are no longer present.
    // This ensures that unused input channels are released promptly.
    // Otherwise, they might stick around until the window handle is destroyed
    // which might not happen until the next GC.
    for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
        if (!mWindowInfos.isWindowPresent(oldWindowHandle)) {
            if (DEBUG_FOCUS) {
                ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
            }
            oldWindowHandle->releaseChannel();
        }
    }
}

std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>
InputDispatcher::DispatcherTouchState::updateFromWindowInfo(
        ui::LogicalDisplayId displayId, const DispatcherWindowInfo& windowInfos) {
    std::list<CancellationArgs> cancellations;
    if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
        TouchState& state = it->second;
        for (size_t i = 0; i < state.windows.size();) {
            TouchedWindow& touchedWindow = state.windows[i];
            if (mWindowInfos.isWindowPresent(touchedWindow.windowHandle)) {
                i++;
        cancellations = eraseRemovedWindowsFromWindowInfo(state, displayId, windowInfos);
        cancellations.splice(cancellations.end(),
                             updateHoveringStateFromWindowInfo(state, displayId, windowInfos));
    }
    return cancellations;
}

std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>
InputDispatcher::DispatcherTouchState::eraseRemovedWindowsFromWindowInfo(
        TouchState& state, ui::LogicalDisplayId displayId,
        const DispatcherWindowInfo& windowInfos) {
    std::list<CancellationArgs> cancellations;
    for (auto it = state.windows.begin(); it != state.windows.end();) {
        TouchedWindow& touchedWindow = *it;
        if (windowInfos.isWindowPresent(touchedWindow.windowHandle)) {
            it++;
            continue;
        }
        LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName()
                  << " in display %" << displayId;
            CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
                                       "touched window was removed", traceContext.getTracker());
            synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options);
            // Since we are about to drop the touch, cancel the events for the wallpaper as
            // well.
        cancellations.emplace_back(touchedWindow.windowHandle,
                                   CancelationOptions::Mode::CANCEL_POINTER_EVENTS, std::nullopt);
        // Since we are about to drop the touch, cancel the events for the wallpaper as well.
        if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) &&
            touchedWindow.windowHandle->getInfo()->inputConfig.test(
                    gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
            for (const DeviceId deviceId : touchedWindow.getTouchingDeviceIds()) {
                if (const auto& ww = state.getWallpaperWindow(deviceId); ww != nullptr) {
                        options.deviceId = deviceId;
                        synthesizeCancelationEventsForWindowLocked(ww, options);
                    cancellations.emplace_back(ww, CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
                                               deviceId);
                }
            }
        }
            state.windows.erase(state.windows.begin() + i);
        }

        // If drag window is gone, it would receive a cancel event and broadcast the DRAG_END. We
        // could just clear the state here.
        if (mDragState && mDragState->dragWindow->getInfo()->displayId == displayId &&
            std::find(windowHandles.begin(), windowHandles.end(), mDragState->dragWindow) ==
                    windowHandles.end()) {
            ALOGI("Drag window went away: %s", mDragState->dragWindow->getName().c_str());
            sendDropWindowCommandLocked(nullptr, 0, 0);
            mDragState.reset();
        it = state.windows.erase(it);
    }
    return cancellations;
}

std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>
InputDispatcher::DispatcherTouchState::updateHoveringStateFromWindowInfo(
        TouchState& state, ui::LogicalDisplayId displayId,
        const DispatcherWindowInfo& windowInfos) {
    std::list<CancellationArgs> cancellations;
    // Check if the hovering should stop because the window is no longer eligible to receive it
    // (for example, if the touchable region changed)
    if (const auto& it = mTouchStates.mTouchStatesByDisplay.find(displayId);
        it != mTouchStates.mTouchStatesByDisplay.end()) {
        TouchState& state = it->second;
    ui::Transform displayTransform = windowInfos.getDisplayTransform(displayId);
    for (TouchedWindow& touchedWindow : state.windows) {
        std::vector<DeviceId> erasedDevices = touchedWindow.eraseHoveringPointersIf(
                    [this, displayId, &touchedWindow](const PointerProperties& properties, float x,
                                                      float y) REQUIRES(mLock) {
                [&](const PointerProperties& properties, float x, float y) {
                    const bool isStylus = properties.toolType == ToolType::STYLUS;
                        const ui::Transform displayTransform =
                                mWindowInfos.getDisplayTransform(displayId);
                    const bool stillAcceptsTouch =
                                windowAcceptsTouchAt(*touchedWindow.windowHandle->getInfo(),
                                                     displayId, x, y, isStylus, displayTransform);
                            windowAcceptsTouchAt(*touchedWindow.windowHandle->getInfo(), displayId,
                                                 x, y, isStylus, displayTransform);
                    return !stillAcceptsTouch;
                });

        for (DeviceId deviceId : erasedDevices) {
                CancelationOptions options(CancelationOptions::Mode::CANCEL_HOVER_EVENTS,
                                           "WindowInfo changed",
                                           traceContext.getTracker());
                options.deviceId = deviceId;
                synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options);
            }
        }
    }

    // Release information for windows that are no longer present.
    // This ensures that unused input channels are released promptly.
    // Otherwise, they might stick around until the window handle is destroyed
    // which might not happen until the next GC.
    for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
        if (!mWindowInfos.isWindowPresent(oldWindowHandle)) {
            if (DEBUG_FOCUS) {
                ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
            }
            oldWindowHandle->releaseChannel();
            cancellations.emplace_back(touchedWindow.windowHandle,
                                       CancelationOptions::Mode::CANCEL_HOVER_EVENTS, deviceId);
        }
    }
    return cancellations;
}

void InputDispatcher::setFocusedApplication(
@@ -5978,7 +5997,7 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
    resetNoFocusedWindowTimeoutLocked();

    mAnrTracker.clear();
    mTouchStates.mTouchStatesByDisplay.clear();
    mTouchStates.clear();
}

void InputDispatcher::logDispatchStateLocked() const {
@@ -6036,15 +6055,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const {
    dump += mFocusResolver.dump();
    dump += dumpPointerCaptureStateLocked();

    if (!mTouchStates.mTouchStatesByDisplay.empty()) {
        dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
        for (const auto& [displayId, state] : mTouchStates.mTouchStatesByDisplay) {
            std::string touchStateDump = addLinePrefix(state.dump(), INDENT2);
            dump += INDENT2 + displayId.toString() + " : " + touchStateDump;
        }
    } else {
        dump += INDENT "TouchStates: <no displays touched>\n";
    }
    dump += addLinePrefix(mTouchStates.dump(), INDENT);

    if (mDragState) {
        dump += StringPrintf(INDENT "DragState:\n");
@@ -7093,7 +7104,7 @@ void InputDispatcher::cancelCurrentTouch() {
                                   "cancel current touch", traceContext.getTracker());
        synthesizeCancelationEventsForAllConnectionsLocked(options);

        mTouchStates.mTouchStatesByDisplay.clear();
        mTouchStates.clear();
    }
    // Wake up poll loop since there might be work to do.
    mLooper->wake();
@@ -7228,18 +7239,7 @@ bool InputDispatcher::isPointerInWindow(const sp<android::IBinder>& token,
                                        ui::LogicalDisplayId displayId, DeviceId deviceId,
                                        int32_t pointerId) {
    std::scoped_lock _l(mLock);
    auto touchStateIt = mTouchStates.mTouchStatesByDisplay.find(displayId);
    if (touchStateIt == mTouchStates.mTouchStatesByDisplay.end()) {
        return false;
    }
    for (const TouchedWindow& window : touchStateIt->second.windows) {
        if (window.windowHandle->getToken() == token &&
            (window.hasTouchingPointer(deviceId, pointerId) ||
             window.hasHoveringPointer(deviceId, pointerId))) {
            return true;
        }
    }
    return false;
    return mTouchStates.isPointerInWindow(token, displayId, deviceId, pointerId);
}

void InputDispatcher::setInputMethodConnectionIsActive(bool isActive) {
@@ -7403,4 +7403,56 @@ ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetF
    return targetFlags;
}

bool InputDispatcher::DispatcherTouchState::hasTouchingOrHoveringPointers(
        ui::LogicalDisplayId displayId, int32_t deviceId) const {
    const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
    if (touchStateIt == mTouchStatesByDisplay.end()) {
        return false;
    }
    return touchStateIt->second.hasTouchingPointers(deviceId) ||
            touchStateIt->second.hasHoveringPointers(deviceId);
}

bool InputDispatcher::DispatcherTouchState::isPointerInWindow(const sp<android::IBinder>& token,
                                                              ui::LogicalDisplayId displayId,
                                                              android::DeviceId deviceId,
                                                              int32_t pointerId) const {
    const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
    if (touchStateIt == mTouchStatesByDisplay.end()) {
        return false;
    }
    for (const TouchedWindow& window : touchStateIt->second.windows) {
        if (window.windowHandle->getToken() == token &&
            (window.hasTouchingPointer(deviceId, pointerId) ||
             window.hasHoveringPointer(deviceId, pointerId))) {
            return true;
        }
    }
    return false;
}

std::string InputDispatcher::DispatcherTouchState::dump() const {
    std::string dump;
    if (!mTouchStatesByDisplay.empty()) {
        dump += StringPrintf("TouchStatesByDisplay:\n");
        for (const auto& [displayId, state] : mTouchStatesByDisplay) {
            std::string touchStateDump = addLinePrefix(state.dump(), INDENT);
            dump += INDENT + displayId.toString() + " : " + touchStateDump;
        }
    } else {
        dump += "TouchStates: <no displays touched>\n";
    }
    return dump;
}

void InputDispatcher::DispatcherTouchState::removeAllPointersForDevice(android::DeviceId deviceId) {
    for (auto& [_, touchState] : mTouchStatesByDisplay) {
        touchState.removeAllPointersForDevice(deviceId);
    }
}

void InputDispatcher::DispatcherTouchState::clear() {
    mTouchStatesByDisplay.clear();
}

} // namespace android::inputdispatcher
+33 −4
Original line number Diff line number Diff line
@@ -352,6 +352,12 @@ private:

    class DispatcherTouchState {
    public:
        struct CancellationArgs {
            const sp<gui::WindowInfoHandle> windowHandle;
            CancelationOptions::Mode mode;
            std::optional<DeviceId> deviceId;
        };

        static void addPointerWindowTarget(const sp<android::gui::WindowInfoHandle>& windowHandle,
                                           InputTarget::DispatchMode dispatchMode,
                                           ftl::Flags<InputTarget::Flags> targetFlags,
@@ -373,14 +379,37 @@ private:
        sp<android::gui::WindowInfoHandle> findTouchedForegroundWindow(
                ui::LogicalDisplayId displayId) const;

        bool hasTouchingOrHoveringPointers(ui::LogicalDisplayId displayId, int32_t deviceId) const;

        bool isPointerInWindow(const sp<android::IBinder>& token, ui::LogicalDisplayId displayId,
                               DeviceId deviceId, int32_t pointerId) const;

        std::string dump() const;

        // Updates the touchState for display from WindowInfo,
        // return vector of CancellationArgs for every cancelled touch
        std::list<CancellationArgs> updateFromWindowInfo(ui::LogicalDisplayId displayId,
                                                         const DispatcherWindowInfo& windowInfos);

        void removeAllPointersForDevice(DeviceId deviceId);

        void clear();

        std::unordered_map<ui::LogicalDisplayId, TouchState> mTouchStatesByDisplay;

    private:
        static std::list<CancellationArgs> eraseRemovedWindowsFromWindowInfo(
                TouchState& state, ui::LogicalDisplayId displayId,
                const DispatcherWindowInfo& windowInfos);

        static std::list<CancellationArgs> updateHoveringStateFromWindowInfo(
                TouchState& state, ui::LogicalDisplayId displayId,
                const DispatcherWindowInfo& windowInfos);

        static std::vector<InputTarget> findOutsideTargets(
                ui::LogicalDisplayId displayId,
                const sp<android::gui::WindowInfoHandle>& touchedWindow, int32_t pointerId,
                const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos,
                std::function<void()> dump);
                ui::LogicalDisplayId displayId, const sp<gui::WindowInfoHandle>& touchedWindow,
                int32_t pointerId, const ConnectionManager& connections,
                const DispatcherWindowInfo& windowInfos, std::function<void()> dump);

        /**
         * Slip the wallpaper touch if necessary.
+30 −20

File changed.

Preview size limit exceeded, changes collapsed.