/*
* Copyright (C) 2025 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 <array>
#include <iostream>
#include "ani_accessibility_config.h"
#include "accessibility_def.h"
#include "ani_utils.h"
#include "ipc_skeleton.h"
#include "accesstoken_kit.h"
#include "hilog_wrapper.h"
#include <ani_signature_builder.h>

using namespace OHOS;
using namespace OHOS::Accessibility;
using namespace Security::AccessToken;
using CONFIG_ID = OHOS::AccessibilityConfig::CONFIG_ID;
using ConfigValue = OHOS::AccessibilityConfig::ConfigValue;

constexpr int32_t ANI_SCOPE_SIZE = 16;
const std::string DEFAULT_FONT_FAMILY = "default";
constexpr uint32_t DEFAULT_FONT_SCALE = 75;
constexpr uint32_t DEFAULT_COLOR = 0xff000000;
const std::string DEFAULT_FONT_EDGE_TYPE = "none";

std::shared_ptr<EnableAbilityListsObserverImpl> ANIAccessibilityConfig::enableAbilityListsObservers_ =
    std::make_shared<EnableAbilityListsObserverImpl>();
std::shared_ptr<ANIAccessibilityConfigObserverImpl> ANIAccessibilityConfig::configObservers_ =
    std::make_shared<ANIAccessibilityConfigObserverImpl>();
std::shared_ptr<EnableAbilityCallbackObserverImpl> ANIAccessibilityConfig::enableAbilityCallbackObservers_ =
    std::make_shared<EnableAbilityCallbackObserverImpl>();
std::shared_ptr<SeniorModeStateObserverImpl> ANIAccessibilityConfig::seniorModeStateObservers_ =
    std::make_shared<SeniorModeStateObserverImpl>();

void EnableAbilityListsObserver::OnEnableAbilityListsStateChanged()
{
    HILOG_DEBUG();
    std::shared_ptr<AccessibilityCallbackInfo> callbackInfo = std::make_shared<AccessibilityCallbackInfo>();
    if (callbackInfo == nullptr) {
        HILOG_ERROR("Failed to create callbackInfo");
        return;
    }
    callbackInfo->env_ = env_;
    callbackInfo->fnRef_ = callback_;
    auto task = [callbackInfo]() {
        HILOG_INFO("on enable ability lists state changed");
        ani_env *tmpEnv = callbackInfo->env_;
        ani_size nr_refs = ANI_SCOPE_SIZE;
        tmpEnv->CreateLocalScope(nr_refs);
        auto fnObj = reinterpret_cast<ani_fn_object>(callbackInfo->fnRef_);
        ani_ref result;
        tmpEnv->FunctionalObject_Call(fnObj, 0, nullptr, &result);
        tmpEnv->DestroyLocalScope();
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void EnableAbilityListsObserverImpl::OnEnableAbilityListsStateChanged()
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto &observer : enableAbilityListsObservers_) {
        if (observer) {
            observer->OnEnableAbilityListsStateChanged();
        } else {
            HILOG_ERROR("observer is null");
        }
    }
}

void EnableAbilityListsObserverImpl::OnInstallAbilityListsStateChanged()
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto &observer : installAbilityListsObservers_) {
        if (observer) {
            observer->OnEnableAbilityListsStateChanged();
        } else {
            HILOG_ERROR("observer is null");
        }
    }
}

void EnableAbilityListsObserverImpl::SubscribeObserver(ani_env *env, ani_object observer)
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    ani_ref fnRef;
    env->GlobalReference_Create(observer, &fnRef);
    for (auto iter = enableAbilityListsObservers_.begin(); iter != enableAbilityListsObservers_.end(); iter++) {
        if (ANIUtils::CheckObserverEqual(env, fnRef, (*iter)->env_, (*iter)->callback_)) {
            env->GlobalReference_Delete(fnRef);
            HILOG_DEBUG("SubscribeObserver Observer exist");
            return;
        }
    }
    std::shared_ptr<EnableAbilityListsObserver> observerPtr = std::make_shared<EnableAbilityListsObserver>(env, fnRef);
    enableAbilityListsObservers_.emplace_back(observerPtr);
    HILOG_DEBUG("enableAbilityListsObservers size%{public}zu", enableAbilityListsObservers_.size());
}

void EnableAbilityListsObserverImpl::SubscribeInstallObserver(ani_env *env, ani_object observer)
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    ani_ref fnRef;
    env->GlobalReference_Create(observer, &fnRef);
    for (auto iter = installAbilityListsObservers_.begin(); iter != installAbilityListsObservers_.end(); iter++) {
        if (ANIUtils::CheckObserverEqual(env, fnRef, (*iter)->env_, (*iter)->callback_)) {
            env->GlobalReference_Delete(fnRef);
            HILOG_DEBUG("SubscribeObserver Observer exist");
            return;
        }
    }
    std::shared_ptr<EnableAbilityListsObserver> observerPtr = std::make_shared<EnableAbilityListsObserver>(env, fnRef);
    installAbilityListsObservers_.emplace_back(observerPtr);
    HILOG_DEBUG("installAbilityListsObservers_ size%{public}zu", installAbilityListsObservers_.size());
}

void EnableAbilityListsObserverImpl::UnsubscribeObserver(ani_env *env, ani_object observer)
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    ani_ref fnRef;
    env->GlobalReference_Create(observer, &fnRef);
    for (auto iter = enableAbilityListsObservers_.begin(); iter != enableAbilityListsObservers_.end(); iter++) {
        if (ANIUtils::CheckObserverEqual(env, fnRef, (*iter)->env_, (*iter)->callback_)) {
            env->GlobalReference_Delete((*iter)->callback_);
            enableAbilityListsObservers_.erase(iter);
            break;
        }
    }
    env->GlobalReference_Delete(fnRef);
}

void EnableAbilityListsObserverImpl::UnsubscribeObservers()
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto iter = enableAbilityListsObservers_.begin(); iter != enableAbilityListsObservers_.end(); iter++) {
        ((*iter)->env_)->GlobalReference_Delete((*iter)->callback_);
    }
    enableAbilityListsObservers_.clear();
}

void EnableAbilityListsObserverImpl::UnsubscribeInstallObserver(ani_env *env, ani_object observer)
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    ani_ref fnRef;
    env->GlobalReference_Create(observer, &fnRef);
    for (auto iter = installAbilityListsObservers_.begin(); iter != installAbilityListsObservers_.end(); iter++) {
        if (ANIUtils::CheckObserverEqual(env, fnRef, (*iter)->env_, (*iter)->callback_)) {
            env->GlobalReference_Delete((*iter)->callback_);
            installAbilityListsObservers_.erase(iter);
            break;
        }
    }
    env->GlobalReference_Delete(fnRef);
}

void EnableAbilityListsObserverImpl::UnsubscribeInstallObservers()
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto iter = installAbilityListsObservers_.begin(); iter != installAbilityListsObservers_.end(); iter++) {
        ((*iter)->env_)->GlobalReference_Delete((*iter)->callback_);
    }
    installAbilityListsObservers_.clear();
}

void EnableAbilityListsObserverImpl::SubscribeToFramework()
{
    HILOG_INFO("SubscribeToFramework");
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    instance.SubscribeEnableAbilityListsObserver(shared_from_this());
}

void EnableAbilityListsObserverImpl::UnsubscribeFromFramework()
{
    HILOG_INFO("UnsubscribeFromFramework");
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    instance.UnsubscribeEnableAbilityListsObserver(shared_from_this());
}

void EnableAbilityCallbackObserver::OnEnableAbilityRemoteDied(const std::string &name)
{
    HILOG_INFO();
    auto task = [vm = vm_, callback = callback_]() {
        HILOG_INFO("on enable ability lists state changed");
        ANIUtils::EnvGuard guard(vm);
        ani_env *tmpEnv = guard.GetEnv();
        if (tmpEnv == nullptr) {
            HILOG_ERROR("tmpEnv is null");
            return;
        }
        ani_size nr_refs = ANI_SCOPE_SIZE;
        tmpEnv->CreateLocalScope(nr_refs);
        ani_ref call = nullptr;
        auto status =
            tmpEnv->Object_GetPropertyByName_Ref(reinterpret_cast<ani_object>(callback), "onDisconnect", &call);
        if (status != ANI_OK) {
            HILOG_ERROR("get onDisconnect property failed with %{public}d", status);
            tmpEnv->DestroyLocalScope();
            return;
        }
        auto fnObj = reinterpret_cast<ani_fn_object>(call);
        ani_ref result;
        status = tmpEnv->FunctionalObject_Call(fnObj, 0, nullptr, &result);
        if (status != ANI_OK) {
            HILOG_ERROR("FunctionalObject_Call failed, status %{public}d", status);
            tmpEnv->DestroyLocalScope();
            return;
        }
        tmpEnv->DestroyLocalScope();
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void EnableAbilityCallbackObserverImpl::OnEnableAbilityRemoteDied(const std::string& name)
{
    HILOG_DEBUG("name: %{public}s", name.c_str());
    std::lock_guard<ffrt::mutex> lock(mutex_);
    auto iter = enableAbilityCallbackObservers_.find(name);
    if (iter != enableAbilityCallbackObservers_.end()) {
        if (iter->second) {
            iter->second->OnEnableAbilityRemoteDied(name);
        }
        enableAbilityCallbackObservers_.erase(iter);
        return;
    }
}

void EnableAbilityCallbackObserverImpl::SubscribeObserver(ani_vm *vm, const std::string& name, ani_ref observer)
{
    HILOG_DEBUG("name: %{public}s", name.c_str());
    std::lock_guard<ffrt::mutex> lock(mutex_);
    if (enableAbilityCallbackObservers_.find(name) != enableAbilityCallbackObservers_.end()) {
        HILOG_DEBUG("Observer exist");
        return;
    }
    std::shared_ptr<EnableAbilityCallbackObserver> observerPtr =
        std::make_shared<EnableAbilityCallbackObserver>(vm, observer);
    enableAbilityCallbackObservers_[name] = observerPtr;
    HILOG_DEBUG("observer size%{public}zu", enableAbilityCallbackObservers_.size());
}

void EnableAbilityCallbackObserverImpl::UnsubscribeObserver(const std::string& name)
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    auto iter = enableAbilityCallbackObservers_.find(name);
    if (iter != enableAbilityCallbackObservers_.end()) {
        enableAbilityCallbackObservers_.erase(iter);
        return;
    }
}

void EnableAbilityCallbackObserverImpl::SubscribeToFramework()
{
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    instance.SubscribeEnableAbilityCallbackObserver(shared_from_this());
}

void EnableAbilityCallbackObserverImpl::UnsubscribeFromFramework()
{
    HILOG_INFO("UnsubscribeFromFramework");
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    instance.UnsubscribeEnableAbilityCallbackObserver(shared_from_this());
}

void ANIAccessibilityConfigObserver::OnConfigChangedExtra(const ConfigValue &value)
{
    if (configId_ == CONFIG_ID::CONFIG_CONTENT_TIMEOUT) {
        NotifyIntChangedToJs(static_cast<int32_t>(value.contentTimeout));
    } else if (configId_ == CONFIG_ID::CONFIG_BRIGHTNESS_DISCOUNT) {
        NotifyFloatChangedToJs(value.brightnessDiscount);
    } else if (configId_ == CONFIG_ID::CONFIG_AUDIO_BALANCE) {
        NotifyFloatChangedToJs(value.audioBalance);
    } else if (configId_ ==  CONFIG_ID::CONFIG_HIGH_CONTRAST_TEXT) {
        NotifyStateChangedToJs(value.highContrastText);
    } else if (configId_ ==  CONFIG_ID::CONFIG_DALTONIZATION_STATE) {
        NotifyStateChangedToJs(value.daltonizationState);
    } else if (configId_ == CONFIG_ID::CONFIG_INVERT_COLOR) {
        NotifyStateChangedToJs(value.invertColor);
    } else if (configId_ == CONFIG_ID::CONFIG_ANIMATION_OFF) {
        NotifyStateChangedToJs(value.animationOff);
    } else if (configId_ == CONFIG_ID::CONFIG_AUDIO_MONO) {
        NotifyStateChangedToJs(value.audioMono);
    } else if (configId_ == CONFIG_ID::CONFIG_CLICK_RESPONSE_TIME) {
        NotifyStringChangedToJs(ConvertClickResponseTimeTypeToString(value.clickResponseTime));
    } else if (configId_ == CONFIG_ID::CONFIG_IGNORE_REPEAT_CLICK_TIME) {
        NotifyStringChangedToJs(ConvertIgnoreRepeatClickTimeTypeToString(value.ignoreRepeatClickTime));
    } else if (configId_ == CONFIG_ID::CONFIG_IGNORE_REPEAT_CLICK_STATE) {
        NotifyStateChangedToJs(value.ignoreRepeatClickState);
    }
}

void ANIAccessibilityConfigObserver::OnConfigChanged(const ConfigValue &value)
{
    HILOG_INFO("id = [%{public}d]", static_cast<int32_t>(configId_));
    if (configId_ == CONFIG_ID::CONFIG_CAPTION_STATE) {
        NotifyStateChangedToJs(value.captionState);
    } else if (configId_ == CONFIG_ID::CONFIG_CAPTION_STYLE) {
        NotifyPropertyChangedToJs(value.captionStyle);
    } else if (configId_ == CONFIG_ID::CONFIG_SCREEN_MAGNIFICATION) {
        NotifyStateChangedToJs(value.screenMagnifier);
    } else if (configId_ == CONFIG_ID::CONFIG_MOUSE_KEY) {
        NotifyStateChangedToJs(value.mouseKey);
    } else if (configId_ == CONFIG_ID::CONFIG_SHORT_KEY) {
        NotifyStateChangedToJs(value.shortkey);
    } else if (configId_ == CONFIG_ID::CONFIG_SHORT_KEY_TARGET) {
        NotifyStringChangedToJs(value.shortkey_target);
    } else if (configId_ == CONFIG_ID::CONFIG_SHORT_KEY_MULTI_TARGET) {
        NotifyStringVectorChangedToJs(value.shortkeyMultiTarget);
    } else if (configId_ == CONFIG_ID::CONFIG_MOUSE_AUTOCLICK) {
        NotifyIntChangedToJs(value.mouseAutoClick);
    } else if (configId_ == CONFIG_ID::CONFIG_DALTONIZATION_COLOR_FILTER) {
        OnDaltonizationColorFilterConfigChanged();
    } else {
        OnConfigChangedExtra(value);
    }
}

void ANIAccessibilityConfigObserver::OnDaltonizationColorFilterConfigChanged()
{
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    OHOS::AccessibilityConfig::DALTONIZATION_TYPE type = OHOS::AccessibilityConfig::DALTONIZATION_TYPE::Normal;
    RetError ret = instance.GetDaltonizationColorFilter(type);
    NotifyStringChangedToJs(ConvertDaltonizationTypeToString(type));
    if (ret != RET_OK) {
        HILOG_ERROR("get DaltonizationColorFilter failed: %{public}d", ret);
    }
}

void ANIAccessibilityConfigObserver::NotifyStateChangedToJs(bool enabled)
{
    HILOG_INFO("id = [%{public}d] value = [%{public}s]", static_cast<int32_t>(configId_), enabled ? "true" : "false");
    std::shared_ptr<ANIStateCallbackInfo> callbackInfo = std::make_shared<ANIStateCallbackInfo>();
    if (callbackInfo == nullptr) {
        HILOG_ERROR("Failed to create callbackInfo");
        return;
    }
    callbackInfo->state_ = enabled;
    callbackInfo->env_ = env_;
    callbackInfo->fnRef_ = handlerRef_;
    auto task = [callbackInfo]() {
        HILOG_INFO("notify state changed to ets");
        ani_env *tmpEnv = callbackInfo->env_;
        ani_size nr_refs = ANI_SCOPE_SIZE;
        tmpEnv->CreateLocalScope(nr_refs);
        auto fnObj = reinterpret_cast<ani_fn_object>(callbackInfo->fnRef_);
        ani_object state = ANIUtils::CreateBoolObject(tmpEnv, static_cast<ani_boolean>(callbackInfo->state_));
        if (state == nullptr) {
            HILOG_ERROR("create boolean object failed");
            tmpEnv->DestroyLocalScope();
            return;
        }
        std::vector<ani_ref> args = {reinterpret_cast<ani_ref>(state)};
        ani_ref result;
        tmpEnv->FunctionalObject_Call(fnObj, 1, args.data(), &result);
        tmpEnv->DestroyLocalScope();
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void ANIAccessibilityConfigObserver::NotifyPropertyChangedToJs(
    const OHOS::AccessibilityConfig::CaptionProperty &caption)
{
    std::shared_ptr<ANICaptionCallbackInfo> callbackInfo = std::make_shared<ANICaptionCallbackInfo>();
    if (callbackInfo == nullptr) {
        HILOG_ERROR("Failed to create callbackInfo.");
        return;
    }
    callbackInfo->caption_ = caption;
    callbackInfo->env_ = env_;
    callbackInfo->fnRef_ = handlerRef_;
    auto task = [callbackInfo] () {
        if (callbackInfo == nullptr) {
            return;
        }
        HILOG_INFO("notify property changed to ets");
        ani_env *tmpEnv = callbackInfo->env_;
        ani_size nr_refs = ANI_SCOPE_SIZE;
        tmpEnv->CreateLocalScope(nr_refs);
        auto fnObj = reinterpret_cast<ani_fn_object>(callbackInfo->fnRef_);
        ani_object state = ANIAccessibilityConfig::CreateJsAccessibilityCaptionProperty(tmpEnv, callbackInfo->caption_);
        if (state == nullptr) {
            HILOG_ERROR("create CaptionProperty object failed");
            tmpEnv->DestroyLocalScope();
            return;
        }
        std::vector<ani_ref> args = {reinterpret_cast<ani_ref>(state)};
        ani_ref result;
        tmpEnv->FunctionalObject_Call(fnObj, 1, args.data(), &result);
        tmpEnv->DestroyLocalScope();
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void ANIAccessibilityConfigObserver::NotifyStringChangedToJs(const std::string& value)
{
    HILOG_INFO("id = [%{public}d] value = [%{public}s]", static_cast<int32_t>(configId_), value.c_str());
    std::shared_ptr<ANIStateCallbackInfo> callbackInfo = std::make_shared<ANIStateCallbackInfo>();
    if (callbackInfo == nullptr) {
        HILOG_ERROR("Failed to create callbackInfo");
        return;
    }
    callbackInfo->stringValue_ = value;
    callbackInfo->env_ = env_;
    callbackInfo->fnRef_ = handlerRef_;
    auto task = [callbackInfo]() {
        HILOG_INFO("notify string changed to ets");
        ani_env *tmpEnv = callbackInfo->env_;
        ani_size nr_refs = ANI_SCOPE_SIZE;
        tmpEnv->CreateLocalScope(nr_refs);
        auto fnObj = reinterpret_cast<ani_fn_object>(callbackInfo->fnRef_);
        ani_object state = ANIUtils::CreateAniString(callbackInfo->env_, callbackInfo->stringValue_);
        if (state == nullptr) {
            HILOG_ERROR("create CreateAniString object failed");
            tmpEnv->DestroyLocalScope();
            return;
        }
        std::vector<ani_ref> args = {reinterpret_cast<ani_ref>(state)};
        ani_ref result;
        tmpEnv->FunctionalObject_Call(fnObj, args.size(), args.data(), &result);
        tmpEnv->DestroyLocalScope();
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void ANIAccessibilityConfigObserver::NotifyStringVectorChangedToJs(std::vector<std::string> value)
{
    HILOG_INFO("id = [%{public}d]", static_cast<int32_t>(configId_));
    std::shared_ptr<ANIStateCallbackInfo> callbackInfo = std::make_shared<ANIStateCallbackInfo>();
    if (callbackInfo == nullptr) {
        HILOG_ERROR("Failed to create callbackInfo");
        return;
    }
    callbackInfo->stringVector_ = value;
    callbackInfo->env_ = env_;
    callbackInfo->fnRef_ = handlerRef_;
    auto task = [callbackInfo]() {
        HILOG_INFO("notify string vector changed to ets");
        ani_env *tmpEnv = callbackInfo->env_;
        ani_size nr_refs = ANI_SCOPE_SIZE;
        tmpEnv->CreateLocalScope(nr_refs);
        auto fnObj = reinterpret_cast<ani_fn_object>(callbackInfo->fnRef_);
        ani_object state = ANIUtils::CreateArray(tmpEnv, callbackInfo->stringVector_);
        if (state == nullptr) {
            HILOG_ERROR("create boolean object failed");
            tmpEnv->DestroyLocalScope();
            return;
        }
        std::vector<ani_ref> args = {reinterpret_cast<ani_ref>(state)};
        ani_ref result;
        tmpEnv->FunctionalObject_Call(fnObj, 1, args.data(), &result);
        tmpEnv->DestroyLocalScope();
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void ANIAccessibilityConfigObserver::NotifyIntChangedToJs(int32_t value)
{
    HILOG_INFO("id = [%{public}d] value = [%{public}d]", static_cast<int32_t>(configId_), value);

    std::shared_ptr<ANIStateCallbackInfo> callbackInfo = std::make_shared<ANIStateCallbackInfo>();
    if (callbackInfo == nullptr) {
        HILOG_ERROR("Failed to create callbackInfo");
        return;
    }
    callbackInfo->int32Value_ = value;
    callbackInfo->env_ = env_;
    callbackInfo->fnRef_ = handlerRef_;
    auto task = [callbackInfo]() {
        HILOG_INFO("notify int changed to ets");
        ani_env *tmpEnv = callbackInfo->env_;
        ani_size nr_refs = ANI_SCOPE_SIZE;
        tmpEnv->CreateLocalScope(nr_refs);
        auto fnObj = reinterpret_cast<ani_fn_object>(callbackInfo->fnRef_);
        ani_object state;
        if (ANIUtils::CreateAniInt(tmpEnv, callbackInfo->int32Value_, state) != ANI_OK) {
            HILOG_ERROR("create int32_t object failed");
            tmpEnv->DestroyLocalScope();
            return;
        }
        std::vector<ani_ref> args = {reinterpret_cast<ani_ref>(state)};

        ani_ref result;
        tmpEnv->FunctionalObject_Call(fnObj, 1, args.data(), &result);
        tmpEnv->DestroyLocalScope();
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void ANIAccessibilityConfigObserver::NotifyFloatChangedToJs(float value)
{
    HILOG_INFO("id = [%{public}d] value = [%{public}f]", static_cast<int32_t>(configId_), value);

    std::shared_ptr<ANIStateCallbackInfo> callbackInfo = std::make_shared<ANIStateCallbackInfo>();
    if (callbackInfo == nullptr) {
        HILOG_ERROR("Failed to create callbackInfo");
        return;
    }
    callbackInfo->floatValue_ = value;
    callbackInfo->env_ = env_;
    callbackInfo->fnRef_ = handlerRef_;
    auto task = [callbackInfo]() {
        HILOG_INFO("notify float changed to ets");
        ani_env *tmpEnv = callbackInfo->env_;
        ani_size nr_refs = ANI_SCOPE_SIZE;
        tmpEnv->CreateLocalScope(nr_refs);
        auto fnObj = reinterpret_cast<ani_fn_object>(callbackInfo->fnRef_);
        ani_object state = ANIUtils::CreateDouble(tmpEnv, callbackInfo->floatValue_);
        if (state == nullptr) {
            HILOG_ERROR("create uint32_t object failed");
            tmpEnv->DestroyLocalScope();
            return;
        }
        std::vector<ani_ref> args = {reinterpret_cast<ani_ref>(state)};
        ani_ref result;
        tmpEnv->FunctionalObject_Call(fnObj, 1, args.data(), &result);
        tmpEnv->DestroyLocalScope();
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void ANIAccessibilityConfigObserverImpl::SubscribeObserver(ani_env* env,
    OHOS::AccessibilityConfig::CONFIG_ID id, ani_object observer)
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    ani_ref fnRef;
    env->GlobalReference_Create(observer, &fnRef);
    for (auto iter = observers_.begin(); iter != observers_.end(); iter++) {
        if (ANIUtils::CheckObserverEqual(env, fnRef, (*iter)->env_, (*iter)->handlerRef_)) {
            env->GlobalReference_Delete(fnRef);
            HILOG_INFO("Config Observer SubscribeObserver Observer exist");
            return;
        }
    }
    std::shared_ptr<ANIAccessibilityConfigObserver> observerPtr =
        std::make_shared<ANIAccessibilityConfigObserver>(env, fnRef, id);
    observers_.emplace_back(observerPtr);
}

void ANIAccessibilityConfigObserverImpl::UnsubscribeObserver(ani_env* env,
    OHOS::AccessibilityConfig::CONFIG_ID id, ani_object observer)
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    ani_ref fnRef;
    env->GlobalReference_Create(observer, &fnRef);
    for (auto iter = observers_.begin(); iter != observers_.end(); iter++) {
        if ((*iter)->configId_ == id) {
            if (ANIUtils::CheckObserverEqual(env, fnRef, (*iter)->env_, (*iter)->handlerRef_)) {
                HILOG_INFO("Config Observer UnsubscribeObserver, ID:%{public}d", id);
                env->GlobalReference_Delete((*iter)->handlerRef_);
                observers_.erase(iter);
                break;
            }
        }
    }
    env->GlobalReference_Delete(fnRef);
}


void ANIAccessibilityConfigObserverImpl::SubscribeToFramework()
{
    HILOG_INFO("Config Observer SubscribeToFramework");
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    for (int32_t index = 0; index < static_cast<int32_t>(CONFIG_ID::CONFIG_ID_MAX); index ++) {
        instance.SubscribeConfigObserver(static_cast<CONFIG_ID>(index), shared_from_this(), false);
    }
}

void ANIAccessibilityConfigObserverImpl::UnsubscribeFromFramework()
{
    HILOG_INFO("Config Observer UnsubscribeFromFramework");
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    for (int32_t index = 0; index < static_cast<int32_t>(CONFIG_ID::CONFIG_ID_MAX); index ++) {
        instance.UnsubscribeConfigObserver(static_cast<CONFIG_ID>(index), shared_from_this());
    }
}

void ANIAccessibilityConfigObserverImpl::UnsubscribeObservers(OHOS::AccessibilityConfig::CONFIG_ID id)
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto iter = observers_.begin(); iter != observers_.end();) {
        if ((*iter)->configId_ == id) {
            iter = observers_.erase(iter);
        } else {
            iter++;
        }
    }
}

void ANIAccessibilityConfigObserverImpl::OnConfigChanged(
    const OHOS::AccessibilityConfig::CONFIG_ID id, const OHOS::AccessibilityConfig::ConfigValue& value)
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto &observer : observers_) {
        if (observer && observer->configId_ == id) {
            observer->OnConfigChanged(value);
        }
    }
}

void ANIAccessibilityConfig::SetSyncboolean(ani_env *env, ani_object object, ani_enum_item id, ani_boolean state)
{
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = RET_OK;
    if (configId == CONFIG_ID::CONFIG_HIGH_CONTRAST_TEXT) {
        ret = instance.SetHighContrastTextState(state);
    } else if (configId == CONFIG_ID::CONFIG_DALTONIZATION_STATE) {
        ret = instance.SetDaltonizationState(state);
    } else if (configId == CONFIG_ID::CONFIG_INVERT_COLOR) {
        ret = instance.SetInvertColorState(state);
    } else if (configId == CONFIG_ID::CONFIG_ANIMATION_OFF) {
        ret = instance.SetAnimationOffState(state);
    } else if (configId == CONFIG_ID::CONFIG_SCREEN_MAGNIFICATION) {
        ret = instance.SetScreenMagnificationState(state);
    } else if (configId == CONFIG_ID::CONFIG_AUDIO_MONO) {
        ret = instance.SetAudioMonoState(state);
    } else if (configId == CONFIG_ID::CONFIG_MOUSE_KEY) {
        ret = instance.SetMouseKeyState(state);
    } else if (configId == CONFIG_ID::CONFIG_SHORT_KEY) {
        ret = instance.SetShortKeyState(state);
    } else if (configId == CONFIG_ID::CONFIG_CAPTION_STATE) {
        ret = instance.SetCaptionsState(state, true);
    } else if (configId == CONFIG_ID::CONFIG_IGNORE_REPEAT_CLICK_STATE) {
        ret = instance.SetIgnoreRepeatClickState(state);
    }
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("SetSyncboolean configId = %{public}d, ret = %{public}d", configId, static_cast<int32_t>(ret));
    return;
}

ani_boolean ANIAccessibilityConfig::GetSyncboolean(ani_env *env, ani_object object, ani_enum_item id)
{
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return false;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    bool state = false;
    RetError ret = RET_ERR_FAILED;

    if (configId == CONFIG_ID::CONFIG_HIGH_CONTRAST_TEXT) {
        ret = instance.GetHighContrastTextState(state);
    } else if (configId == CONFIG_ID::CONFIG_DALTONIZATION_STATE) {
        ret = instance.GetDaltonizationState(state);
    } else if (configId == CONFIG_ID::CONFIG_INVERT_COLOR) {
        ret = instance.GetInvertColorState(state);
    } else if (configId == CONFIG_ID::CONFIG_ANIMATION_OFF) {
        ret = instance.GetAnimationOffState(state);
    } else if (configId == CONFIG_ID::CONFIG_SCREEN_MAGNIFICATION) {
        ret = instance.GetScreenMagnificationState(state);
    } else if (configId == CONFIG_ID::CONFIG_AUDIO_MONO) {
        ret = instance.GetAudioMonoState(state);
    } else if (configId == CONFIG_ID::CONFIG_MOUSE_KEY) {
        ret = instance.GetMouseKeyState(state);
    } else if (configId == CONFIG_ID::CONFIG_SHORT_KEY) {
        ret = instance.GetShortKeyState(state);
    } else if (configId == CONFIG_ID::CONFIG_CAPTION_STATE) {
        ret = instance.GetCaptionsState(state, true);
    } else if (configId == CONFIG_ID::CONFIG_IGNORE_REPEAT_CLICK_STATE) {
        ret = instance.GetIgnoreRepeatClickState(state);
    }

    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("GetSyncboolean configId = %{public}d, ret = %{public}d", configId, static_cast<int32_t>(ret));
    return static_cast<ani_boolean>(state);
}

void ANIAccessibilityConfig::SetSyncDouble(ani_env *env, ani_object object, ani_enum_item id, ani_double value)
{
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = RET_OK;
    if (configId == CONFIG_ID::CONFIG_AUDIO_BALANCE) {
        ret = instance.SetAudioBalance(static_cast<float>(value));
    } else if (configId == CONFIG_ID::CONFIG_BRIGHTNESS_DISCOUNT) {
        ret = instance.SetBrightnessDiscount(static_cast<float>(value));
    }

    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("SetSyncDouble configId = %{public}d, ret = %{public}d", configId, static_cast<int32_t>(ret));
    return;
}

ani_double ANIAccessibilityConfig::GetSyncDouble(ani_env *env, ani_object object, ani_enum_item id)
{
    float floatData = 0;
    RetError ret = RET_ERR_FAILED;
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return false;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    if (configId == CONFIG_ID::CONFIG_AUDIO_BALANCE) {
        ret = instance.GetAudioBalance(floatData);
    } else if (configId == CONFIG_ID::CONFIG_BRIGHTNESS_DISCOUNT) {
        ret = instance.GetBrightnessDiscount(floatData);
    }

    HILOG_INFO("getSyncNumber configId = %{public}d, ret = %{public}d", configId, static_cast<int32_t>(ret));
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }

    return static_cast<ani_double>(floatData);
}

void ANIAccessibilityConfig::SetSyncInt(ani_env *env, ani_object object, ani_enum_item id, ani_int value)
{
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = RET_ERR_FAILED;
    if (configId == CONFIG_ID::CONFIG_CONTENT_TIMEOUT) {
        ret = instance.SetContentTimeout(static_cast<uint32_t>(value));
    } else if (configId == CONFIG_ID::CONFIG_MOUSE_AUTOCLICK) {
        ret = instance.SetMouseAutoClick(static_cast<uint32_t>(value));
    }
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("SetSyncInt configId = %{public}d, ret = %{public}d", configId, static_cast<int32_t>(ret));
    return;
}

ani_int ANIAccessibilityConfig::GetSyncInt(ani_env *env, ani_object object, ani_enum_item id)
{
    float floatData = 0;
    int32_t int32Data = 0;
    RetError ret = RET_ERR_FAILED;
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return -1;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    if (configId == CONFIG_ID::CONFIG_CONTENT_TIMEOUT) {
        uint32_t timeout = 0;
        ret = instance.GetContentTimeout(timeout);
        int32Data = static_cast<int32_t>(timeout);
    } else if (configId == CONFIG_ID::CONFIG_MOUSE_AUTOCLICK) {
        ret = instance.GetMouseAutoClick(int32Data);
    }

    HILOG_INFO("getSyncNumber configId = %{public}d, ret = %{public}d", configId, static_cast<int32_t>(ret));
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }

    return static_cast<ani_int>(int32Data);
}

void ANIAccessibilityConfig::SetSyncString(ani_env *env, ani_object object, ani_enum_item id, ani_string value)
{
    (void)id;
    std::string nameStr = ANIUtils::ANIStringToStdString(env, value);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = instance.SetShortkeyTarget(nameStr);
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("Set shortkey target ret = %{public}d", static_cast<int32_t>(ret));
    return;
}

ani_string ANIAccessibilityConfig::GetSyncString(ani_env *env, ani_object object, ani_enum_item id)
{
    (void)id;
    ani_string retResult = nullptr;
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    std::string result = "";
    auto ret = instance.GetShortkeyTarget(result);
    if (ret != RET_OK) {
        HILOG_ERROR("GetSyncString failed! ret = %{public}d", static_cast<int32_t>(ret));
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    env->String_NewUTF8(result.c_str(), result.size(), &retResult);
    return retResult;
}

void ANIAccessibilityConfig::SetSyncVectorString(ani_env *env, ani_object object, ani_enum_item id, ani_object value)
{
    (void)id;
    std::vector<std::string> valueList;
    if (!ANIUtils::ParseStringArray(env, value, valueList)) {
        HILOG_ERROR("ParseStringArray fail");
        return;
    }
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = instance.SetShortkeyMultiTarget(valueList);
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("Set shortkey multi-target ret = %{public}d", static_cast<int32_t>(ret));
    return;
}

ani_object ANIAccessibilityConfig::GetSyncVectorString(ani_env *env, ani_object object, ani_enum_item id)
{
    (void)id;
    ani_string retResult = nullptr;
    std::vector<std::string> multiList;
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = instance.GetShortkeyMultiTarget(multiList);
    if (ret != RET_OK) {
        HILOG_ERROR("GetSyncVecotorString failed! ret = %{public}d", static_cast<int32_t>(ret));
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }

    return ANIUtils::CreateArray(env, multiList);
}

void ANIAccessibilityConfig::SetSyncDaltonizationColorFilter(ani_env *env, ani_object object,
    ani_enum_item id, ani_string value)
{
    (void)id;
    std::string nameStr = ANIUtils::ANIStringToStdString(env, value);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto filter = ConvertStringToDaltonizationTypes(nameStr);
    auto ret = instance.SetDaltonizationColorFilter(filter);
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("SetSyncDaltonizationColorFilter ret = %{public}d", static_cast<int32_t>(ret));
    return;
}

ani_string ANIAccessibilityConfig::GetSyncDaltonizationColorFilter(ani_env *env, ani_object object, ani_enum_item id)
{
    (void)id;
    ani_string retResult = nullptr;
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    OHOS::AccessibilityConfig::DALTONIZATION_TYPE type;
    auto ret = instance.GetDaltonizationColorFilter(type);
    if (ret != RET_OK) {
        HILOG_ERROR("GetSyncDaltonizationColorFilter failed! ret = %{public}d", static_cast<int32_t>(ret));
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    std::string result = ConvertDaltonizationTypeToString(type);
    env->String_NewUTF8(result.c_str(), result.size(), &retResult);
    return retResult;
}

void ANIAccessibilityConfig::SetSyncClickResponseTime(ani_env *env, ani_object object,
    ani_enum_item id, ani_string value)
{
    (void)id;
    std::string nameStr = ANIUtils::ANIStringToStdString(env, value);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto time = ConvertStringToClickResponseTimeTypes(nameStr);
    auto ret = instance.SetClickResponseTime(time);
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("SetSyncClickResponseTime ret = %{public}d", static_cast<int32_t>(ret));
    return;
}

ani_string ANIAccessibilityConfig::GetSyncClickResponseTime(ani_env *env, ani_object object, ani_enum_item id)
{
    (void)id;
    ani_string retResult = nullptr;
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();

    OHOS::AccessibilityConfig::CLICK_RESPONSE_TIME time;
    auto ret = instance.GetClickResponseTime(time);
    if (ret != RET_OK) {
        HILOG_ERROR("GetSyncClickResponseTimer failed! ret = %{public}d", static_cast<int32_t>(ret));
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    std::string result = ConvertClickResponseTimeTypeToString(time);
    env->String_NewUTF8(result.c_str(), result.size(), &retResult);
    return retResult;
}

void ANIAccessibilityConfig::SetSyncRepeatClickInterval(ani_env *env, ani_object object,
    ani_enum_item id, ani_string value)
{
    (void)id;
    std::string nameStr = ANIUtils::ANIStringToStdString(env, value);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto time = ConvertStringToIgnoreRepeatClickTimeTypes(nameStr);
    auto ret = instance.SetIgnoreRepeatClickTime(time);
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("SetSyncRepeatClickInterval ret = %{public}d", static_cast<int32_t>(ret));
    return;
}

ani_string ANIAccessibilityConfig::GetSyncRepeatClickInterval(ani_env *env, ani_object object, ani_enum_item id)
{
    (void)id;
    ani_string retResult = nullptr;
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();

    OHOS::AccessibilityConfig::IGNORE_REPEAT_CLICK_TIME time;
    auto ret = instance.GetIgnoreRepeatClickTime(time);
    if (ret != RET_OK) {
        HILOG_ERROR("GetSyncRepeatClickInterval failed! ret = %{public}d", static_cast<int32_t>(ret));
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    std::string result = ConvertIgnoreRepeatClickTimeTypeToString(time);
    env->String_NewUTF8(result.c_str(), result.size(), &retResult);
    return retResult;
}

void ANIAccessibilityConfig::SetSyncCaptionsStyle(ani_env *env, ani_object object, ani_enum_item id, ani_object value)
{
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    OHOS::AccessibilityConfig::CaptionProperty captionProperty;

    std::string fontFamily = DEFAULT_FONT_FAMILY;
    uint32_t fontScale = DEFAULT_FONT_SCALE;
    uint32_t fontColor = DEFAULT_COLOR;
    std::string fontEdgeType = DEFAULT_FONT_EDGE_TYPE;
    uint32_t backgroundColor = DEFAULT_COLOR;
    uint32_t windowColor = DEFAULT_COLOR;
    ani_boolean isUndefined = true;
    if (env->Reference_IsUndefined(value, &isUndefined) != ANI_OK) {
        HILOG_ERROR("SetSyncCaptionsStyle Reference_IsUndefined");
        return;
    }

    if (!isUndefined) {
        RETURN_IF_FALSE(ANIUtils::GetStringMember(env, value, "fontFamily", fontFamily));
        RETURN_IF_FALSE(ANIUtils::GetColorMember(env, value, "fontColor", fontColor));
        RETURN_IF_FALSE(ANIUtils::GetStringMember(env, value, "fontEdgeType", fontEdgeType));
        RETURN_IF_FALSE(ANIUtils::GetColorMember(env, value, "backgroundColor", backgroundColor));
        RETURN_IF_FALSE(ANIUtils::GetColorMember(env, value, "windowColor", windowColor));
        int value1 = 0;
        if ((env->Object_GetPropertyByName_Int(value, "fontScale", &value1) != ANI_OK) || (value1 < 0)) {
            HILOG_ERROR("Get property value1  failed");
            return;
        }
        fontScale = static_cast<uint32_t>(value1);
    }

    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = RET_OK;
    if (configId == CONFIG_ID::CONFIG_CAPTION_STYLE) {
        captionProperty.SetFontFamily(fontFamily);
        captionProperty.SetFontScale(fontScale);
        captionProperty.SetFontColor(fontColor);
        captionProperty.SetFontEdgeType(fontEdgeType);
        captionProperty.SetBackgroundColor(backgroundColor);
        captionProperty.SetWindowColor(windowColor);
        ret = instance.SetCaptionsProperty(captionProperty, true);
    }
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("SetSyncCaptionsStyle ret = %{public}d", static_cast<int32_t>(ret));
    return;
}

ani_object ANIAccessibilityConfig::CreateJsCaptionPropertyInfoInner(ani_env *env, ani_class cls,
    ani_object &object, OHOS::AccessibilityConfig::CaptionProperty &captionProperty)
{
    if (env == nullptr || cls == nullptr || object == nullptr) {
        HILOG_ERROR("invalid args");
        return nullptr;
    }

    if (!ANIUtils::SetStringProperty(env, object, "fontFamily", captionProperty.GetFontFamily())) {
        HILOG_ERROR("set fontFamily failed");
    }
    if (!ANIUtils::SetStringProperty(env, object, "fontEdgeType", captionProperty.GetFontEdgeType())) {
        HILOG_ERROR("set fontEdgeType failed");
    }
    if (env->Object_SetPropertyByName_Int(object, "fontScale", captionProperty.GetFontScale()) != ANI_OK) {
        HILOG_ERROR("Set property fontScale failed");
    }

    if (!ANIUtils::SetStringProperty(env, object, "fontColor",
        ConvertColorToString(captionProperty.GetFontColor()))) {
        HILOG_ERROR("Set property fontColor failed");
    }

    if (!ANIUtils::SetStringProperty(env, object, "backgroundColor",
        ConvertColorToString(captionProperty.GetBackgroundColor()))) {
        HILOG_ERROR("Set property backgroundColor failed");
    }

    if (!ANIUtils::SetStringProperty(env, object, "windowColor",
        ConvertColorToString(captionProperty.GetWindowColor()))) {
        HILOG_ERROR("Set property windowColor failed");
    }

    return object;
}

ani_object ANIAccessibilityConfig::CreateJsAccessibilityCaptionProperty(ani_env *env,
    OHOS::AccessibilityConfig::CaptionProperty &captionProperty)
{
    HILOG_DEBUG();
    arkts::ani_signature::Type className =
        arkts::ani_signature::Builder::BuildClass("@ohos.accessibility.accessibility.CaptionsStyleImpl");
    ani_class cls;
    if (env->FindClass(className.Descriptor().c_str(), &cls) != ANI_OK) {
        HILOG_ERROR("Class CaptionsStyle not found");
        return nullptr;
    }
    ani_method ctor;
    if (env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor) != ANI_OK) {
        HILOG_ERROR("Find method '<ctor>' failed");
        return nullptr;
    }

    ani_object object;
    if (env->Object_New(cls, ctor, &object) != ANI_OK) {
        HILOG_ERROR("New object fail");
        return nullptr;
    }

    return CreateJsCaptionPropertyInfoInner(env, cls, object, captionProperty);
}

ani_object ANIAccessibilityConfig::GetSyncCaptionsStyle(ani_env *env, ani_object object, ani_enum_item id)
{
    (void)id;
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    OHOS::AccessibilityConfig::CaptionProperty captionProperty;
    auto ret = instance.GetCaptionsProperty(captionProperty, true);
    if (ret != RET_OK) {
        HILOG_ERROR("GetSyncCaptionsStyle failed! ret = %{public}d", static_cast<int32_t>(ret));
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }

    return CreateJsAccessibilityCaptionProperty(env, captionProperty);
}


void ANIAccessibilityConfig::EnableAbilitySync(ani_env *env, ani_string name, ani_array capability)
{
    std::string nameStr = ANIUtils::ANIStringToStdString(env, name);

    if (capability == nullptr) {
        HILOG_ERROR("capability is null");
        return;
    }
    ani_size length;
    ani_status status = env->Array_GetLength(capability, &length);
    if (status != ANI_OK) {
        HILOG_ERROR("Object_GetPropertyByName_Double faild. status : %{public}d", status);
        return;
    }

    std::vector<std::string> strings;
    for (ani_size i = 0; i < length; i++) {
        ani_ref stringRef;
        auto signature = arkts::ani_signature::SignatureBuilder().AddInt().SetReturnUndefined()
            .BuildSignatureDescriptor();
        if (env->Array_Get(capability, i, &stringRef) != ANI_OK) {
            HILOG_ERROR("Object_CallMethodByName_Ref Failed");
            return;
        }
        strings.emplace_back(ANIUtils::ANIStringToStdString(env, static_cast<ani_string>(stringRef)));
    }
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = instance.EnableAbility(nameStr, ParseCapabilitiesFromVec(strings), false);
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("EnableAbilitySync ret = %{public}d", static_cast<int32_t>(ret));
    return;
}

void ANIAccessibilityConfig::EnableAbilityWithCallbackSync(
    ani_env* env, ani_string name, ani_array capability, ani_object connectCallback)
{
    std::string nameStr = ANIUtils::ANIStringToStdString(env, name);

    if (capability == nullptr) {
        HILOG_INFO("capability is null");
        return;
    }
    if (connectCallback == nullptr) {
        HILOG_INFO("connectCallback is null");
        return;
    }

    ani_size length;
    ani_status status = env->Array_GetLength(capability, &length);
    if (status != ANI_OK) {
        HILOG_INFO("Array_GetLength failed. status : %{public}d", status);
        return;
    }

    std::vector<std::string> strings;
    for (ani_size i = 0; i < length; i++) {
        ani_ref stringRef;
        auto signature = arkts::ani_signature::SignatureBuilder().AddInt().SetReturnUndefined()
            .BuildSignatureDescriptor();
        if (ANI_OK != env->Array_Get(capability, i, &stringRef)) {
            HILOG_ERROR("Object_CallMethodByName_Ref Failed");
            return;
        }
        strings.emplace_back(ANIUtils::ANIStringToStdString(env, static_cast<ani_string>(stringRef)));
    }
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = instance.EnableAbility(nameStr, ParseCapabilitiesFromVec(strings), true);
    if (ret != RET_OK) {
        HILOG_ERROR("EnableAbilityWithCallbackSync ret = %{public}d", static_cast<int32_t>(ret));
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
        return;
    }
    ani_vm *vm = nullptr;
    env->GetVM(&vm);
    ani_ref callback = nullptr;
    env->GlobalReference_Create(connectCallback, &callback);
    enableAbilityCallbackObservers_->SubscribeObserver(vm, nameStr, callback);
}

void ANIAccessibilityConfig::DisableAbilitySync(ani_env *env, ani_string name)
{
    std::string nameStr = ANIUtils::ANIStringToStdString(env, name);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = instance.DisableAbility(nameStr);
    if (ret != RET_OK) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
    HILOG_INFO("DisableAbilitySync ret = %{public}d", static_cast<int32_t>(ret));
    return;
}

bool ANIAccessibilityConfig::CheckReadPermission(const std::string &permission)
{
    HILOG_DEBUG();
    uint32_t tokenId = IPCSkeleton::GetCallingTokenID();
    int result = TypePermissionState::PERMISSION_GRANTED;
    ATokenTypeEnum tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId);
    if (tokenType == TOKEN_INVALID) {
        HILOG_WARN("AccessToken type invalid!");
        return false;
    } else {
        result = AccessTokenKit::VerifyAccessToken(tokenId, permission);
    }
    if (result == TypePermissionState::PERMISSION_DENIED) {
        HILOG_WARN("AccessTokenID denied!");
        return false;
    }
    HILOG_DEBUG("tokenType %{private}d dAccessTokenID:%{private}u, permission:%{private}s matched!",
        tokenType, tokenId, permission.c_str());
    return true;
}

bool ANIAccessibilityConfig::IsAvailable(ani_env *env)
{
    HILOG_DEBUG();
    if (!AccessTokenKit::IsSystemAppByFullTokenID(IPCSkeleton::GetCallingFullTokenID())) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(RET_ERR_NOT_SYSTEM_APP));
        HILOG_ERROR("Not system app");
        return false;
    }

    if (!CheckReadPermission(OHOS_PERMISSION_READ_ACCESSIBILITY_CONFIG)) {
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(RET_ERR_NO_PERMISSION));
        HILOG_ERROR("No read permission");
        return false;
    }

    return true;
}

void ANIAccessibilityConfig::SubscribeState(ani_env *env, ani_string type, ani_object observer)
{
    if (!IsAvailable(env)) {
        return;
    }
    std::string typeStr = ANIUtils::ANIStringToStdString(env, type);
    if (enableAbilityListsObservers_ == nullptr) {
        HILOG_ERROR("enableAbilityListsObservers_ is null");
        return;
    }
    if (std::strcmp(typeStr.c_str(), "enabledAccessibilityExtensionListChange") == 0) {
        enableAbilityListsObservers_->SubscribeObserver(env, observer);
    } else if (std::strcmp(typeStr.c_str(), "installedAccessibilityListChange") == 0) {
        enableAbilityListsObservers_->SubscribeInstallObserver(env, observer);
    }
}

void ANIAccessibilityConfig::UnsubscribeState(ani_env *env, ani_string type, ani_object observer)
{
    if (!IsAvailable(env)) {
        return;
    }
    std::string typeStr = ANIUtils::ANIStringToStdString(env, type);
    HILOG_INFO("OffObserver: %{public}s", typeStr.c_str());
    if (enableAbilityListsObservers_ == nullptr) {
        HILOG_ERROR("enableAbilityListsObservers_ is null");
        return;
    }
    if (std::strcmp(typeStr.c_str(), "enabledAccessibilityExtensionListChange") == 0) {
        enableAbilityListsObservers_->UnsubscribeObserver(env, observer);
    } else if (std::strcmp(typeStr.c_str(), "installedAccessibilityListChange") == 0) {
        enableAbilityListsObservers_->UnsubscribeInstallObserver(env, observer);
    }
}

void ANIAccessibilityConfig::UnsubscribeStates(ani_env *env, ani_string type)
{
    if (!IsAvailable(env)) {
        return;
    }
    std::string typeStr = ANIUtils::ANIStringToStdString(env, type);
    HILOG_INFO("OffObservers: %{public}s", typeStr.c_str());
    if (enableAbilityListsObservers_ == nullptr) {
        HILOG_ERROR("enableAbilityListsObservers_ is null");
        return;
    }
    if (std::strcmp(typeStr.c_str(), "enabledAccessibilityExtensionListChange") == 0) {
        enableAbilityListsObservers_->UnsubscribeObservers();
    } else if (std::strcmp(typeStr.c_str(), "installedAccessibilityListChange") == 0) {
        enableAbilityListsObservers_->UnsubscribeInstallObservers();
    }
}

void ANIAccessibilityConfig::SetMagnificationState(ani_env *env, ani_boolean state)
{
    if (!IsAvailable(env)) {
        return;
    }
    HILOG_INFO();
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    auto ret = instance.SetMagnificationState(static_cast<bool>(state));
    if (ret != RET_OK) {
        HILOG_ERROR("SetMagnificationState failed, ret = %{public}d", static_cast<int32_t>(ret));
        ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(ret));
    }
}

void ANIAccessibilityConfig::SubscribeConfigObserver(ani_env *env, ani_object object,
    ani_enum_item id, ani_object callback)
{
    if (!IsAvailable(env)) {
        return;
    }
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    configObservers_->SubscribeObserver(env, configId, callback);
}

void ANIAccessibilityConfig::UnSubscribeConfigObservers(ani_env *env, ani_object object, ani_enum_item id)
{
    if (!IsAvailable(env)) {
        return;
    }
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    configObservers_->UnsubscribeObservers(configId);
}

void ANIAccessibilityConfig::UnSubscribeConfigObserver(ani_env *env, ani_object object,
    ani_enum_item id, ani_object observer)
{
    if (!IsAvailable(env)) {
        return;
    }
    ani_int itemEnum;
    if (env->EnumItem_GetValue_Int(id, &itemEnum) != ANI_OK) {
        HILOG_ERROR("get value int ERROR");
        return;
    }
    CONFIG_ID configId = static_cast<CONFIG_ID>(itemEnum);
    configObservers_->UnsubscribeObserver(env, configId, observer);
}

void SeniorModeStateObserverImpl::SubscribeToFramework()
{
    HILOG_INFO("SubscribeToFramework");
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    instance.SubscribeAppSeniorModeStateObserver(shared_from_this());
}

void SeniorModeStateObserverImpl::UnsubscribeFromFramework()
{
    HILOG_INFO("UnsubscribeFromFramework");
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    instance.UnsubscribeAppSeniorModeStateObserver(shared_from_this());
}

void SeniorModeStateObserverImpl::SubscribeObserver(ani_env *env, ani_object observer)
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    ani_ref fnRef;
    env->GlobalReference_Create(observer, &fnRef);
    for (auto iter = seniorModeStateObservers_.begin(); iter != seniorModeStateObservers_.end(); iter++) {
        if (ANIUtils::CheckObserverEqual(env, fnRef, (*iter)->env_, (*iter)->callback_)) {
            env->GlobalReference_Delete(fnRef);
            HILOG_DEBUG("SubscribeObserver Observer exist");
            return;
        }
    }
    std::shared_ptr<SeniorModeStateObserver> observerPtr = std::make_shared<SeniorModeStateObserver>(env, fnRef);
    seniorModeStateObservers_.emplace_back(observerPtr);
    HILOG_DEBUG("seniorModeStateObservers_ size%{public}zu", seniorModeStateObservers_.size());
}

void SeniorModeStateObserverImpl::UnsubscribeObserver(ani_env *env, ani_object observer)
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    ani_ref fnRef;
    env->GlobalReference_Create(observer, &fnRef);
    for (auto iter = seniorModeStateObservers_.begin(); iter != seniorModeStateObservers_.end(); iter++) {
        if (ANIUtils::CheckObserverEqual(env, fnRef, (*iter)->env_, (*iter)->callback_)) {
            env->GlobalReference_Delete((*iter)->callback_);
            seniorModeStateObservers_.erase(iter);
            break;
        }
    }
    env->GlobalReference_Delete(fnRef);
}

void SeniorModeStateObserverImpl::UnsubscribeObservers()
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto iter = seniorModeStateObservers_.begin(); iter != seniorModeStateObservers_.end(); iter++) {
        ((*iter)->env_)->GlobalReference_Delete((*iter)->callback_);
    }
    seniorModeStateObservers_.clear();
}

void SeniorModeStateObserverImpl::OnSeniorModeStateChanged(const std::string& bundleName, int32_t appIndex,
    const bool state)
{
    HILOG_DEBUG();
    std::lock_guard<ffrt::mutex> lock(mutex_);
    for (auto &observer : seniorModeStateObservers_) {
        if (observer) {
            observer->OnSeniorModeStateChanged(bundleName, appIndex, state);
        } else {
            HILOG_ERROR("observer is null");
        }
    }
}

void SeniorModeStateObserver::OnSeniorModeStateChanged(const std::string& bundleName, int32_t appIndex, bool state)
{
    std::shared_ptr<AccessibilityCallbackInfo> callbackInfo = std::make_shared<AccessibilityCallbackInfo>();
    if (callbackInfo == nullptr) {
        HILOG_ERROR("Failed to create callbackInfo");
        return;
    }
    callbackInfo->env_ = env_;
    callbackInfo->fnRef_ = callback_;
    auto task = [callbackInfo, bundleName, appIndex, state]() {
        ani_env *tmpEnv = callbackInfo->env_;
        ani_class cls;
        arkts::ani_signature::Type className = arkts::ani_signature::Builder::BuildClass(
            "@ohos.accessibility.config.config.AppSeniorModeInfoImpl");
        if (tmpEnv->FindClass(className.Descriptor().c_str(), &cls) != ANI_OK) {
            HILOG_ERROR("Class AppSeniorModeInfoImpl not found");
            return;
        }
        ani_object spanObj = ANIUtils::CreateObject(tmpEnv, cls);
        if (!ANIUtils::SetStringField(tmpEnv, spanObj, "bundleName", bundleName)) {
            return;
        }
        if (!ANIUtils::SetIntField(tmpEnv, spanObj, "appIndex", appIndex)) {
            return;
        }
        if (tmpEnv->Object_SetPropertyByName_Boolean(spanObj, "seniorModeState",
            static_cast<ani_boolean>(state)) != ANI_OK) {
            HILOG_ERROR("set property seniorModeState failed.");
            return;
        }

        ani_ref fnRef;
        tmpEnv->GlobalReference_Create(spanObj, &fnRef);
        auto fnObj = reinterpret_cast<ani_fn_object>(callbackInfo->fnRef_);
        ani_ref result;
        tmpEnv->FunctionalObject_Call(fnObj, 1, &fnRef, &result);
    };
    if (!ANIUtils::SendEventToMainThread(task)) {
        HILOG_ERROR("failed to send event");
    }
}

void ANIAccessibilityConfig::OnSeniorModeStateChangeForApp(ani_env *env, ani_object observer)
{
    HILOG_INFO("onSeniorModeStateChangeForApp");
    seniorModeStateObservers_->SubscribeObserver(env, observer);
}

void ANIAccessibilityConfig::OffSeniorModeStateChangeForApp(ani_env *env, ani_object observer)
{
    HILOG_INFO("offSeniorModeStateChangeForApp");
    seniorModeStateObservers_->UnsubscribeObserver(env, observer);
}

void ANIAccessibilityConfig::OffSeniorModeStateChangeForApps()
{
    HILOG_INFO("offSeniorModeStateChangeForApp");
    seniorModeStateObservers_->UnsubscribeObservers();
}

ani_boolean ANIAccessibilityConfig::GetSeniorModeStateForApp(ani_env *env, ani_string bundleName, ani_int appIndex)
{
    HILOG_INFO("getSeniorModeStateForApp");
    bool state = false;
    std::string bundleNameStr = ANIUtils::ANIStringToStdString(env, bundleName);
    int32_t appIndexInt = static_cast<int32_t>(appIndex);
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    OHOS::Accessibility::RetError ret = instance.GetSeniorModeStateForApp(bundleNameStr, appIndexInt, state);
    if (ret != OHOS::Accessibility::RET_OK) {
        HILOG_ERROR("GetSeniorModeStateForApp failed: %{public}d", ret);
        return static_cast<ani_boolean>(false);
    }
    return static_cast<ani_boolean>(state);
}

void ANIAccessibilityConfig::SetSeniorModeStateForApp(ani_env *env, ani_array seniorModeInfoArray)
{
    HILOG_INFO("setSeniorModeStateForApp");

    ani_size arrayLength = 0;
    if (env->Array_GetLength(static_cast<ani_array>(seniorModeInfoArray), &arrayLength) != ANI_OK) {
        HILOG_ERROR("get array length failed.");
        return;
    }
    std::vector<OHOS::AccessibilityConfig::AccessibilityBundleSeniorModeInfo> infos;
    for (ani_size i = 0; i < arrayLength; i++) {
        ani_ref elementRef;
        if (env->Array_Get(seniorModeInfoArray, i, &elementRef) != ANI_OK) {
            HILOG_ERROR("Object_CallMethodByName_Ref Failed");
            return;
        }
        ani_object element = reinterpret_cast<ani_object>(elementRef);

        std::string bundleName;
        if (!ANIUtils::GetStringField(env, "bundleName", element, bundleName)) {
            HILOG_ERROR("get bundleName failed.");
            continue;
        }

        int32_t appIndex;
        if (!ANIUtils::GetIntField(env, "appIndex", element, appIndex)) {
            HILOG_DEBUG("use defalut appIndex 0.");
            appIndex = 0;
        }

        if (appIndex < 0) {
            HILOG_ERROR("appIndex is invilid.");
            ANIUtils::ThrowBusinessError(env, ANIUtils::QueryRetMsg(RET_ERR_INVILID_APPINDEX));
            return;
        }

        ani_boolean state;
        if (env->Object_GetPropertyByName_Boolean(element, "seniorModeState", &state) != ANI_OK) {
            HILOG_ERROR("get seniorModeState boolean value failed.");
            continue;
        }

        OHOS::AccessibilityConfig::AccessibilityBundleSeniorModeInfo info;
        info.bundleName_ = bundleName;
        info.appIndex_ = appIndex;
        info.seniorModeState_ = static_cast<bool>(state);
        infos.push_back(info);
    }
    auto &instance = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
    OHOS::Accessibility::RetError ret = instance.SetSeniorModeStateForApp(infos);
    if (ret != OHOS::Accessibility::RET_OK) {
        HILOG_ERROR("SetSeniorModeStateForApp failed: %{public}d", ret);
    }
}