/*
 * Copyright (C) 2022 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 "accessible_ability_channel_proxy.h"

#include <cinttypes>

#include "accessibility_element_info_parcel.h"
#include "accessibility_gesture_inject_path_parcel.h"
#include "accessibility_ipc_interface_code.h"
#include "accessibility_window_info_parcel.h"
#include "hilog_wrapper.h"
#include "accessibility_constants.h"

namespace OHOS {
namespace Accessibility {
AccessibleAbilityChannelProxy::AccessibleAbilityChannelProxy(
    const sptr<IRemoteObject> &object): IRemoteProxy<IAccessibleAbilityChannel>(object)
{
}

bool AccessibleAbilityChannelProxy::WriteInterfaceToken(MessageParcel &data)
{
    HILOG_DEBUG();

    if (!data.WriteInterfaceToken(AccessibleAbilityChannelProxy::GetDescriptor())) {
        HILOG_ERROR("write interface token failed");
        return false;
    }
    return true;
}

bool AccessibleAbilityChannelProxy::SendTransactCmd(AccessibilityInterfaceCode code,
    MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
    HILOG_DEBUG();

    sptr<IRemoteObject> remoteChannelProxy = Remote();
    if (remoteChannelProxy == nullptr) {
        HILOG_ERROR("fail to send transact cmd %{public}d due to remote object", code);
        return false;
    }
    int32_t resultChannelProxy = remoteChannelProxy->SendRequest(static_cast<uint32_t>(code), data, reply, option);
    if (resultChannelProxy != NO_ERROR) {
        HILOG_ERROR("receive error transact code %{public}d in transact cmd %{public}d", resultChannelProxy, code);
        return false;
    }
    return true;
}

bool AccessibleAbilityChannelProxy::WriteActionArguments(MessageParcel &data,
    const std::map<std::string, std::string> &actionArguments)
{
    std::vector<std::string> actionArgumentsKey {};
    std::vector<std::string> actionArgumentsValue {};
    for (auto iter = actionArguments.begin(); iter != actionArguments.end(); iter++) {
        actionArgumentsKey.push_back(iter->first);
        actionArgumentsValue.push_back(iter->second);
    }
    if (!data.WriteStringVector(actionArgumentsKey)) {
        HILOG_ERROR("actionArgumentsKey write error");
        return false;
    }
    if (!data.WriteStringVector(actionArgumentsValue)) {
        HILOG_ERROR("actionArgumentsValue write error");
        return false;
    }
    return true;
}

bool AccessibleAbilityChannelProxy::WriteAccessibilityVirtualNode(MessageParcel &data,
    const AccessibilityVirtualNode& accessibilityVirtualNode)
{
    if (!WriteVirtualNodeBasicProperties(data, accessibilityVirtualNode)) {
        return false;
    }
    if (!WriteVirtualNodeRectProperties(data, accessibilityVirtualNode)) {
        return false;
    }
    if (!WriteVirtualNodeBoolProperties(data, accessibilityVirtualNode)) {
        return false;
    }
    if (!WriteVirtualNodeOtherProperties(data, accessibilityVirtualNode)) {
        return false;
    }
    if (!WriteVirtualNodeRelationProperties(data, accessibilityVirtualNode)) {
        return false;
    }
    return true;
}

bool AccessibleAbilityChannelProxy::WriteVirtualNodeBasicProperties(MessageParcel &data,
    const AccessibilityVirtualNode& accessibilityVirtualNode)
{
    if (!data.WriteInt64(accessibilityVirtualNode.GetId())) {
        HILOG_ERROR("id write error: %{public}" PRId64 "", accessibilityVirtualNode.GetId());
        return false;
    }
    if (!data.WriteString(accessibilityVirtualNode.GetText())) {
        HILOG_ERROR("text write error");
        return false;
    }
    if (!data.WriteString(accessibilityVirtualNode.GetAccessibilityText())) {
        HILOG_ERROR("accessibilityText write error");
        return false;
    }
    if (!data.WriteBool(accessibilityVirtualNode.GetAccessibilityGroup())) {
        HILOG_ERROR("accessibilityGroup write error");
        return false;
    }
    if (!data.WriteString(accessibilityVirtualNode.GetAccessibilityLevel())) {
        HILOG_ERROR("accessibilityLevel write error");
        return false;
    }
    return true;
}

bool AccessibleAbilityChannelProxy::WriteVirtualNodeRectProperties(MessageParcel &data,
    const AccessibilityVirtualNode& accessibilityVirtualNode)
{
    if (!data.WriteInt32(accessibilityVirtualNode.GetRect().GetLeftTopXScreenPostion())) {
        HILOG_ERROR("rect leftTopX write error");
        return false;
    }
    if (!data.WriteInt32(accessibilityVirtualNode.GetRect().GetLeftTopYScreenPostion())) {
        HILOG_ERROR("rect leftTopY write error");
        return false;
    }
    if (!data.WriteInt32(accessibilityVirtualNode.GetRect().GetRightBottomXScreenPostion())) {
        HILOG_ERROR("rect rightBottomX write error");
        return false;
    }
    if (!data.WriteInt32(accessibilityVirtualNode.GetRect().GetRightBottomYScreenPostion())) {
        HILOG_ERROR("rect rightBottomY write error");
        return false;
    }
    return true;
}

bool AccessibleAbilityChannelProxy::WriteVirtualNodeBoolProperties(MessageParcel &data,
    const AccessibilityVirtualNode& accessibilityVirtualNode)
{
    if (!data.WriteBool(accessibilityVirtualNode.GetCheckable())) {
        HILOG_ERROR("checkable write error");
        return false;
    }
    if (!data.WriteBool(accessibilityVirtualNode.GetChecked())) {
        HILOG_ERROR("checked write error");
        return false;
    }
    if (!data.WriteBool(accessibilityVirtualNode.GetClickable())) {
        HILOG_ERROR("clickable write error");
        return false;
    }
    if (!data.WriteBool(accessibilityVirtualNode.GetEnabled())) {
        HILOG_ERROR("enabled write error");
        return false;
    }
    if (!data.WriteBool(accessibilityVirtualNode.GetSelected())) {
        HILOG_ERROR("selected write error");
        return false;
    }
    return true;
}

bool AccessibleAbilityChannelProxy::WriteVirtualNodeOtherProperties(MessageParcel &data,
    const AccessibilityVirtualNode& accessibilityVirtualNode)
{
    if (!data.WriteString(accessibilityVirtualNode.GetCustomComponentType())) {
        HILOG_ERROR("customComponentType write error");
        return false;
    }
    if (!data.WriteInt32(accessibilityVirtualNode.GetPoint().GetX())) {
        HILOG_ERROR("point.x write error");
        return false;
    }
    if (!data.WriteInt32(accessibilityVirtualNode.GetPoint().GetY())) {
        HILOG_ERROR("point.y write error");
        return false;
    }
    if (!data.WriteBool(accessibilityVirtualNode.GetAccessibilityFocused())) {
        HILOG_ERROR("accessibilityFocused write error");
        return false;
    }
    return true;
}

bool AccessibleAbilityChannelProxy::WriteVirtualNodeRelationProperties(MessageParcel &data,
    const AccessibilityVirtualNode& accessibilityVirtualNode)
{
    if (!data.WriteInt64(accessibilityVirtualNode.GetParentId())) {
        HILOG_ERROR("parentId write error: %{public}" PRId64 "", accessibilityVirtualNode.GetParentId());
        return false;
    }
    int32_t childNodeCount = accessibilityVirtualNode.GetChildNodeIds().size();
    if (childNodeCount > MAX_ALLOW_SIZE) {
        HILOG_ERROR("childNodeCount exceeds MAX_ALLOW_SIZE");
        return false;
    }
    if (!data.WriteInt32(childNodeCount)) {
        HILOG_ERROR("childNodeCount write error");
        return false;
    }
    for (int32_t i = 0; i < childNodeCount; i++) {
        if (!data.WriteInt64(accessibilityVirtualNode.GetChildNodeIds()[i])) {
            HILOG_ERROR("childNodeId[%{public}d] write error", i);
            return false;
        }
    }
    if (!data.WriteInt64(accessibilityVirtualNode.GetElementId())) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 "", accessibilityVirtualNode.GetElementId());
        return false;
    }
    if (!data.WriteInt32(accessibilityVirtualNode.GetWindowId())) {
        HILOG_ERROR("windowId write error: %{public}d", accessibilityVirtualNode.GetWindowId());
        return false;
    }
    return true;
}

RetError AccessibleAbilityChannelProxy::SearchElementInfoByAccessibilityId(const ElementBasicInfo elementBasicInfo,
    const int32_t requestId, const sptr<IAccessibilityElementOperatorCallback> &callback,
    const int32_t mode, bool isFilter, bool systemApi)
{
    HILOG_DEBUG();
    if (callback == nullptr) {
        HILOG_ERROR("callback is nullptr.");
        return RET_ERR_INVALID_PARAM;
    }

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(elementBasicInfo.windowId)) {
        HILOG_ERROR("windowId write error: %{public}d, ", elementBasicInfo.windowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(elementBasicInfo.treeId)) {
        HILOG_ERROR("treeId write error: %{public}d", elementBasicInfo.treeId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(elementBasicInfo.elementId)) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 "", elementBasicInfo.elementId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(mode)) {
        HILOG_ERROR("mode write error: %{public}d, ", mode);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(isFilter)) {
        HILOG_ERROR("isFilter write error: %{public}d, ", isFilter);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(systemApi)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::SEARCH_ELEMENTINFO_BY_ACCESSIBILITY_ID,
        data, reply, option)) {
        HILOG_ERROR("fail to find elementInfo by elementId");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::SearchDefaultFocusedByWindowId(const ElementBasicInfo elementBasicInfo,
    const int32_t requestId, const sptr<IAccessibilityElementOperatorCallback> &callback,
    const int32_t mode, bool isFilter)
{
    HILOG_DEBUG();
    if (callback == nullptr) {
        HILOG_ERROR("callback is nullptr.");
        return RET_ERR_INVALID_PARAM;
    }
 
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
 
    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(elementBasicInfo.windowId)) {
        HILOG_ERROR("windowId write error: %{public}d, ", elementBasicInfo.windowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(elementBasicInfo.elementId)) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 "", elementBasicInfo.elementId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(elementBasicInfo.treeId)) {
        HILOG_ERROR("treeId write error: %{public}d, ", elementBasicInfo.treeId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(mode)) {
        HILOG_ERROR("mode write error: %{public}d, ", mode);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(isFilter)) {
        HILOG_ERROR("isFilter write error: %{public}d, ", isFilter);
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::SEARCH_DEFAULTFOCUSED_BY_WINDOW_ID,
        data, reply, option)) {
        HILOG_ERROR("fail to find elementInfo by elementId");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::SearchElementInfosByText(const int32_t accessibilityWindowId,
    const int64_t elementId, const std::string &text, const int32_t requestId,
    const sptr<IAccessibilityElementOperatorCallback> &callback, bool systemApi)
{
    HILOG_DEBUG();

    if (callback == nullptr) {
        HILOG_ERROR("callback is nullptr.");
        return RET_ERR_INVALID_PARAM;
    }

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(accessibilityWindowId)) {
        HILOG_ERROR("accessibilityWindowId write error: %{public}d, ", accessibilityWindowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(elementId)) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 "", elementId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteString(text)) {
        HILOG_ERROR("text write error: %{public}s, ", text.c_str());
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(systemApi)) {
        HILOG_ERROR("systemApi write error: %{public}d, ", systemApi);
        return RET_ERR_IPC_FAILED;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::SEARCH_ELEMENTINFOS_BY_TEXT,
        data, reply, option)) {
        HILOG_ERROR("fail to find elementInfo by text");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::FindFocusedElementInfo(const int32_t accessibilityWindowId,
    const int64_t elementId, const int32_t focusType, const int32_t requestId,
    const sptr<IAccessibilityElementOperatorCallback> &callback, bool systemApi)
{
    HILOG_DEBUG();
    if (callback == nullptr) {
        HILOG_ERROR("callback is nullptr.");
        return RET_ERR_INVALID_PARAM;
    }

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(accessibilityWindowId)) {
        HILOG_ERROR("accessibilityWindowId write error: %{public}d, ", accessibilityWindowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(elementId)) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 "", elementId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(focusType)) {
        HILOG_ERROR("focusType write error: %{public}d, ", focusType);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(systemApi)) {
        HILOG_ERROR("systemApi write error: %{public}d, ", systemApi);
        return RET_ERR_IPC_FAILED;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::FIND_FOCUSED_ELEMENTINFO, data, reply, option)) {
        HILOG_ERROR("fail to gain focus");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::FocusMoveSearch(const int32_t accessibilityWindowId, const int64_t elementId,
    const int32_t direction, const int32_t requestId, const sptr<IAccessibilityElementOperatorCallback> &callback,
    bool systemApi)
{
    HILOG_DEBUG();
    if (callback == nullptr) {
        HILOG_ERROR("callback is nullptr.");
        return RET_ERR_INVALID_PARAM;
    }

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(accessibilityWindowId)) {
        HILOG_ERROR("accessibilityWindowId write error: %{public}d, ", accessibilityWindowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(elementId)) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 "", elementId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(direction)) {
        HILOG_ERROR("direction write error: %{public}d, ", direction);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(systemApi)) {
        HILOG_ERROR("systemApi write error: %{public}d, ", systemApi);
        return RET_ERR_IPC_FAILED;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::FOCUS_MOVE_SEARCH, data, reply, option)) {
        HILOG_ERROR("fail to search focus");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::EnableScreenCurtain(bool isEnable)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(isEnable)) {
        HILOG_ERROR("isEnable write error: %{public}d, ", isEnable);
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::SET_CURTAIN_SCREEN,
        data, reply, option)) {
        HILOG_ERROR("fail to enable screen curtain");
        return RET_ERR_IPC_FAILED;
    }

    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::HoldRunningLock()
{
    HILOG_DEBUG();
 
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
 
    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
 
    if (!SendTransactCmd(AccessibilityInterfaceCode::HOLD_RUNNING_LOCK,
        data, reply, option)) {
        HILOG_ERROR("fail to hold the running lock");
        return RET_ERR_IPC_FAILED;
    }
 
    return static_cast<RetError>(reply.ReadInt32());
}
 
RetError AccessibleAbilityChannelProxy::UnholdRunningLock()
{
    HILOG_DEBUG();
 
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
 
    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::UNHOLD_RUNNING_LOCK,
        data, reply, option)) {
        HILOG_ERROR("fail to unhold the running lock");
        return RET_ERR_IPC_FAILED;
    }
 
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::ExecuteAction(const int32_t accessibilityWindowId, const int64_t elementId,
    const int32_t action, const std::map<std::string, std::string> &actionArguments, const int32_t requestId,
    const sptr<IAccessibilityElementOperatorCallback> &callback, const Rect &rect)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(accessibilityWindowId)) {
        HILOG_ERROR("accessibilityWindowId write error: %{public}d, ", accessibilityWindowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(elementId)) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 "", elementId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(action)) {
        HILOG_ERROR("action write error: %{public}d, ", action);
        return RET_ERR_IPC_FAILED;
    }
    if (!WriteActionArguments(data, actionArguments)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (callback == nullptr || !data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    RectParcel rectParcel(rect);
    if (!data.WriteParcelable(&rectParcel)) {
        HILOG_ERROR("rect write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::PERFORM_ACTION,
        data, reply, option)) {
        HILOG_ERROR("fail to perform accessibility action");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::GetWindow(const int32_t windowId, AccessibilityWindowInfo &windowInfo)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }

    if (!data.WriteInt32(windowId)) {
        HILOG_ERROR("windowId write error: %{public}d, ", windowId);
        return RET_ERR_IPC_FAILED;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::GET_WINDOW, data, reply, option)) {
        HILOG_ERROR("fail to get window");
        return RET_ERR_IPC_FAILED;
    }

    sptr<AccessibilityWindowInfoParcel> windowInfoParcel = reply.ReadStrongParcelable<AccessibilityWindowInfoParcel>();
    if (windowInfoParcel == nullptr) {
        HILOG_ERROR("ReadStrongParcelable<AccessibilityWindowInfoParcel> failed");
        return RET_ERR_IPC_FAILED;
    }
    windowInfo = *windowInfoParcel;

    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::GetWindows(std::vector<AccessibilityWindowInfo> &windows, bool systemApi)
{
    HILOG_DEBUG();
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(systemApi)) {
        HILOG_ERROR("systemApi write error: %{public}d, ", systemApi);
        return RET_ERR_IPC_FAILED;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::GET_WINDOWS, data, reply, option)) {
        HILOG_ERROR("fail to get windows");
        return RET_ERR_IPC_FAILED;
    }

    int32_t windowsSize = reply.ReadInt32();
    if (windowsSize < 0 || windowsSize > MAX_ALLOW_SIZE) {
        HILOG_ERROR("windowsSize is invalid");
        return RET_ERR_INVALID_PARAM;
    }

    for (int32_t i = 0; i < windowsSize; i++) {
        sptr<AccessibilityWindowInfoParcel> window = reply.ReadStrongParcelable<AccessibilityWindowInfoParcel>();
        if (window == nullptr) {
            HILOG_ERROR("ReadStrongParcelable<AccessibilityWindowInfoParcel> failed");
            return RET_ERR_IPC_FAILED;
        }
        windows.emplace_back(*window);
    }

    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::GetWindowsByDisplayId(const uint64_t displayId,
    std::vector<AccessibilityWindowInfo> &windows, bool systemApi)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }

    if (!data.WriteUint64(displayId)) {
        HILOG_ERROR("displayId write error: %{public}" PRIu64 ", ", displayId);
        return RET_ERR_IPC_FAILED;
    }

    if (!data.WriteBool(systemApi)) {
        HILOG_ERROR("systemApi write error: %{public}d, ", systemApi);
        return RET_ERR_IPC_FAILED;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::GET_WINDOWS_BY_DISPLAY_ID, data, reply, option)) {
        HILOG_ERROR("fail to get windows");
        return RET_ERR_IPC_FAILED;
    }

    int32_t windowsSize = reply.ReadInt32();
    if (windowsSize < 0 || windowsSize > MAX_ALLOW_SIZE) {
        HILOG_ERROR("windowsSize is invalid");
        return RET_ERR_INVALID_PARAM;
    }

    for (int32_t i = 0; i < windowsSize; i++) {
        sptr<AccessibilityWindowInfoParcel> window = reply.ReadStrongParcelable<AccessibilityWindowInfoParcel>();
        if (window == nullptr) {
            HILOG_ERROR("ReadStrongParcelable<AccessibilityWindowInfoParcel> failed");
            return RET_ERR_IPC_FAILED;
        }
        windows.emplace_back(*window);
    }

    return static_cast<RetError>(reply.ReadInt32());
}

void AccessibleAbilityChannelProxy::SetOnKeyPressEventResult(const bool handled, const int32_t sequence)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_ASYNC);

    if (!WriteInterfaceToken(data)) {
        return;
    }
    if (!data.WriteBool(handled)) {
        HILOG_ERROR("handled write error: %{public}d, ", handled);
        return;
    }
    if (!data.WriteInt32(sequence)) {
        HILOG_ERROR("sequence write error: %{public}d, ", sequence);
        return;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::SET_ON_KEY_PRESS_EVENT_RESULT,
        data, reply, option)) {
        HILOG_ERROR("fail to set onKeyPressEvent result");
    }
}

RetError AccessibleAbilityChannelProxy::GetCursorPosition(const int32_t accessibilityWindowId, const int64_t elementId,
    const int32_t requestId, const sptr<IAccessibilityElementOperatorCallback> &callback)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_ASYNC);
    if (!WriteInterfaceToken(data)) {
        return RET_ERR_FAILED;
    }
    if (!data.WriteInt32(accessibilityWindowId)) {
        HILOG_ERROR("accessibilityWindowId write error: %{public}d, ", accessibilityWindowId);
        return RET_ERR_FAILED;
    }
    if (!data.WriteInt64(elementId)) {
        HILOG_ERROR("elementId write error");
        return RET_ERR_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (callback == nullptr) {
        HILOG_ERROR("callback is null");
        return RET_ERR_FAILED;
    }
    if (callback->AsObject() == nullptr) {
        HILOG_ERROR("callback->AsObject() is null");
        return RET_ERR_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::GET_CURSOR_POSITION,
        data, reply, option)) {
        HILOG_ERROR("fail to set onKeyPressEvent result");
        return RET_ERR_FAILED;
    }

    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::SendSimulateGesture(
    const std::shared_ptr<AccessibilityGestureInjectPath>& gesturePath)
{
    HILOG_DEBUG();
    sptr<AccessibilityGestureInjectPathParcel> path =
        new(std::nothrow) AccessibilityGestureInjectPathParcel(*gesturePath);
    if (path == nullptr) {
        HILOG_ERROR("Failed to create path.");
        return RET_ERR_NULLPTR;
    }

    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }

    if (!data.WriteStrongParcelable(path)) {
        HILOG_ERROR("WriteStrongParcelable<AccessibilityGestureInjectPathParcel> failed");
        return RET_ERR_IPC_FAILED;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::SEND_SIMULATE_GESTURE_PATH, data, reply, option)) {
        HILOG_ERROR("fail to send simulation gesture path");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::SetTargetBundleName(const std::vector<std::string> &targetBundleNames)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (targetBundleNames.size() > static_cast<size_t>(MAX_ALLOW_SIZE)) {
        HILOG_ERROR("targetBundleNames.size() exceeds MAX_ALLOW_SIZE: %{public}zu", targetBundleNames.size());
        return RET_ERR_INVALID_PARAM;
    }
    if (!data.WriteInt32(targetBundleNames.size())) {
        HILOG_ERROR("targetBundleNames.size() write error: %{public}zu, ", targetBundleNames.size());
        return RET_ERR_IPC_FAILED;
    }
    for (auto &targetBundleName : targetBundleNames) {
        if (!data.WriteString(targetBundleName)) {
            HILOG_ERROR("targetBundleName write error: %{public}s, ", targetBundleName.c_str());
            return RET_ERR_IPC_FAILED;
        }
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::SET_TARGET_BUNDLE_NAME, data, reply, option)) {
        HILOG_ERROR("fail to set target bundle name filter");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::SetIsRegisterDisconnectCallback(bool isRegister)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteBool(isRegister)) {
        HILOG_ERROR("isRegister write error: %{public}d, ", isRegister);
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::SET_IS_REGISTER_DISCONNECT_CALLBACK,
        data, reply, option)) {
        HILOG_ERROR("fail to SetIsRegisterDisconnectCallback");
        return RET_ERR_IPC_FAILED;
    }

    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::NotifyDisconnect()
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::NOTIFY_DISCONNECT,
        data, reply, option)) {
        HILOG_ERROR("fail to notify disconnect");
        return RET_ERR_IPC_FAILED;
    }

    return static_cast<RetError>(reply.ReadInt32());
}

void AccessibleAbilityChannelProxy::SearchElementInfoBySpecificProperty(const ElementBasicInfo elementBasicInfo,
    const SpecificPropertyParam& param, const int32_t requestId,
    const sptr<IAccessibilityElementOperatorCallback> &callback)
{
    HILOG_DEBUG("windowId:%{public}d, elementId:%{public}" PRId64 ", propertyTarget:%{public}s,"
        "propertyType:%{public}u, requestId:%{public}d", elementBasicInfo.windowId, elementBasicInfo.elementId,
        param.propertyTarget.c_str(), static_cast<uint32_t>(param.propertyType), requestId);
    if (callback == nullptr) {
        HILOG_ERROR("callback is nullptr.");
        return;
    }

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return;
    }
    if (!data.WriteInt32(elementBasicInfo.windowId)) {
        HILOG_ERROR("windowId write error: %{public}d, ", elementBasicInfo.windowId);
        return;
    }
    if (!data.WriteInt64(elementBasicInfo.elementId)) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 ", ", elementBasicInfo.elementId);
        return;
    }
    if (!data.WriteInt32(elementBasicInfo.treeId)) {
        HILOG_ERROR("treeId write error: %{public}d, ", elementBasicInfo.treeId);
        return;
    }
    if (!data.WriteString(param.propertyTarget)) {
        HILOG_ERROR("propertyTarget write error");
        return;
    }
    if (!data.WriteUint32(static_cast<uint32_t>(param.propertyType))) {
        HILOG_ERROR("propertyType write error");
        return;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return;
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::SEARCH_ELEMENTINFOS_BY_SPECIFIC_PROPERTY,
        data, reply, option)) {
        HILOG_ERROR("fail to find elementInfo by specific property");
        return;
    }
}

RetError AccessibleAbilityChannelProxy::ConfigureEvents(const std::vector<uint32_t> needEvents)
{
    HILOG_DEBUG();

    MessageParcel data;
    MessageParcel reply;
    MessageOption option(MessageOption::TF_SYNC);

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (needEvents.size() > static_cast<size_t>(MAX_ALLOW_SIZE)) {
        HILOG_ERROR("needEvents.size() exceeds MAX_ALLOW_SIZE: %{public}zu", needEvents.size());
        return RET_ERR_INVALID_PARAM;
    }
    if (!data.WriteInt32(needEvents.size())) {
        HILOG_ERROR("needEvents size write error: %{public}zu", needEvents.size());
        return RET_ERR_IPC_FAILED;
    }
    for (auto &needEvent : needEvents) {
        if (!data.WriteUint32(needEvent)) {
            HILOG_ERROR("needEvent write error: %{public}d", needEvent);
            return RET_ERR_IPC_FAILED;
        }
    }

    if (!SendTransactCmd(AccessibilityInterfaceCode::CONFIGURE_EVENTS,
        data, reply, option)) {
        HILOG_ERROR("fail to notify disconnect");
        return RET_ERR_IPC_FAILED;
    }

    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::FocusMoveSearchWithCondition(const AccessibilityElementInfo &info,
    const AccessibilityFocusMoveParam& param, const int32_t requestId,
    const sptr<IAccessibilityElementOperatorCallback> &callback, const int32_t windowId)
{
    if (callback == nullptr) {
        HILOG_ERROR("callback is nullptr.");
        return RET_ERR_NULLPTR;
    }

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
    AccessibilityElementInfoParcel infoParcel(info);

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteParcelable(&infoParcel)) {
        HILOG_ERROR("connection write info failed");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(param.direction)) {
        HILOG_ERROR("connection write direction failed");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(param.condition)) {
        HILOG_ERROR("connection write condition failed");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(param.type)) {
        HILOG_ERROR("connection write type failed");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(param.parentId)) {
        HILOG_ERROR("connection write parentId failed");
        return RET_ERR_IPC_FAILED;
    }

    if (!data.WriteBool(param.detectParent)) {
        HILOG_ERROR("connection write detectParent failed");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d, ", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(windowId)) {
        HILOG_ERROR("windowId write error: %{public}d, ", windowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::FOCUS_MOVE_SEARCH_WITH_CONDITION,
        data, reply, option)) {
        HILOG_ERROR("fail to find elementInfo by specific property");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}

RetError AccessibleAbilityChannelProxy::UpdateCustomAccessibilityProperty(const int64_t elementId,
    const int32_t windowId, const AccessibilityVirtualNode& accessibilityVirtualNode, const int32_t requestId,
    const sptr<IAccessibilityElementOperatorCallback> &callback)
{
    HILOG_DEBUG("elementId[%{public}" PRId64 "], windowId[%{public}d]", elementId, windowId);

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(elementId)) {
        HILOG_ERROR("elementId write error: %{public}" PRId64 "", elementId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(windowId)) {
        HILOG_ERROR("windowId write error: %{public}d", windowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!WriteAccessibilityVirtualNode(data, accessibilityVirtualNode)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::UPDATE_ACCESSIBILITY_ELEMENT_INFO,
        data, reply, option)) {
        HILOG_ERROR("fail to update accessibility element info");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}
 
RetError AccessibleAbilityChannelProxy::AddAccessibilityVirtualNode(const int64_t rootId,
    const int32_t windowId, const std::vector<AccessibilityVirtualNode> &nodes, const int32_t requestId,
    const sptr<IAccessibilityElementOperatorCallback> &callback)
{
    HILOG_DEBUG("rootId[%{public}" PRId64 "], windowId[%{public}d]", rootId, windowId);

    MessageParcel data;
    MessageParcel reply;
    MessageOption option;

    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(rootId)) {
        HILOG_ERROR("rootId write error: %{public}" PRId64 "", rootId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(windowId)) {
        HILOG_ERROR("windowId write error: %{public}d", windowId);
        return RET_ERR_IPC_FAILED;
    }
    int32_t nodeCount = nodes.size();
    if (nodeCount > MAX_ALLOW_SIZE) {
        HILOG_ERROR("nodes.size() exceeds MAX_ALLOW_SIZE");
        return RET_ERR_INVALID_PARAM;
    }
    if (!data.WriteInt32(nodeCount)) {
        HILOG_ERROR("nodeCount write error");
        return RET_ERR_IPC_FAILED;
    }
    for (int32_t i = 0; i < nodeCount; i++) {
        if (!WriteAccessibilityVirtualNode(data, nodes[i])) {
            HILOG_ERROR("node[%{public}d] write error", i);
            return RET_ERR_IPC_FAILED;
        }
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::ADD_ACCESSIBILITY_VIRTUAL_NODE,
        data, reply, option)) {
        HILOG_ERROR("fail to add accessibility virtual node");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}
 
RetError AccessibleAbilityChannelProxy::RemoveAccessibilityVirtualNode(const int64_t id,
    const int32_t windowId, const int32_t requestId,
    const sptr<IAccessibilityElementOperatorCallback> &callback)
{
    HILOG_DEBUG("id[%{public}" PRId64 "], windowId[%{public}d]", id, windowId);
 
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
 
    if (!WriteInterfaceToken(data)) {
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt64(id)) {
        HILOG_ERROR("id write error: %{public}" PRId64 "", id);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(windowId)) {
        HILOG_ERROR("windowId write error: %{public}d", windowId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteInt32(requestId)) {
        HILOG_ERROR("requestId write error: %{public}d", requestId);
        return RET_ERR_IPC_FAILED;
    }
    if (!data.WriteRemoteObject(callback->AsObject())) {
        HILOG_ERROR("callback write error");
        return RET_ERR_IPC_FAILED;
    }
    if (!SendTransactCmd(AccessibilityInterfaceCode::REMOVE_ACCESSIBILITY_VIRTUAL_NODE,
        data, reply, option)) {
        HILOG_ERROR("fail to remove accessibility virtual node");
        return RET_ERR_IPC_FAILED;
    }
    return static_cast<RetError>(reply.ReadInt32());
}
} // namespace Accessibility
} // namespace OHOS