/*
 * Copyright (C) 2024-2026 Huawei Device Co., Ltd.
 * 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 "accessibility_touch_exploration.h"
#include "accessibility_event_info.h"
#include "hilog_wrapper.h"
#include "securec.h"
#include "ext_utils.h"
#ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
#include "accessibility_display_manager.h"
#endif

namespace OHOS {
namespace Accessibility {

void TouchExploration::InitTwoFingerGestureFuncMap()
{
    handleEventFuncMap_.insert({
        {TouchExplorationState::TWO_FINGERS_DOWN, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleTwoFingersDownStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleTwoFingersDownStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleTwoFingersDownStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::TWO_FINGERS_DRAG, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleTwoFingersDragStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleTwoFingersDragStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleTwoFingersDragStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::TWO_FINGERS_TAP, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleTwoFingersTapStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleMultiFingersTapStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleTwoFingersTapStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::TWO_FINGERS_CONTINUE_DOWN, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleMultiFingersContinueDownStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleTwoFingersContinueDownStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleTwoFingersContinueDownStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::TWO_FINGERS_UNKNOWN, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleTwoFingersUnknownStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleTwoFingersUnknownStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleTwoFingersUnknownStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        }
    });
}

void TouchExploration::InitThreeFingerGestureFuncMap()
{
    handleEventFuncMap_.insert({
        {TouchExplorationState::THREE_FINGERS_DOWN, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleThreeFingersDownStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleThreeFingersDownStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleThreeFingersDownStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::THREE_FINGERS_SWIPE, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleThreeFingersSwipeStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleThreeFingersSwipeStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleThreeFingersSwipeStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::THREE_FINGERS_TAP, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleThreeFingersTapStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleMultiFingersTapStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleThreeFingersTapStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::THREE_FINGERS_CONTINUE_DOWN, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleMultiFingersContinueDownStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleThreeFingersContinueDownStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleThreeFingersContinueDownStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        }
    });
}

void TouchExploration::InitFourFingerGestureFuncMap()
{
    handleEventFuncMap_.insert({
        {TouchExplorationState::THREE_FINGERS_CONTINUE_DOWN, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleMultiFingersContinueDownStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleThreeFingersContinueDownStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleThreeFingersContinueDownStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::FOUR_FINGERS_DOWN, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleFourFingersDownStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleFourFingersDownStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleFourFingersDownStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::FOUR_FINGERS_SWIPE, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleFourFingersSwipeStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleFourFingersSwipeStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleFourFingersSwipeStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::FOUR_FINGERS_TAP, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleFourFingersTapStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleMultiFingersTapStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleFourFingersTapStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        },
        {TouchExplorationState::FOUR_FINGERS_CONTINUE_DOWN, {
            {MMI::PointerEvent::POINTER_ACTION_DOWN, BIND(HandleMultiFingersContinueDownStateDown)},
            {MMI::PointerEvent::POINTER_ACTION_UP, BIND(HandleFourFingersContinueDownStateUp)},
            {MMI::PointerEvent::POINTER_ACTION_MOVE, BIND(HandleFourFingersContinueDownStateMove)},
            {MMI::PointerEvent::POINTER_ACTION_CANCEL, BIND(HandleCancelEvent)}}
        }
    });
}

std::map<TouchExplorationMsg, GestureType> TouchExploration::GetMultiFingerMsgToGestureMap()
{
    static std::map<TouchExplorationMsg, GestureType> MULTI_GESTURE_TYPE = {
        {TouchExplorationMsg::TWO_FINGER_SINGLE_TAP_MSG, GestureType::GESTURE_TWO_FINGER_SINGLE_TAP},
        {TouchExplorationMsg::TWO_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
        {TouchExplorationMsg::TWO_FINGER_DOUBLE_TAP_MSG, GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP},
        {TouchExplorationMsg::TWO_FINGER_DOUBLE_TAP_AND_HOLD_MSG, GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP_AND_HOLD},
        {TouchExplorationMsg::TWO_FINGER_TRIPLE_TAP_MSG, GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP},
        {TouchExplorationMsg::TWO_FINGER_TRIPLE_TAP_AND_HOLD_MSG, GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP_AND_HOLD},
        {TouchExplorationMsg::THREE_FINGER_SINGLE_TAP_MSG, GestureType::GESTURE_THREE_FINGER_SINGLE_TAP},
        {TouchExplorationMsg::THREE_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
        {TouchExplorationMsg::THREE_FINGER_DOUBLE_TAP_MSG, GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP},
        {TouchExplorationMsg::THREE_FINGER_DOUBLE_TAP_AND_HOLD_MSG,
            GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP_AND_HOLD},
        {TouchExplorationMsg::THREE_FINGER_TRIPLE_TAP_MSG, GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP},
        {TouchExplorationMsg::THREE_FINGER_TRIPLE_TAP_AND_HOLD_MSG,
            GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP_AND_HOLD},
        {TouchExplorationMsg::FOUR_FINGER_SINGLE_TAP_MSG, GestureType::GESTURE_FOUR_FINGER_SINGLE_TAP},
        {TouchExplorationMsg::FOUR_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
        {TouchExplorationMsg::FOUR_FINGER_DOUBLE_TAP_MSG, GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP},
        {TouchExplorationMsg::FOUR_FINGER_DOUBLE_TAP_AND_HOLD_MSG,
            GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP_AND_HOLD},
        {TouchExplorationMsg::FOUR_FINGER_TRIPLE_TAP_MSG, GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP},
        {TouchExplorationMsg::FOUR_FINGER_TRIPLE_TAP_AND_HOLD_MSG, GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP_AND_HOLD}
    };
    return MULTI_GESTURE_TYPE;
}

// LCOV_EXCL_START
void TouchExploration::ProcessMultiFingerGesture(TouchExplorationMsg msg, uint64_t displayId)
{
    std::map<TouchExplorationMsg, GestureType> multiGestureMap = GetMultiFingerMsgToGestureMap();
    if (multiGestureMap.find(msg) == multiGestureMap.end()) {
        return;
    }

    static std::map<GestureType, TouchExplorationState> MULTI_FINGER_TAP_GESTURE_TO_STATE = {
        {GestureType::GESTURE_TWO_FINGER_SINGLE_TAP, TouchExplorationState::TWO_FINGERS_TAP},
        {GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP, TouchExplorationState::TWO_FINGERS_TAP},
        {GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP, TouchExplorationState::TWO_FINGERS_TAP},
        {GestureType::GESTURE_THREE_FINGER_SINGLE_TAP, TouchExplorationState::THREE_FINGERS_TAP},
        {GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP, TouchExplorationState::THREE_FINGERS_TAP},
        {GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP, TouchExplorationState::THREE_FINGERS_TAP},
        {GestureType::GESTURE_FOUR_FINGER_SINGLE_TAP, TouchExplorationState::FOUR_FINGERS_TAP},
        {GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP, TouchExplorationState::FOUR_FINGERS_TAP},
        {GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP, TouchExplorationState::FOUR_FINGERS_TAP}
    };
    GestureType gestureType = multiGestureMap.at(msg);
    if (MULTI_FINGER_TAP_GESTURE_TO_STATE.find(gestureType) != MULTI_FINGER_TAP_GESTURE_TO_STATE.end()) {
        // multi-finger multi-tap gesture
        if (GetCurrentState() == MULTI_FINGER_TAP_GESTURE_TO_STATE.at(gestureType)) {
            SendGestureEventToAA(gestureType, displayId);
            Clear();
            SetCurrentState(TouchExplorationState::TOUCH_INIT);
        }
    } else if (gestureType == GestureType::GESTURE_INVALID) {
        if (GetCurrentState() == TouchExplorationState::TWO_FINGERS_DOWN) {
            for (auto& event : receivedPointerEvents_) {
                SendEventToMultimodal(event, ChangeAction::NO_CHANGE);
            }
            Clear();
            SetCurrentState(TouchExplorationState::PASSING_THROUGH);
            return;
        }
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
    } else {
        // multi-finger multi-tap-and-hold gesture
        SendGestureEventToAA(gestureType, displayId);
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
    }
}
// LCOV_EXCL_STOP

void TouchExploration::HandleTwoFingersDownStateDown(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);
    CancelPostEvent(TouchExplorationMsg::TWO_FINGER_SINGLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::TWO_FINGER_LONG_PRESS_MSG);

    if (event.GetPointerIds().size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_3)) {
        CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
        return;
    }

    if (!handler_->HasInnerEvent(static_cast<uint32_t>(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG))) {
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
        return;
    }

    CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
    handler_->SendEvent(static_cast<uint32_t>(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG), 0,
        static_cast<int32_t>(TimeoutDuration::MULTI_FINGER_TAP_INTERVAL_TIMEOUT));
    handler_->SendEvent(static_cast<uint32_t>(TouchExplorationMsg::THREE_FINGER_SINGLE_TAP_MSG), 0,
        static_cast<int32_t>(TimeoutDuration::DOUBLE_TAP_TIMEOUT));
    handler_->SendEvent(static_cast<uint32_t>(TouchExplorationMsg::THREE_FINGER_LONG_PRESS_MSG), 0,
        static_cast<int32_t>(TimeoutDuration::DOUBLE_TAP_TIMEOUT));
    SetCurrentState(TouchExplorationState::THREE_FINGERS_DOWN);
}

void TouchExploration::HandleTwoFingersDownStateUp(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);
    CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
    CancelPostEvent(TouchExplorationMsg::TWO_FINGER_LONG_PRESS_MSG);

    uint32_t pointerSize = event.GetPointerIds().size();
    if (pointerSize == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1)) {
        SetCurrentState(TouchExplorationState::TWO_FINGERS_TAP);
    } else if (pointerSize > static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
        Clear();
        CancelPostEvent(TouchExplorationMsg::TWO_FINGER_SINGLE_TAP_MSG);
        SetCurrentState(TouchExplorationState::INVALID);
    }
}

bool TouchExploration::GetBasePointItem(MMI::PointerEvent::PointerItem &basePointerItem, int32_t pId)
{
    HILOG_DEBUG();
    for (auto rIter = receivedPointerEvents_.rbegin(); rIter != receivedPointerEvents_.rend(); ++rIter) {
        if ((rIter->GetPointerId() == pId) && (rIter->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN)) {
            rIter->GetPointerItem(pId, basePointerItem);
            return true;
        }
    }
    return false;
}

void TouchExploration::GetPointOffset(MMI::PointerEvent &event, std::vector<float> &firstPointOffset,
    std::vector<float> &secondPointOffset)
{
    HILOG_DEBUG();
    std::vector<int32_t> pIds = event.GetPointerIds();
    if (pIds.size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
        return;
    }

    MMI::PointerEvent::PointerItem pointerF {};
    MMI::PointerEvent::PointerItem pointerS {};
    event.GetPointerItem(pIds[0], pointerF);
    event.GetPointerItem(pIds[1], pointerS);

    MMI::PointerEvent::PointerItem basePointerF {};
    MMI::PointerEvent::PointerItem basePointerS {};
    if (GetBasePointItem(basePointerF, pIds[0]) && GetBasePointItem(basePointerS, pIds[1])) {
        firstPointOffset.push_back(pointerF.GetDisplayX() - basePointerF.GetDisplayX());
        firstPointOffset.push_back(pointerF.GetDisplayY() - basePointerF.GetDisplayY());
        secondPointOffset.push_back(pointerS.GetDisplayX() - basePointerS.GetDisplayX());
        secondPointOffset.push_back(pointerS.GetDisplayY() - basePointerS.GetDisplayY());
    }
}

float TouchExploration::GetAngleCos(float offsetX, float offsetY, bool isGetX)
{
    HILOG_DEBUG();
    float ret = isGetX ? offsetX : offsetY;
    double duration = hypot(offsetX, offsetY);
    if (duration < - EPSINON || duration > EPSINON) {
        ret = ret / duration;
    }
    return ret;
}

bool TouchExploration::IsDragGestureAccept(MMI::PointerEvent &event)
{
    HILOG_DEBUG();
    std::vector<float> firstPointOffset;
    std::vector<float> secondPointOffset;
    GetPointOffset(event, firstPointOffset, secondPointOffset);
    if (firstPointOffset.size() != SCREEN_AXIS_NUM || secondPointOffset.size() != SCREEN_AXIS_NUM) {
        return false;
    }

    float firstOffsetX = firstPointOffset[0];
    float firstOffsetY = firstPointOffset[1];
    float secondOffsetX = secondPointOffset[0];
    float secondOffsetY = secondPointOffset[1];
    if ((!firstOffsetX && !firstOffsetY) ||
        (!secondOffsetX && !secondOffsetY)) {
        return true;
    }

    float firstXCos = GetAngleCos(firstOffsetX, firstOffsetY, true);
    float firstYCos = GetAngleCos(firstOffsetX, firstOffsetY, false);
    float secondXCos = GetAngleCos(secondOffsetX, secondOffsetY, true);
    float secondYCos = GetAngleCos(secondOffsetX, secondOffsetY, false);
    return (firstXCos * secondXCos + firstYCos * secondYCos) >= MAX_DRAG_GESTURE_COSINE;
}

void TouchExploration::SendDragDownEventToMultimodal(MMI::PointerEvent event)
{
    HILOG_DEBUG();
    std::vector<int32_t> pIds = event.GetPointerIds();
    int32_t xPointDown = 0;
    int32_t yPointDown = 0;
    int64_t actionTime = 0;
    MMI::PointerEvent::PointerItem basePointerItem {};

    for (auto &baseEvent : receivedPointerEvents_) {
        if ((baseEvent.GetPointerId() == event.GetPointerId()) &&
            (baseEvent.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN)) {
            baseEvent.GetPointerItem(event.GetPointerId(), basePointerItem);
            xPointDown = basePointerItem.GetDisplayX();
            yPointDown = basePointerItem.GetDisplayY();
            actionTime = baseEvent.GetActionTime();
            break;
        }
    }

    MMI::PointerEvent::PointerItem pointer {};
    event.GetPointerItem(draggingPid_, pointer);
    pointer.SetDisplayX(xPointDown);
    pointer.SetDisplayY(yPointDown);
    event.RemovePointerItem(draggingPid_);
    event.AddPointerItem(pointer);
    event.SetActionTime(actionTime);
    int32_t removePid = draggingPid_ == pIds[0] ? pIds[1] : pIds[0];
    event.RemovePointerItem(removePid);
    SendEventToMultimodal(event, ChangeAction::POINTER_DOWN);
    draggingDownEvent_ = std::make_shared<MMI::PointerEvent>(event);
}

bool TouchExploration::IsRealMove(MMI::PointerEvent &event)
{
    std::vector<float> firstPointOffset;
    std::vector<float> secondPointOffset;
    GetPointOffset(event, firstPointOffset, secondPointOffset);
    if (firstPointOffset.size() != SCREEN_AXIS_NUM || secondPointOffset.size() != SCREEN_AXIS_NUM) {
        return false;
    }

    return (hypot(firstPointOffset[0], firstPointOffset[1]) >= TOUCH_SLOP &&
        hypot(secondPointOffset[0], secondPointOffset[1]) >= TOUCH_SLOP);
}

void TouchExploration::HandleTwoFingersDownStateMove(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);

    MMI::PointerEvent::PointerItem pointerItem;
    event.GetPointerItem(event.GetPointerId(), pointerItem);

    MMI::PointerEvent::PointerItem basePointerItem;
    if (!GetBasePointItem(basePointerItem, event.GetPointerId())) {
        HILOG_ERROR("get base point item failed, pid = %{public}d.", event.GetPointerId());
        return;
    }

    int32_t offsetX = pointerItem.GetDisplayX() - basePointerItem.GetDisplayX();
    int32_t offsetY = pointerItem.GetDisplayY() - basePointerItem.GetDisplayY();
    if (hypot(offsetX, offsetY) > TOUCH_SLOP * static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
        HILOG_DEBUG("cancel two-finger tap gesture because finger move");
        CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
        CancelPostEvent(TouchExplorationMsg::TWO_FINGER_SINGLE_TAP_MSG);
        CancelPostEvent(TouchExplorationMsg::TWO_FINGER_LONG_PRESS_MSG);
        if (event.GetPointerIds().size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
            Clear();
            SendScreenWakeUpEvent(event);
            SetCurrentState(TouchExplorationState::INVALID);
            return;
        }
        if (!IsRealMove(event)) {
            HILOG_DEBUG("not a move");
            return;
        }
        if (IsDragGestureAccept(event)) {
            draggingPid_ = event.GetPointerId();
            SendDragDownEventToMultimodal(event);
            SendEventToMultimodal(event, ChangeAction::NO_CHANGE);
            SetCurrentState(TouchExplorationState::TWO_FINGERS_DRAG);
        } else {
            for (auto &receivedEvent : receivedPointerEvents_) {
                SendEventToMultimodal(receivedEvent, ChangeAction::NO_CHANGE);
            }
            Clear();
            SetCurrentState(TouchExplorationState::PASSING_THROUGH);
        }
    }
}

void TouchExploration::SendUpForDragDownEvent()
{
    HILOG_DEBUG();
    if (receivedPointerEvents_.empty()) {
        HILOG_ERROR("received pointer event is null!");
        return;
    }

    MMI::PointerEvent lastMoveEvent = receivedPointerEvents_.back();
    MMI::PointerEvent::PointerItem movePointerItem;
    lastMoveEvent.GetPointerItem(lastMoveEvent.GetPointerId(), movePointerItem);
    int32_t x = movePointerItem.GetDisplayX();
    int32_t y = movePointerItem.GetDisplayY();

    if (draggingDownEvent_ == nullptr) {
        HILOG_ERROR("dragging down event is null!");
        return;
    }
    MMI::PointerEvent::PointerItem pointerItem {};
    draggingDownEvent_->SetActionTime(ExtUtils::GetSystemTime() * US_TO_MS);
    draggingDownEvent_->GetPointerItem(draggingDownEvent_->GetPointerId(), pointerItem);
    pointerItem.SetPressed(false);
    pointerItem.SetDisplayX(x);
    pointerItem.SetDisplayY(y);
    draggingDownEvent_->RemovePointerItem(draggingDownEvent_->GetPointerId());
    draggingDownEvent_->AddPointerItem(pointerItem);
    SendEventToMultimodal(*draggingDownEvent_, ChangeAction::POINTER_UP);
}

void TouchExploration::HandleTwoFingersDragStateDown(MMI::PointerEvent &event)
{
    if (event.GetPointerIds().size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
        SendUpForDragDownEvent();
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
    }
}

void TouchExploration::HandleTwoFingersDragStateUp(MMI::PointerEvent &event)
{
    if (event.GetPointerIds().size() == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1)) {
        SendUpForDragDownEvent();
        Clear();
        SetCurrentState(TouchExplorationState::TOUCH_INIT);
    }
}

void TouchExploration::HandleTwoFingersDragStateMove(MMI::PointerEvent &event)
{
    std::vector<int32_t> pIds = event.GetPointerIds();
    if (pIds.size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_2) || event.GetPointerId() != draggingPid_) {
        return;
    }

    receivedPointerEvents_.push_back(event);

#ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
    // Get densityPixels from WMS
    AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
    auto display = displayMgr.GetDefaultDisplay();
    float densityPixels = display->GetVirtualPixelRatio();
    int32_t miniZoomPointerDistance = static_cast<int32_t>(MINI_POINTER_DISTANCE_DIP * densityPixels);
#else
    HILOG_DEBUG("not support display manager");
    int32_t miniZoomPointerDistance = static_cast<int32_t>(MINI_POINTER_DISTANCE_DIP * 1);
#endif

    MMI::PointerEvent::PointerItem pointerF {};
    MMI::PointerEvent::PointerItem pointerS {};
    event.GetPointerItem(pIds[0], pointerF);
    event.GetPointerItem(pIds[1], pointerS);
    float xPointF = pointerF.GetDisplayX();
    float xPointS = pointerS.GetDisplayX();
    float yPointF = pointerF.GetDisplayY();
    float yPointS = pointerS.GetDisplayY();
    float offsetX = abs(xPointF - xPointS);
    float offsetY = abs(yPointF - yPointS);
    double duration = hypot(offsetX, offsetY);
    if (duration > miniZoomPointerDistance) {
        // Adjust this event's location.
        MMI::PointerEvent::PointerItem pointer {};
        event.GetPointerItem(event.GetPointerId(), pointer);
        pointer.SetDisplayX(pointer.GetDisplayX() + offsetX / DIVIDE_NUM);
        pointer.SetDisplayY(pointer.GetDisplayY() + offsetY / DIVIDE_NUM);
        event.RemovePointerItem(event.GetPointerId());
        event.AddPointerItem(pointer);
    }
    int32_t removePid = draggingPid_ == pIds[0]? pIds[1] : pIds[0];
    event.RemovePointerItem(removePid);
    SendEventToMultimodal(event, ChangeAction::NO_CHANGE);
}

bool TouchExploration::GetPointerItemWithFingerNum(uint32_t fingerNum,
    std::vector<MMI::PointerEvent::PointerItem> &curPoints,
    std::vector<MMI::PointerEvent::PointerItem> &prePoints, MMI::PointerEvent &event)
{
    HILOG_DEBUG();
    if (fingerNum > static_cast<uint32_t>(INT32_MAX)) {
        HILOG_ERROR("fingerNum is invalid!");
        return false;
    }

    bool findPrePointer = false;
    std::vector<int32_t> pIds = event.GetPointerIds();
    for (int32_t i = 0; i < static_cast<int32_t>(fingerNum); i++) {
        findPrePointer = false;
        event.GetPointerItem(pIds[i], curPoints[i]);
        for (auto &preEvent : receivedPointerEvents_) {
            if ((preEvent.GetPointerId() == pIds[i]) &&
                (preEvent.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN)) {
                findPrePointer = true;
                preEvent.GetPointerItem(pIds[i], prePoints[i]);
                break;
            }
        }
        if (!findPrePointer) {
            HILOG_ERROR("get prePointerItem(%{public}d) failed", i);
            return false;
        }
    }
    return true;
}

bool TouchExploration::IsMultiFingerMultiTap(MMI::PointerEvent &event, const uint32_t fingerNum)
{
    HILOG_DEBUG();
    std::vector<MMI::PointerEvent::PointerItem> curPoints(fingerNum);
    std::vector<MMI::PointerEvent::PointerItem> prePoints(fingerNum);
    if (!GetPointerItemWithFingerNum(fingerNum, curPoints, prePoints, event)) {
        return false;
    }

    std::vector<int32_t> excludePid(fingerNum, -1);
    for (auto curPoint : curPoints) {
        float moveDelta = FLT_MAX;
        int32_t nearestPid = -1;
        int32_t curX = curPoint.GetDisplayX();
        int32_t curY = curPoint.GetDisplayY();
        for (auto prePoint : prePoints) {
            int32_t pId = prePoint.GetPointerId();
            if (std::find(excludePid.begin(), excludePid.end(), pId) != excludePid.end()) {
                continue;
            }
            int32_t preX = prePoint.GetDisplayX();
            int32_t preY = prePoint.GetDisplayY();
            int32_t offsetX = curX - preX;
            int32_t offsetY = curY - preY;
            if (offsetX == 0 && offsetY == 0) {
                nearestPid = pId;
                moveDelta = 0;
                break;
            }

            float delta = hypot(offsetX, offsetY);
            if (delta < moveDelta) {
                moveDelta = delta;
                nearestPid = pId;
            }
        }
        if (moveDelta < multiTapOffsetThresh_ * fingerNum) {
            excludePid.push_back(nearestPid);
        } else {
            return false;
        }
    }

    return true;
}

bool TouchExploration::IsMultiFingerMultiTapGesture(MMI::PointerEvent &event, const uint32_t fingerNum)
{
    HILOG_DEBUG();

    if (fingerNum < static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
        return false;
    }

    if (IsMultiFingerMultiTap(event, fingerNum)) {
        multiTapNum_ = multiTapNum_ + 1;
        HILOG_DEBUG("%{public}d finger %{public}d tap is recognized", static_cast<int32_t>(fingerNum),
            multiTapNum_ + 1);
    } else {
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
        return false;
    }

    uint32_t fingerNumIndex = fingerNum - 2;
    handler_->SendEvent(static_cast<uint32_t>(GESTURE_TAP_MSG[multiTapNum_][fingerNumIndex]), 0,
        static_cast<int32_t>(TimeoutDuration::DOUBLE_TAP_TIMEOUT));
    handler_->SendEvent(static_cast<uint32_t>(GESTURE_HOLD_MSG[multiTapNum_][fingerNumIndex]), 0,
        static_cast<int32_t>(TimeoutDuration::DOUBLE_TAP_TIMEOUT));
    return true;
}

void TouchExploration::HandleMultiFingersTapStateDown(MMI::PointerEvent &event, uint32_t fingerNum)
{
    receivedPointerEvents_.push_back(event);
    CancelMultiFingerTapEvent();
    CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);

    if (multiTapNum_ == TAP_COUNT_MAXIMUM - 1) {
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
        return;
    }

    uint32_t pointerSize = event.GetPointerIds().size();
    if (pointerSize < fingerNum) {
        handler_->SendEvent(static_cast<uint32_t>(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG), 0,
            static_cast<int32_t>(TimeoutDuration::MULTI_FINGER_TAP_INTERVAL_TIMEOUT));
    } else if (pointerSize == fingerNum) {
        if (IsMultiFingerMultiTapGesture(event, fingerNum)) {
            if (fingerNum == static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
                SetCurrentState(TouchExplorationState::TWO_FINGERS_CONTINUE_DOWN);
            } else if (fingerNum == static_cast<uint32_t>(PointerCount::POINTER_COUNT_3)) {
                SetCurrentState(TouchExplorationState::THREE_FINGERS_CONTINUE_DOWN);
            } else {
                SetCurrentState(TouchExplorationState::FOUR_FINGERS_CONTINUE_DOWN);
            }
        }
    } else {
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
    }
}

void TouchExploration::HandleTwoFingersTapStateDown(MMI::PointerEvent &event)
{
    HandleMultiFingersTapStateDown(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_2));
}

void TouchExploration::HandleMultiFingersTapStateUp(MMI::PointerEvent &event)
{
    Clear();
    CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);

    uint32_t pointerSize = event.GetPointerIds().size();
    if (pointerSize == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1)) {
        SetCurrentState(TouchExplorationState::TOUCH_INIT);
    } else {
        SetCurrentState(TouchExplorationState::INVALID);
    }
}

void TouchExploration::HandleMultiFingersTapStateMove(MMI::PointerEvent &event, uint32_t fingerNum)
{
    if (event.GetPointerIds().size() >= fingerNum) {
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
        return;
    }

    receivedPointerEvents_.push_back(event);

    MMI::PointerEvent::PointerItem pointerItem;
    event.GetPointerItem(event.GetPointerId(), pointerItem);

    MMI::PointerEvent::PointerItem basePointerItem;
    if (!GetBasePointItem(basePointerItem, event.GetPointerId())) {
        HILOG_ERROR("get base point item failed, pid = %{public}d.", event.GetPointerId());
        return;
    }

    int32_t offsetX = pointerItem.GetDisplayX() - basePointerItem.GetDisplayX();
    int32_t offsetY = pointerItem.GetDisplayY() - basePointerItem.GetDisplayY();
    if (hypot(offsetX, offsetY) > TOUCH_SLOP * (fingerNum - 1)) {
        CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
    }

    SendScreenWakeUpEvent(event);
}

void TouchExploration::HandleTwoFingersTapStateMove(MMI::PointerEvent &event)
{
    HandleMultiFingersTapStateMove(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_2));
}

void TouchExploration::HandleMultiFingersContinueDownStateDown(MMI::PointerEvent &event)
{
    CancelMultiFingerTapEvent();
    CancelMultiFingerTapAndHoldEvent();
    Clear();
    SetCurrentState(TouchExplorationState::INVALID);
}

void TouchExploration::HandleMultiFingersContinueDownStateUp(MMI::PointerEvent &event, uint32_t fingerNum)
{
    receivedPointerEvents_.push_back(event);
    CancelMultiFingerTapAndHoldEvent();

    uint32_t pointerSize = event.GetPointerIds().size();
    if (pointerSize == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1)) {
        if (fingerNum == static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
            SetCurrentState(TouchExplorationState::TWO_FINGERS_TAP);
        } else if (fingerNum == static_cast<uint32_t>(PointerCount::POINTER_COUNT_3)) {
            SetCurrentState(TouchExplorationState::THREE_FINGERS_TAP);
        } else {
            SetCurrentState(TouchExplorationState::FOUR_FINGERS_TAP);
        }
    } else if (pointerSize > fingerNum) {
        CancelMultiFingerTapEvent();
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
    }
}

void TouchExploration::HandleTwoFingersContinueDownStateUp(MMI::PointerEvent &event)
{
    HandleMultiFingersContinueDownStateUp(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_2));
}

void TouchExploration::HandleMultiFingersContinueDownStateMove(MMI::PointerEvent &event, uint32_t fingerNum)
{
    receivedPointerEvents_.push_back(event);

    MMI::PointerEvent::PointerItem pointerItem;
    event.GetPointerItem(event.GetPointerId(), pointerItem);

    MMI::PointerEvent::PointerItem basePointerItem;
    if (!GetBasePointItem(basePointerItem, event.GetPointerId())) {
        HILOG_ERROR("get base point item failed, pid = %{public}d.", event.GetPointerId());
        return;
    }

    int32_t offsetX = pointerItem.GetDisplayX() - basePointerItem.GetDisplayX();
    int32_t offsetY = pointerItem.GetDisplayY() - basePointerItem.GetDisplayY();
    if (hypot(offsetX, offsetY) > TOUCH_SLOP * fingerNum) {
        Clear();
        CancelMultiFingerTapEvent();
        CancelMultiFingerTapAndHoldEvent();
        SetCurrentState(TouchExplorationState::INVALID);
    }

    SendScreenWakeUpEvent(event);
}

void TouchExploration::HandleTwoFingersContinueDownStateMove(MMI::PointerEvent &event)
{
    HandleMultiFingersContinueDownStateMove(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_2));
}

void TouchExploration::HandleTwoFingersUnknownStateDown(MMI::PointerEvent &event)
{
    if (event.GetPointerIds().size() == static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) {
        receivedPointerEvents_.push_back(event);
        return;
    }

    Clear();
    SetCurrentState(TouchExplorationState::INVALID);
}

void TouchExploration::HandleTwoFingersUnknownStateUp(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);
    if (event.GetPointerIds().size() == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1)) {
        Clear();
        SetCurrentState(TouchExplorationState::TOUCH_INIT);
    }
}

void TouchExploration::HandleTwoFingersUnknownStateMove(MMI::PointerEvent &event)
{
    if ((event.GetPointerIds().size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_2)) ||
        (event.GetPointerId() != draggingPid_)) {
        return;
    }

    receivedPointerEvents_.push_back(event);

    std::vector<int32_t> pIds = event.GetPointerIds();
    if (IsDragGestureAccept(event)) {
        int32_t removePid = draggingPid_ == pIds[0] ? pIds[1] : pIds[0];
        event.RemovePointerItem(removePid);
        SendEventToMultimodal(event, ChangeAction::POINTER_DOWN);
        draggingDownEvent_ = std::make_shared<MMI::PointerEvent>(event);
        SetCurrentState(TouchExplorationState::TWO_FINGERS_DRAG);
        return;
    }
}

void TouchExploration::HandleThreeFingersDownStateDown(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);
    CancelPostEvent(TouchExplorationMsg::THREE_FINGER_SINGLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::THREE_FINGER_LONG_PRESS_MSG);

    if (event.GetPointerIds().size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_4)) {
        CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
        return;
    }

    if (!handler_->HasInnerEvent(static_cast<uint32_t>(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG))) {
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
        return;
    }

    CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
    handler_->SendEvent(static_cast<uint32_t>(TouchExplorationMsg::FOUR_FINGER_SINGLE_TAP_MSG), 0,
        static_cast<int32_t>(TimeoutDuration::DOUBLE_TAP_TIMEOUT));
    handler_->SendEvent(static_cast<uint32_t>(TouchExplorationMsg::FOUR_FINGER_LONG_PRESS_MSG), 0,
        static_cast<int32_t>(TimeoutDuration::DOUBLE_TAP_TIMEOUT));
    SetCurrentState(TouchExplorationState::FOUR_FINGERS_DOWN);
}

void TouchExploration::HandleThreeFingersDownStateUp(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);
    CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
    CancelPostEvent(TouchExplorationMsg::THREE_FINGER_LONG_PRESS_MSG);

    uint32_t pointerSize = event.GetPointerIds().size();
    if (pointerSize == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1)) {
        SetCurrentState(TouchExplorationState::THREE_FINGERS_TAP);
    } else if (pointerSize > static_cast<uint32_t>(PointerCount::POINTER_COUNT_3)) {
        CancelPostEvent(TouchExplorationMsg::THREE_FINGER_SINGLE_TAP_MSG);
        Clear();
        SetCurrentState(TouchExplorationState::INVALID);
    }
}

void TouchExploration::StoreMultiFingerSwipeBaseDownPoint()
{
    HILOG_DEBUG();
    for (auto& event : receivedPointerEvents_) {
        if (event.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_DOWN) {
            Pointer mp;
            MMI::PointerEvent::PointerItem pointerItem;
            std::vector<Pointer> mpVec;
            int32_t pId = event.GetPointerId();
            event.GetPointerItem(pId, pointerItem);
            mp.px_ = static_cast<float>(pointerItem.GetDisplayX());
            mp.py_ = static_cast<float>(pointerItem.GetDisplayY());
            mpVec.push_back(mp);
            multiFingerSwipeRoute_.insert(std::make_pair(pId, mpVec));
            multiFingerSwipePrePoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
        }
    }
}

void TouchExploration::HandleThreeFingersDownStateMove(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);

    MMI::PointerEvent::PointerItem pointerItem;
    event.GetPointerItem(event.GetPointerId(), pointerItem);

    MMI::PointerEvent::PointerItem basePointerItem;
    if (!GetBasePointItem(basePointerItem, event.GetPointerId())) {
        HILOG_ERROR("get base point item failed, pid = %{public}d.", event.GetPointerId());
        return;
    }

    int32_t offsetX = pointerItem.GetDisplayX() - basePointerItem.GetDisplayX();
    int32_t offsetY = pointerItem.GetDisplayY() - basePointerItem.GetDisplayY();
    if (hypot(offsetX, offsetY) > TOUCH_SLOP * static_cast<uint32_t>(PointerCount::POINTER_COUNT_3)) {
        CancelPostEvent(TouchExplorationMsg::WAIT_ANOTHER_FINGER_DOWN_MSG);
        CancelPostEvent(TouchExplorationMsg::THREE_FINGER_SINGLE_TAP_MSG);
        CancelPostEvent(TouchExplorationMsg::THREE_FINGER_LONG_PRESS_MSG);
        if (event.GetPointerIds().size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_3)) {
            Clear();
            SendScreenWakeUpEvent(event);
            SetCurrentState(TouchExplorationState::INVALID);
            return;
        }
        StoreMultiFingerSwipeBaseDownPoint();
        multiFingerSwipeDirection_ = GetSwipeDirection(offsetX, offsetY);
        SetCurrentState(TouchExplorationState::THREE_FINGERS_SWIPE);
    }

    SendScreenWakeUpEvent(event);
}

void TouchExploration::HandleThreeFingersSwipeStateDown(MMI::PointerEvent &event)
{
    Clear();
    SetCurrentState(TouchExplorationState::INVALID);
}

// LCOV_EXCL_START
bool TouchExploration::GetMultiFingerSwipeBasePointerItem(MMI::PointerEvent::PointerItem &basePointerItem, int32_t pId)
{
    HILOG_DEBUG();
    if (multiFingerSwipePrePoint_.count(pId) == 0 || !multiFingerSwipePrePoint_[pId]) {
        HILOG_ERROR("get base pointEvent(%{public}d) failed", pId);
        return false;
    }
    if (multiFingerSwipePrePoint_[pId] == nullptr) {
        HILOG_ERROR("multiFingerSwipePrePoint_ get pointEvent(%{public}d) occurred null pointer.", pId);
        return false;
    }
    multiFingerSwipePrePoint_[pId]->GetPointerItem(pId, basePointerItem);
    return true;
}

bool TouchExploration::SaveMultiFingerSwipeGesturePointerInfo(MMI::PointerEvent &event)
{
    HILOG_DEBUG();
    MMI::PointerEvent::PointerItem pointerItem;
    int32_t pId = event.GetPointerId();
    event.GetPointerItem(pId, pointerItem);

    MMI::PointerEvent::PointerItem basePointerItem;
    if (!GetMultiFingerSwipeBasePointerItem(basePointerItem, pId)) {
        HILOG_WARN("get base point item failed, pid = %{public}d.", pId);
        return true;
    }

    int32_t offsetX = pointerItem.GetDisplayX() - basePointerItem.GetDisplayX();
    int32_t offsetY = pointerItem.GetDisplayY() - basePointerItem.GetDisplayY();
    if (abs(offsetX) > mMinPixelsBetweenSamplesX_ || abs(offsetY) > mMinPixelsBetweenSamplesY_) {
        if (multiFingerSwipeDirection_ != GetSwipeDirection(offsetX, offsetY)) {
            Clear();
            if ((event.GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_UP) &&
                (event.GetPointerIds().size() == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1))) {
                SetCurrentState(TouchExplorationState::TOUCH_INIT);
            } else {
                SetCurrentState(TouchExplorationState::INVALID);
            }
            return false;
        }

        Pointer mp;
        mp.px_ = static_cast<float>(pointerItem.GetDisplayX());
        mp.py_ = static_cast<float>(pointerItem.GetDisplayY());
        multiFingerSwipeRoute_[pId].push_back(mp);
        multiFingerSwipePrePoint_[pId] = std::make_shared<MMI::PointerEvent>(event);
    }

    return true;
}

bool TouchExploration::RecognizeMultiFingerSwipePath(const std::vector<Pointer> &path)
{
    HILOG_DEBUG();
    if (path.size() < MIN_MULTI_FINGER_SWIPE_POINTER_NUM) {
        return false;
    }

    int pathSize = static_cast<int>(path.size() - 1);
    for (int routerIndex = 0; routerIndex < pathSize; routerIndex++) {
        int32_t dx = static_cast<int32_t>(path[routerIndex + 1].px_ - path[routerIndex].px_);
        int32_t dy = static_cast<int32_t>(path[routerIndex + 1].py_ - path[routerIndex].py_);
        if (GetSwipeDirection(dx, dy) != multiFingerSwipeDirection_) {
            return false;
        }
    }
    return true;
}

GestureType TouchExploration::GetMultiFingerSwipeGestureId(uint32_t fingerNum)
{
    HILOG_DEBUG();
    if (fingerNum == static_cast<uint32_t>(PointerCount::POINTER_COUNT_3)) {
        switch (multiFingerSwipeDirection_) {
            case SWIPE_LEFT:
                return GestureType::GESTURE_THREE_FINGER_SWIPE_LEFT;
            case SWIPE_RIGHT:
                return GestureType::GESTURE_THREE_FINGER_SWIPE_RIGHT;
            case SWIPE_UP:
                return GestureType::GESTURE_THREE_FINGER_SWIPE_UP;
            case SWIPE_DOWN:
                return GestureType::GESTURE_THREE_FINGER_SWIPE_DOWN;
            default:
                return GestureType::GESTURE_INVALID;
        }
    } else if (fingerNum == static_cast<uint32_t>(PointerCount::POINTER_COUNT_4)) {
        switch (multiFingerSwipeDirection_) {
            case SWIPE_LEFT:
                return GestureType::GESTURE_FOUR_FINGER_SWIPE_LEFT;
            case SWIPE_RIGHT:
                return GestureType::GESTURE_FOUR_FINGER_SWIPE_RIGHT;
            case SWIPE_UP:
                return GestureType::GESTURE_FOUR_FINGER_SWIPE_UP;
            case SWIPE_DOWN:
                return GestureType::GESTURE_FOUR_FINGER_SWIPE_DOWN;
            default:
                return GestureType::GESTURE_INVALID;
        }
    }
    return GestureType::GESTURE_INVALID;
}

void TouchExploration::HandleMultiFingersSwipeStateUp(MMI::PointerEvent &event, uint32_t fingerNum)
{
    receivedPointerEvents_.push_back(event);

    if (!SaveMultiFingerSwipeGesturePointerInfo(event)) {
        return;
    }

    if (event.GetPointerIds().size() == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1)) {
        if (fingerNum > static_cast<uint32_t>(INT32_MAX)) {
            SetCurrentState(TouchExplorationState::TOUCH_INIT);
            return;
        }
        for (auto &pair : multiFingerSwipeRoute_) {
            if (pair.second.size() < MIN_MULTI_FINGER_SWIPE_POINTER_NUM) {
                Clear();
                SetCurrentState(TouchExplorationState::TOUCH_INIT);
                return;
            }
            if (!RecognizeMultiFingerSwipePath(pair.second)) {
                Clear();
                SetCurrentState(TouchExplorationState::TOUCH_INIT);
                return;
            }
        }

        GestureType gestureId = GetMultiFingerSwipeGestureId(fingerNum);
        SendGestureEventToAA(gestureId, event.GetTargetDisplayId());
        Clear();
        SetCurrentState(TouchExplorationState::TOUCH_INIT);
    }
}

void TouchExploration::HandleThreeFingersSwipeStateUp(MMI::PointerEvent &event)
{
    HandleMultiFingersSwipeStateUp(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_3));
}

void TouchExploration::HandleThreeFingersSwipeStateMove(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);
    SaveMultiFingerSwipeGesturePointerInfo(event);
    SendScreenWakeUpEvent(event);
}

void TouchExploration::HandleThreeFingersTapStateDown(MMI::PointerEvent &event)
{
    HandleMultiFingersTapStateDown(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_3));
}

void TouchExploration::HandleThreeFingersTapStateMove(MMI::PointerEvent &event)
{
    HandleMultiFingersTapStateMove(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_3));
}

void TouchExploration::HandleThreeFingersContinueDownStateUp(MMI::PointerEvent &event)
{
    HandleMultiFingersContinueDownStateUp(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_3));
}

void TouchExploration::HandleThreeFingersContinueDownStateMove(MMI::PointerEvent &event)
{
    HandleMultiFingersContinueDownStateMove(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_3));
}

void TouchExploration::HandleFourFingersDownStateDown(MMI::PointerEvent &event)
{
    Clear();
    CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_SINGLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_LONG_PRESS_MSG);
    SetCurrentState(TouchExplorationState::INVALID);
}

void TouchExploration::HandleFourFingersDownStateUp(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);
    CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_LONG_PRESS_MSG);

    uint32_t pointerSize = event.GetPointerIds().size();
    if (pointerSize == static_cast<uint32_t>(PointerCount::POINTER_COUNT_1)) {
        SetCurrentState(TouchExplorationState::FOUR_FINGERS_TAP);
    } else if (pointerSize > static_cast<uint32_t>(PointerCount::POINTER_COUNT_4)) {
        Clear();
        CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_SINGLE_TAP_MSG);
        SetCurrentState(TouchExplorationState::INVALID);
    }
}

void TouchExploration::HandleFourFingersDownStateMove(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);

    MMI::PointerEvent::PointerItem pointerItem;
    event.GetPointerItem(event.GetPointerId(), pointerItem);
    MMI::PointerEvent::PointerItem basePointerItem;
    if (!GetBasePointItem(basePointerItem, event.GetPointerId())) {
        HILOG_ERROR("get base point item failed, pid = %{public}d.", event.GetPointerId());
        return;
    }

    int32_t offsetX = pointerItem.GetDisplayX() - basePointerItem.GetDisplayX();
    int32_t offsetY = pointerItem.GetDisplayY() - basePointerItem.GetDisplayY();
    if (hypot(offsetX, offsetY) > TOUCH_SLOP * static_cast<uint32_t>(PointerCount::POINTER_COUNT_4)) {
        CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_SINGLE_TAP_MSG);
        CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_LONG_PRESS_MSG);
        if (event.GetPointerIds().size() != static_cast<uint32_t>(PointerCount::POINTER_COUNT_4)) {
            Clear();
            SendScreenWakeUpEvent(event);
            SetCurrentState(TouchExplorationState::INVALID);
            return;
        }
        StoreMultiFingerSwipeBaseDownPoint();
        multiFingerSwipeDirection_ = GetSwipeDirection(offsetX, offsetY);
        SetCurrentState(TouchExplorationState::FOUR_FINGERS_SWIPE);
    }

    SendScreenWakeUpEvent(event);
}

void TouchExploration::HandleFourFingersSwipeStateDown(MMI::PointerEvent &event)
{
    Clear();
    SetCurrentState(TouchExplorationState::INVALID);
}

void TouchExploration::HandleFourFingersSwipeStateUp(MMI::PointerEvent &event)
{
    HandleMultiFingersSwipeStateUp(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_4));
}

void TouchExploration::HandleFourFingersSwipeStateMove(MMI::PointerEvent &event)
{
    receivedPointerEvents_.push_back(event);
    SaveMultiFingerSwipeGesturePointerInfo(event);
    SendScreenWakeUpEvent(event);
}

void TouchExploration::HandleFourFingersTapStateDown(MMI::PointerEvent &event)
{
    HandleMultiFingersTapStateDown(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_4));
}

void TouchExploration::HandleFourFingersTapStateMove(MMI::PointerEvent &event)
{
    HandleMultiFingersTapStateMove(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_4));
}
// LCOV_EXCL_STOP

void TouchExploration::HandleFourFingersContinueDownStateUp(MMI::PointerEvent &event)
{
    HandleMultiFingersContinueDownStateUp(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_4));
}

void TouchExploration::HandleFourFingersContinueDownStateMove(MMI::PointerEvent &event)
{
    HandleMultiFingersContinueDownStateMove(event, static_cast<uint32_t>(PointerCount::POINTER_COUNT_4));
}

void TouchExploration::CancelPostEvent(TouchExplorationMsg msg)
{
    HILOG_DEBUG("innerEventID = %{public}u", static_cast<uint32_t>(msg));
    if (handler_->HasInnerEvent(static_cast<uint32_t>(msg))) {
        handler_->RemoveEvent(static_cast<uint32_t>(msg));
    }
}

void TouchExploration::CancelMultiFingerTapEvent()
{
    CancelPostEvent(TouchExplorationMsg::TWO_FINGER_SINGLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::TWO_FINGER_DOUBLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::TWO_FINGER_TRIPLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::THREE_FINGER_SINGLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::THREE_FINGER_DOUBLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::THREE_FINGER_TRIPLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_SINGLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_DOUBLE_TAP_MSG);
    CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_TRIPLE_TAP_MSG);
}

void TouchExploration::CancelMultiFingerTapAndHoldEvent()
{
    CancelPostEvent(TouchExplorationMsg::TWO_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
    CancelPostEvent(TouchExplorationMsg::TWO_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
    CancelPostEvent(TouchExplorationMsg::THREE_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
    CancelPostEvent(TouchExplorationMsg::THREE_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
    CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
    CancelPostEvent(TouchExplorationMsg::FOUR_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
}
} // namespace Accessibility
} // namespace OHOS