/*
 * 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 <ani.h>
#include <string>
#include <unistd.h>

#include "base/log/log.h"
#include "base/memory/ace_type.h"
#include "core/common/container.h"
#include "core/components_ng/base/observer_handler.h"
#include "core/pipeline_ng/pipeline_context.h"

using NavIdAndListenersMap =
    std::unordered_map<std::optional<std::string>, std::list<ani_ref>>;

namespace {
// constexpr const char DENSITY_CHNAGE[] = "densityUpdate";
const char ANI_OBSERVER_NS[] = "@ohos.arkui.observer.uiObserver";
const char ANI_OBSERVER_CLS[] = "@ohos.arkui.observer.uiObserver.UIObserver";
constexpr char ANI_NAVDESTINATION_INFO_CLS[] = "@ohos.arkui.observer.uiObserver.NavDestinationInfoImpl";
constexpr char ANI_NAVDESTINATION_STATE_TYPE[] = "@ohos.arkui.observer.uiObserver.NavDestinationState";
constexpr char ANI_NAVDESTINATION_MODE_TYPE[] = "arkui.component.navDestination.NavDestinationMode";
constexpr char ANI_ROUTER_INFO_CLS[] = "@ohos.arkui.observer.uiObserver.RouterPageInfo";
constexpr char ANI_ROUTER_STATE_TYPE[] = "@ohos.arkui.observer.uiObserver.RouterPageState";
constexpr char NAVDESTINATION_PARAM_WITHID[] =
    "C{std.core.String}C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Object}:";
constexpr char ANI_NAV_SWITCH_INFO[] = "@ohos.arkui.observer.uiObserver.NavDestinationSwitchInfoImpl";
constexpr char ANI_NAVIGATION_OPERATION_TYPE[] = "arkui.component.navigation.NavigationOperation";
constexpr char ANI_SCROLL_EVENT_INFO_CLS[] = "@ohos.arkui.observer.uiObserver.ScrollEventInfoImpl";
constexpr char ANI_SCROLL_AXIS[] = "arkui.component.enums.Axis";
constexpr char ANI_SCROLL_EVENT_TYPE[] = "@ohos.arkui.observer.uiObserver.ScrollEventType";
constexpr char ANI_TABCONTENT_INFO_CLS[] = "@ohos.arkui.observer.uiObserver.TabContentInfoImpl";
constexpr char ANI_TABCONTENT_STATE_TYPE[] = "@ohos.arkui.observer.uiObserver.TabContentState";
constexpr char TAB_CHANGE_PARAM[] = "C{std.core.Function1}:";
constexpr char TAB_CHANGE_PARAM_WITHID[] = "C{@ohos.arkui.observer.uiObserver.ObserverOptions}C{std.core.Function1}:";
constexpr char ANI_TABCONTENT_WITH_OPTIONS_CLS[] =
    "C{@ohos.arkui.observer.uiObserver.ObserverOptions}C{std.core.Function1}:";
constexpr char ANI_TABCONTENT_CLS[] = "C{std.core.Function1}:";
constexpr char ANI_SIZE_INNER_CLS[] = "@ohos.arkui.observer.uiObserver.SizeInner";
constexpr char ANI_WINDOW_SIZE_BREAKPOINT_INFO_CLS[] =
    "@ohos.arkui.observer.uiObserverImpl.WindowSizeLayoutBreakpointImpl";
constexpr char ANI_WIDTHBREAKPOINT_TYPE[] = "arkui.component.enums.WidthBreakpoint";
constexpr char ANI_HEIGHTBREAKPOINT_TYPE[] = "arkui.component.enums.HeightBreakpoint";
constexpr char ROUTER_NAVIGATION_PARAM[] =
    "X{C{application.UIAbilityContext.UIAbilityContext}C{@ohos.arkui.UIContext.UIContext}}C{std.core.Function1}:";
constexpr char ANI_UICONTEXT_UTIL_CLS[] = "arkui.base.UIContextUtil.UIContextUtil";
} // namespace
namespace OHOS::Ace {
class UiObserver {
public:
    explicit UiObserver(int32_t instanceId) : id_(instanceId) {}

    static ani_object CreateSize(ani_env* env, ani_double width, ani_double height)
    {
        ani_ref undefinedVal;
        ani_status status;
        if ((status = env->GetUndefined(&undefinedVal)) != ANI_OK) {
            LOGE("failed to get undefined value when create size, status:%{public}d", status);
            return nullptr;
        }
        ani_object undefinedObj = static_cast<ani_object>(undefinedVal);
        ani_class cls;
        if ((status = env->FindClass(ANI_SIZE_INNER_CLS, &cls)) != ANI_OK) {
            LOGE("failed to find %{public}s class, status:%{public}d", ANI_SIZE_INNER_CLS, status);
            return undefinedObj;
        }
        ani_method ctor;
        if ((status = env->Class_FindMethod(cls, "<ctor>", "dd:", &ctor)) != ANI_OK) {
            LOGE("failed to find constructor of %{public}s class, status:%{public}d", ANI_SIZE_INNER_CLS, status);
            return undefinedObj;
        }
        ani_object obj = {};
        if ((status = env->Object_New(cls, ctor, &obj, width, height)) != ANI_OK) {
            LOGE("failed to create %{public}s object, status:%{public}d", ANI_SIZE_INNER_CLS, status);
            return undefinedObj;
        }
        return obj;
    }

    static void CallJsFunction(ani_env* env, std::list<ani_ref>& cbList)
    {
        std::vector<ani_ref> vec;
        ani_ref fnReturnVal;
        for (auto& cb : cbList) {
            env->FunctionalObject_Call(reinterpret_cast<ani_fn_object>(cb), vec.size(), vec.data(), &fnReturnVal);
        }
    }

    // UIObserver.on(type: "densityUpdate", uiContext | null, callback)
    // register a listener on current page
    void RegisterDensityCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        id_ = uiContextInstanceId;
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = densityCbMap_.find(uiContextInstanceId);
        if (iter == densityCbMap_.end()) {
            densityCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }
    // UIObserver.off(type: "densityUpdate", uiContext | null, callback)
    void UnRegisterDensityCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = densityCbMap_.find(uiContextInstanceId);
        if (iter == densityCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
                         holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            holder.end());
    }

    void RegisterBeforePanStartCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        id_ = uiContextInstanceId;
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedBeforePanStartCbMap_.find(uiContextInstanceId);
        if (iter == specifiedBeforePanStartCbMap_.end()) {
            specifiedBeforePanStartCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterBeforePanStartCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedBeforePanStartCbMap_.find(uiContextInstanceId);
        if (iter == specifiedBeforePanStartCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(holder.begin(),
                                    holder.end(),
                                    [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
                     holder.end());
    }

    void RegisterAfterPanStartCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedAfterPanStartCbMap_.find(uiContextInstanceId);
        if (iter == specifiedAfterPanStartCbMap_.end()) {
            specifiedAfterPanStartCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterAfterPanStartCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedAfterPanStartCbMap_.find(uiContextInstanceId);
        if (iter == specifiedAfterPanStartCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(holder.begin(),
                                    holder.end(),
                                    [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
                     holder.end());
    }

    void RegisterBeforePanEndCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        id_ = uiContextInstanceId;
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedBeforePanEndCbMap_.find(uiContextInstanceId);
        if (iter == specifiedBeforePanEndCbMap_.end()) {
            specifiedBeforePanEndCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterBeforePanEndCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedBeforePanEndCbMap_.find(uiContextInstanceId);
        if (iter == specifiedBeforePanEndCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(holder.begin(),
                                    holder.end(),
                                    [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
                     holder.end());
    }

    void RegisterAfterPanEndCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        id_ = uiContextInstanceId;
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedAfterPanEndCbMap_.find(uiContextInstanceId);
        if (iter == specifiedAfterPanEndCbMap_.end()) {
            specifiedAfterPanEndCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterAfterPanEndCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedAfterPanEndCbMap_.find(uiContextInstanceId);
        if (iter == specifiedAfterPanEndCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(holder.begin(),
                                    holder.end(),
                                    [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
                     holder.end());
    }

    void RegisterWillClickCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        id_ = uiContextInstanceId;
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedWillClickCbMap_.find(uiContextInstanceId);
        if (iter == specifiedWillClickCbMap_.end()) {
            specifiedWillClickCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterWillClickCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedWillClickCbMap_.find(uiContextInstanceId);
        if (iter == specifiedWillClickCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(holder.begin(),
                                    holder.end(),
                                    [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
                     holder.end());
    }

    void RegisterDidLayoutCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        id_ = uiContextInstanceId;
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedDidLayoutCbMap_.find(uiContextInstanceId);
        if (iter == specifiedDidLayoutCbMap_.end()) {
            specifiedDidLayoutCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterDidLayoutCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedDidLayoutCbMap_.find(uiContextInstanceId);
        if (iter == specifiedDidLayoutCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
                         holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            holder.end());
    }

    void RegisterWillDrawCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        id_ = uiContextInstanceId;
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedWillDrawCbMap_.find(uiContextInstanceId);
        if (iter == specifiedWillDrawCbMap_.end()) {
            specifiedWillDrawCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterWillDrawCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedWillDrawCbMap_.find(uiContextInstanceId);
        if (iter == specifiedWillDrawCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
                         holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            holder.end());
    }

    void HandleWillDraw(ani_env* env)
    {
        auto currentId = Container::CurrentId();
        auto iter = specifiedWillDrawCbMap_.find(currentId);
        if (iter == specifiedWillDrawCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        CallJsFunction(env, holder);
    }

    void HandleDidLayout(ani_env* env)
    {
        auto currentId = Container::CurrentId();
        auto iter = specifiedDidLayoutCbMap_.find(currentId);
        if (iter == specifiedDidLayoutCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        CallJsFunction(env, holder);
    }

    void RegisterDidClickCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        id_ = uiContextInstanceId;
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedDidClickCbMap_.find(uiContextInstanceId);
        if (iter == specifiedDidClickCbMap_.end()) {
            specifiedDidClickCbMap_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterDidClickCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedDidClickCbMap_.find(uiContextInstanceId);
        if (iter == specifiedDidClickCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(holder.begin(),
                                    holder.end(),
                                    [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
                     holder.end());
    }

    // UIObserver.on(type: "navDestinationUpdate", callback)
    static void RegisterNavigationCallback(ani_ref& cb)
    {
        if (std::find(unspecifiedNavigationListeners_.begin(), unspecifiedNavigationListeners_.end(), cb) !=
            unspecifiedNavigationListeners_.end()) {
            return;
        }
        unspecifiedNavigationListeners_.emplace_back(cb);
    }

    // UIObserver.off(type: "navDestinationUpdate", callback)
    static void UnRegisterNavigationCallback(ani_env* env, ani_ref& cb)
    {
        if (cb == nullptr) {
            unspecifiedNavigationListeners_.clear();
            return;
        }

        unspecifiedNavigationListeners_.erase(
            std::remove_if(unspecifiedNavigationListeners_.begin(), unspecifiedNavigationListeners_.end(),
                [env, cb](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            unspecifiedNavigationListeners_.end());
    }

    // UIObserver.on(type: "navDestinationUpdate", options, callback)
    static void RegisterNavigationCallback(std::string navigationId, ani_ref& cb)
    {
        auto iter = specifiedCNavigationListeners_.find(navigationId);
        if (iter == specifiedCNavigationListeners_.end()) {
            specifiedCNavigationListeners_.emplace(navigationId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    // UIObserver.off(type: "navDestinationUpdate", optisons, callback)
    static void UnRegisterNavigationCallback(ani_env* env, std::string navigationId, ani_ref& cb)
    {
        auto iter = specifiedCNavigationListeners_.find(navigationId);
        if (iter == specifiedCNavigationListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
            holder.begin(), holder.end(), [env, cb](ani_ref cb1) { return AniEqual(env, cb, cb1); }), holder.end());
    }

    void RegisterTextChangeCallback(ani_ref& cb)
    {
        if (std::find(unspecifiedTextChangeListeners_.begin(), unspecifiedTextChangeListeners_.end(), cb) !=
            unspecifiedTextChangeListeners_.end()) {
            return;
        }
        hasSetTextChangeCallback_ = true;
        unspecifiedTextChangeListeners_.emplace_back(cb);
    }

    void UnRegisterTextChangeCallback(ani_env* env, ani_ref& cb)
    {
        if (cb == nullptr) {
            for (auto& callback : unspecifiedTextChangeListeners_) {
                env->GlobalReference_Delete(callback);
            }
            unspecifiedTextChangeListeners_.clear();
            return;
        }

        unspecifiedTextChangeListeners_.erase(
            std::remove_if(unspecifiedTextChangeListeners_.begin(), unspecifiedTextChangeListeners_.end(),
                [env, cb, this](ani_ref cb1) {
                    auto result = AniEqual(env, cb, cb1);
                    if (result) {
                        env->GlobalReference_Delete(cb1);
                    }
                    return result;
                }),
            unspecifiedTextChangeListeners_.end());
    }

    void RegisterTextChangeCallback(std::string id, ani_ref& cb)
    {
        auto iter = specifiedTextChangeListeners_.find(id);
        if (iter == specifiedTextChangeListeners_.end()) {
            hasSetTextChangeCallback_ = true;
            specifiedTextChangeListeners_.emplace(id, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterTextChangeCallback(ani_env* env, std::string id, ani_ref& cb)
    {
        auto iter = specifiedTextChangeListeners_.find(id);
        if (iter == specifiedTextChangeListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
            holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            holder.end());
    }

    void RegisterSwiperContentUpdateCallback(ani_ref& cb)
    {
        if (std::find(unspecifiedSwiperContentUpdateListeners_.begin(),
                unspecifiedSwiperContentUpdateListeners_.end(), cb) !=
                unspecifiedSwiperContentUpdateListeners_.end()) {
            return;
        }
        hasSetSwiperContentUpdateCallback_ = true;
        unspecifiedSwiperContentUpdateListeners_.emplace_back(cb);
    }

    void UnRegisterSwiperContentUpdateCallback(ani_env* env, ani_ref& cb)
    {
        if (cb == nullptr) {
            for (auto& callback : unspecifiedSwiperContentUpdateListeners_) {
                env->GlobalReference_Delete(callback);
            }
            unspecifiedSwiperContentUpdateListeners_.clear();
            return;
        }

        unspecifiedSwiperContentUpdateListeners_.erase(std::remove_if(unspecifiedSwiperContentUpdateListeners_.begin(),
            unspecifiedSwiperContentUpdateListeners_.end(),
                [env, cb, this](ani_ref cb1) {
                    auto result = AniEqual(env, cb, cb1);
                    if (result) {
                        env->GlobalReference_Delete(cb1);
                    }
                    return result;
                }),
            unspecifiedSwiperContentUpdateListeners_.end());
    }

    void RegisterSwiperContentUpdateCallback(std::string id, ani_ref& cb)
    {
        auto iter = specifiedSwiperContentUpdateListeners_.find(id);
        if (iter == specifiedSwiperContentUpdateListeners_.end()) {
            hasSetSwiperContentUpdateCallback_ = true;
            specifiedSwiperContentUpdateListeners_.emplace(id, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterSwiperContentUpdateCallback(ani_env* env, std::string id, ani_ref& cb)
    {
        auto iter = specifiedSwiperContentUpdateListeners_.find(id);
        if (iter == specifiedSwiperContentUpdateListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
            holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            holder.end());
    }

    void RegisterTabChangeCallback(ani_ref& cb)
    {
        if (std::find(unspecifiedTabChangeListeners_.begin(), unspecifiedTabChangeListeners_.end(), cb) !=
            unspecifiedTabChangeListeners_.end()) {
            return;
        }
        hasSetTabChangeCallback_ = true;
        unspecifiedTabChangeListeners_.emplace_back(cb);
    }

    void UnRegisterTabChangeCallback(ani_env* env, ani_ref& cb)
    {
        if (cb == nullptr) {
            for (auto& callback : unspecifiedTabChangeListeners_) {
                env->GlobalReference_Delete(callback);
            }
            unspecifiedTabChangeListeners_.clear();
            return;
        }

        unspecifiedTabChangeListeners_.erase(
            std::remove_if(unspecifiedTabChangeListeners_.begin(), unspecifiedTabChangeListeners_.end(),
                [env, cb, this](ani_ref cb1) {
                    auto result = AniEqual(env, cb, cb1);
                    if (result) {
                        env->GlobalReference_Delete(cb1);
                    }
                    return result;
                }),
            unspecifiedTabChangeListeners_.end());
    }

    void RegisterTabChangeCallback(std::string id, ani_ref& cb)
    {
        auto iter = specifiedTabChangeListeners_.find(id);
        if (iter == specifiedTabChangeListeners_.end()) {
            hasSetTabChangeCallback_ = true;
            specifiedTabChangeListeners_.emplace(id, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterTabChangeCallback(ani_env* env, std::string id, ani_ref& cb)
    {
        auto iter = specifiedTabChangeListeners_.find(id);
        if (iter == specifiedTabChangeListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            for (auto& callback : holder) {
                env->GlobalReference_Delete(callback);
            }
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
            holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) {
                auto result = AniEqual(env, cb, cb1);
                if (result) {
                    env->GlobalReference_Delete(cb1);
                }
                return result;
            }),
            holder.end());
    }

    static void RegisterTabContentUpdateCallback(const ani_ref& cb)
    {
        if (std::find(unspecifiedTabContentListeners_.begin(), unspecifiedTabContentListeners_.end(), cb) !=
            unspecifiedTabContentListeners_.end()) {
            return;
        }
        unspecifiedTabContentListeners_.emplace_back(cb);
    }

    static void RegisterTabContentUpdateCallback(const std::string& id, const ani_ref& cb)
    {
        auto iter = specifiedTabContentUpdateListeners_.find(id);
        if (iter == specifiedTabContentUpdateListeners_.end()) {
            specifiedTabContentUpdateListeners_.emplace(id, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    static void UnRegisterTabContentUpdateCallback(ani_env* env, const ani_ref& cb)
    {
        if (cb == nullptr) {
            unspecifiedTabContentListeners_.clear();
            return;
        }
        unspecifiedTabContentListeners_.erase(
            std::remove_if(unspecifiedTabContentListeners_.begin(), unspecifiedTabContentListeners_.end(),
                [env, cb](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            unspecifiedTabContentListeners_.end());
    }

    static void UnRegisterTabContentUpdateCallback(ani_env* env, const std::string& id, const ani_ref& cb)
    {
        auto iter = specifiedTabContentUpdateListeners_.find(id);
        if (iter == specifiedTabContentUpdateListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(holder.begin(),
                                    holder.end(),
                                    [env, cb](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
                     holder.end());
    }

    // UIObserver.on(type: "routerPageUpdate", UIContext, callback)
    static void RegisterRouterPageCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentIdSafelyWithCheck();
        }
        auto iter = specifiedRouterPageListeners_.find(uiContextInstanceId);
        if (iter == specifiedRouterPageListeners_.end()) {
            specifiedRouterPageListeners_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    // UIObserver.off(type: "routerPageUpdate", UIContext, callback)
    static void UnRegisterRouterPageCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentIdSafelyWithCheck();
        }
        auto iter = specifiedRouterPageListeners_.find(uiContextInstanceId);
        if (iter == specifiedRouterPageListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
            holder.begin(), holder.end(), [env, cb](ani_ref cb1) { return AniEqual(env, cb, cb1); }), holder.end());
    }

    static void RegisterNavDestinationSwitchCallback(
        int32_t uiContextInstanceId, const std::optional<std::string>& navigationId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentIdSafelyWithCheck();
        }
        auto listenersMapIter = uiContextNavDesSwitchListeners_.find(uiContextInstanceId);
        if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
            NavIdAndListenersMap listenersMap;
            listenersMap.emplace(navigationId, std::list<ani_ref>({ cb }));
            uiContextNavDesSwitchListeners_[uiContextInstanceId] = listenersMap;
            return;
        }

        auto& listenersMap = listenersMapIter->second;
        auto it = listenersMap.find(navigationId);
        if (it == listenersMap.end()) {
            listenersMap[navigationId] = std::list<ani_ref>({ cb });
            return;
        }

        if (std::find(it->second.begin(), it->second.end(), cb) == it->second.end()) {
            it->second.emplace_back(cb);
        }
    }

    static void UnRegisterNavDestinationSwitchCallback(
        ani_env* env, int32_t uiContextInstanceId, const std::optional<std::string>& navigationId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentIdSafelyWithCheck();
        }
        auto listenersMapIter = uiContextNavDesSwitchListeners_.find(uiContextInstanceId);
        if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
            return;
        }
        auto& listenersMap = listenersMapIter->second;
        auto it = listenersMap.find(navigationId);
        if (it == listenersMap.end()) {
            return;
        }
        auto& listeners = it->second;
        if (cb == nullptr) {
            listeners.clear();
        } else {
            listeners.erase(std::remove_if(listeners.begin(), listeners.end(),
                                [env, cb](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
                listeners.end());
        }
        if (listeners.empty()) {
            listenersMap.erase(it);
        }
        if (listenersMap.empty()) {
            uiContextNavDesSwitchListeners_.erase(listenersMapIter);
        }
    }

    static void HandleUIContextNavDestinationSwitch(ani_env* env, const NG::NavDestinationSwitchInfo& switchInfo)
    {
        auto currentId = Container::CurrentIdSafelyWithCheck();
        auto listenersMapIter = uiContextNavDesSwitchListeners_.find(currentId);
        if (listenersMapIter == uiContextNavDesSwitchListeners_.end()) {
            return;
        }
        auto listenersMap = listenersMapIter->second;
        HandleListenersWithEmptyNavigationId(env, listenersMap, switchInfo);
        HandleListenersWithSpecifiedNavigationId(env, listenersMap, switchInfo);
    }

    static void HandleListenersWithEmptyNavigationId(
        ani_env* env, const NavIdAndListenersMap& listenersMap, const NG::NavDestinationSwitchInfo& switchInfo)
    {
        std::optional<std::string> navId;
        auto it = listenersMap.find(navId);
        if (it != listenersMap.end()) {
            ani_object res;
            CreateNavSwitchInfo(env, switchInfo, res);
            std::vector<ani_ref> cbParam;
            cbParam.emplace_back(res);
            ani_ref fnReturnVal;
            const auto listeners = it->second;
            for (const auto& listener : listeners) {
                env->FunctionalObject_Call(
                    reinterpret_cast<ani_fn_object>(listener), cbParam.size(), cbParam.data(), &fnReturnVal);
            }
        }
    }

    static void HandleListenersWithSpecifiedNavigationId(
        ani_env* env, const NavIdAndListenersMap& listenersMap, const NG::NavDestinationSwitchInfo& switchInfo)
    {
        std::string navigationId;
        if (switchInfo.from.has_value()) {
            navigationId = switchInfo.from.value().navigationId;
        } else if (switchInfo.to.has_value()) {
            navigationId = switchInfo.to.value().navigationId;
        }
        if (!navigationId.empty()) {
            std::optional<std::string> navId { navigationId };
            ani_object res;
            CreateNavSwitchInfo(env, switchInfo, res);
            std::vector<ani_ref> cbParam;
            cbParam.emplace_back(res);
            ani_ref fnReturnVal;
            auto it = listenersMap.find(navId);
            if (it != listenersMap.end()) {
                const auto listeners = it->second;
                for (const auto& listener : listeners) {
                    env->FunctionalObject_Call(
                        reinterpret_cast<ani_fn_object>(listener), cbParam.size(), cbParam.data(), &fnReturnVal);
                }
            }
        }
    }

    void RegisterWindowSizeBreakpointCallback(int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedWindowSizeBreakpointListeners_.find(uiContextInstanceId);
        if (iter == specifiedWindowSizeBreakpointListeners_.end()) {
            specifiedWindowSizeBreakpointListeners_.emplace(uiContextInstanceId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterWindowSizeBreakpointCallback(ani_env* env, int32_t uiContextInstanceId, ani_ref& cb)
    {
        if (uiContextInstanceId == 0) {
            uiContextInstanceId = Container::CurrentId();
        }
        auto iter = specifiedWindowSizeBreakpointListeners_.find(uiContextInstanceId);
        if (iter == specifiedWindowSizeBreakpointListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
            holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            holder.end());
    }

    void HandleWindowSizeBreakpointChange(ani_env* env, int32_t instanceId, const WindowSizeBreakpoint& breakpoint)
    {
        auto iter = specifiedWindowSizeBreakpointListeners_.find(instanceId);
        if (iter == specifiedWindowSizeBreakpointListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        std::vector<ani_ref> callbackParams;
        ani_ref fnReturnVal;
        ani_object res;
        CreateWindowSizeBreakpointInfo(env, breakpoint, res);
        callbackParams.emplace_back(res);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), callbackParams.size(), callbackParams.data(), &fnReturnVal);
        }
    }

    void CreateWindowSizeBreakpointInfo(ani_env* env, const WindowSizeBreakpoint& breakpoint, ani_object& res)
    {
        ani_class cls;
        env->FindClass(ANI_WINDOW_SIZE_BREAKPOINT_INFO_CLS, &cls);
        ani_method windowSizeBreakpointInfoCtor;
        env->Class_FindMethod(cls, "<ctor>", nullptr, &windowSizeBreakpointInfoCtor);
        env->Object_New(cls, windowSizeBreakpointInfoCtor, &res);
        ani_enum widthBreakpointEnum;
        env->FindEnum(ANI_WIDTHBREAKPOINT_TYPE, &widthBreakpointEnum);
        ani_enum_item widthBreakpointItem;
        env->Enum_GetEnumItemByIndex(
            widthBreakpointEnum, static_cast<ani_size>(breakpoint.widthBreakpoint), &widthBreakpointItem);
        env->Object_SetPropertyByName_Ref(res, "widthBreakpoint", widthBreakpointItem);
        ani_enum heightBreakpointEnum;
        env->FindEnum(ANI_HEIGHTBREAKPOINT_TYPE, &heightBreakpointEnum);
        ani_enum_item heightBreakpointItem;
        env->Enum_GetEnumItemByIndex(
            heightBreakpointEnum, static_cast<ani_size>(breakpoint.heightBreakpoint), &heightBreakpointItem);
        env->Object_SetPropertyByName_Ref(res, "heightBreakpoint", heightBreakpointItem);
    }

    void HandleDensityChange(ani_env* env, double density)
    {
        auto currentId = Container::CurrentId();
        auto iter = densityCbMap_.find(currentId);
        if (iter == densityCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        std::vector<ani_ref> callbackParams;
        ani_ref fnReturnVal;
        ani_object res;
        CreateDensityInfo(env, density, res);
        callbackParams.emplace_back(res);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(reinterpret_cast<ani_fn_object>(cb),
                                       callbackParams.size(),
                                       callbackParams.data(),
                                       &fnReturnVal);
        }
    }

    void HandleBeforePanStart(ani_env* env)
    {
        auto currentId = Container::CurrentId();
        auto iter = specifiedBeforePanStartCbMap_.find(currentId);
        if (iter == specifiedBeforePanStartCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        CallJsFunction(env, holder);
    }

    void HandleAfterPanStart(ani_env* env)
    {
        auto currentId = Container::CurrentId();
        auto iter = specifiedAfterPanStartCbMap_.find(currentId);
        if (iter == specifiedAfterPanStartCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        CallJsFunction(env, holder);
    }

    void HandleBeforePanEnd(ani_env* env)
    {
        auto currentId = Container::CurrentId();
        auto iter = specifiedBeforePanEndCbMap_.find(currentId);
        if (iter == specifiedBeforePanEndCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        CallJsFunction(env, holder);
    }

    void HandleAfterPanEnd(ani_env* env)
    {
        auto currentId = Container::CurrentId();
        auto iter = specifiedAfterPanEndCbMap_.find(currentId);
        if (iter == specifiedAfterPanEndCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        CallJsFunction(env, holder);
    }

    void HandleWillClick(ani_env* env)
    {
        auto currentId = Container::CurrentId();
        auto iter = specifiedWillClickCbMap_.find(currentId);
        if (iter == specifiedWillClickCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        CallJsFunction(env, holder);
    }
    void HandleDidClick(ani_env* env)
    {
        auto currentId = Container::CurrentId();
        auto iter = specifiedDidClickCbMap_.find(currentId);
        if (iter == specifiedDidClickCbMap_.end()) {
            return;
        }
        auto& holder = iter->second;
        CallJsFunction(env, holder);
    }

    static void HandleNavigationStateChange(ani_env* env, const NG::NavDestinationInfo& info)
    {
        auto unspecifiedHolder = unspecifiedNavigationListeners_;
        std::vector<ani_ref> cbParam;
        ani_ref fnRetrunVal;
        ani_object res;
        CreateNavigationInfo(env, info, res);
        cbParam.emplace_back(res);
        for (auto& cb : unspecifiedHolder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnRetrunVal);
        }

        auto iter = specifiedCNavigationListeners_.find(info.navigationId);
        if (iter == specifiedCNavigationListeners_.end()) {
            return;
        }

        auto holder = iter->second;
        std::vector<ani_ref> cbParamsWithId;
        ani_ref fnReturnValWithId;
        ani_object resWithId;
        CreateNavigationInfo(env, info, resWithId);
        cbParamsWithId.emplace_back(resWithId);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParamsWithId.size(), cbParamsWithId.data(), &fnReturnValWithId);
        }
    }

    static void HandleTabContentUpdate(ani_env* env, const NG::TabContentInfo& tabContentInfo)
    {
        auto unspecifiedHolder = unspecifiedTabContentListeners_;
        std::vector<ani_ref> cbParam;
        ani_ref fnRetrunVal;
        ani_object res;
        CreateTabContentUpdateInfo(env, tabContentInfo, res);
        cbParam.emplace_back(res);
        for (auto& cb : unspecifiedHolder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnRetrunVal);
        }
        auto iter = specifiedTabContentUpdateListeners_.find(tabContentInfo.id);
        if (iter == specifiedTabContentUpdateListeners_.end()) {
            return;
        }
        auto holder = iter->second;
        std::vector<ani_ref> cbParamsWithId;
        ani_ref fnReturnValWithId;
        ani_object resWithId = nullptr;
        CreateTabContentUpdateInfo(env, tabContentInfo, resWithId);
        cbParamsWithId.emplace_back(resWithId);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParamsWithId.size(), cbParamsWithId.data(), &fnReturnValWithId);
        }
    }

    static void HandleRouterPageStateChange(ani_env* env, NG::AbilityContextInfo& info,
        const NG::RouterPageInfoNG& pageInfo)
    {
        auto currentId = Container::CurrentIdSafelyWithCheck();
        auto iter = specifiedRouterPageListeners_.find(currentId);
        if (iter == specifiedRouterPageListeners_.end()) {
            return;
        }
        ani_object res;
        CreateRouterPageInfo(env, pageInfo, res);
        std::vector<ani_ref> cbParam;
        cbParam.emplace_back(res);
        ani_ref fnReturnVal;

        auto holder = iter->second;
        for (const auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnReturnVal);
        }
    }

    void HandleTabChange(ani_env* env, const NG::TabContentInfo& info)
    {
        if (!hasSetTabChangeCallback_) {
            return;
        }
        auto unspecifiedHolder = unspecifiedTabChangeListeners_;
        std::vector<ani_ref> cbParam;
        ani_ref fnRetrunVal;
        ani_object res;
        CreateTabContentInfo(env, info, res);
        cbParam.emplace_back(res);
        for (auto& cb : unspecifiedHolder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnRetrunVal);
        }

        auto iter = specifiedTabChangeListeners_.find(info.id);
        if (iter == specifiedTabChangeListeners_.end()) {
            return;
        }

        auto holder = iter->second;
        std::vector<ani_ref> cbParamsWithId;
        ani_ref fnReturnValWithId;
        ani_object resWithId;
        CreateTabContentInfo(env, info, resWithId);
        cbParamsWithId.emplace_back(resWithId);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParamsWithId.size(), cbParamsWithId.data(), &fnReturnValWithId);
        }
    }

    void HandleTextChange(ani_env* env, const NG::TextChangeEventInfo& info)
    {
        if (!hasSetTextChangeCallback_) {
            return;
        }
        auto unspecifiedHolder = unspecifiedTextChangeListeners_;
        std::vector<ani_ref> cbParam;
        ani_ref fnRetrunVal;
        ani_object res;
        CreateTextChangeEventInfo(env, info, res);
        cbParam.emplace_back(res);
        for (auto& cb : unspecifiedHolder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnRetrunVal);
        }

        auto iter = specifiedTextChangeListeners_.find(info.id);
        if (iter == specifiedTextChangeListeners_.end()) {
            return;
        }

        auto holder = iter->second;
        std::vector<ani_ref> cbParamsWithId;
        ani_ref fnReturnValWithId;
        ani_object resWithId;
        CreateTextChangeEventInfo(env, info, resWithId);
        cbParamsWithId.emplace_back(resWithId);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParamsWithId.size(), cbParamsWithId.data(), &fnReturnValWithId);
        }
    }

    void HandleSwiperContentUpdate(ani_env* env, const NG::SwiperContentInfo& info)
    {
        if (!hasSetSwiperContentUpdateCallback_) {
            return;
        }
        auto unspecifiedHolder = unspecifiedSwiperContentUpdateListeners_;
        std::vector<ani_ref> cbParam;
        ani_ref fnRetrunVal;
        ani_object res;
        CreateSwiperContentUpdateEventInfo(env, info, res);
        cbParam.emplace_back(res);
        for (auto& cb : unspecifiedHolder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnRetrunVal);
        }

        auto iter = specifiedSwiperContentUpdateListeners_.find(info.id);
        if (iter == specifiedSwiperContentUpdateListeners_.end()) {
            return;
        }

        auto holder = iter->second;
        std::vector<ani_ref> cbParamsWithId;
        ani_ref fnReturnValWithId;
        ani_object resWithId;
        CreateSwiperContentUpdateEventInfo(env, info, resWithId);
        cbParamsWithId.emplace_back(resWithId);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParamsWithId.size(), cbParamsWithId.data(), &fnReturnValWithId);
        }
    }

    static ani_boolean AniEqual(ani_env* env, ani_ref cb, ani_ref cb1)
    {
        ani_boolean isEquals = false;
        env->Reference_StrictEquals(cb, cb1, &isEquals);
        return isEquals;
    }

    void CreateDensityInfo(ani_env* env, double density, ani_object& obj)
    {
        static const char* className = "@ohos.arkui.observer.uiObserver.DensityInfo";
        ani_class cls;
        env->FindClass(className, &cls);
        ani_method ctor;
        env->Class_FindMethod(cls, "<ctor>", ":", &ctor);
        env->Object_New(cls, ctor, &obj);
        env->Object_SetPropertyByName_Double(obj, "density", ani_double(density));
    }

    static void CreateNavigationInfo(ani_env* env, const NG::NavDestinationInfo& info, ani_object& res)
    {
        ani_class cls;
        env->FindClass(ANI_NAVDESTINATION_INFO_CLS, &cls);
        ani_method navDestinationInfoCtor;
        env->Class_FindMethod(cls, "<ctor>", ":", &navDestinationInfoCtor);
        env->Object_New(cls, navDestinationInfoCtor, &res);

        env->Object_SetPropertyByName_Double(res, "uniqueId", static_cast<ani_double>(info.uniqueId));
        env->Object_SetPropertyByName_Int(res, "index", static_cast<ani_int>(info.index));

        ani_string navDesName {};
        env->String_NewUTF8(info.name.c_str(), info.name.size(), &navDesName);
        env->Object_SetPropertyByName_Ref(res, "name", navDesName);

        ani_string navDesId {};
        env->String_NewUTF8(info.navDestinationId.c_str(), info.navDestinationId.size(), &navDesId);
        env->Object_SetPropertyByName_Ref(res, "navDestinationId", navDesId);

        ani_string navigationId {};
        env->String_NewUTF8(info.navigationId.c_str(), info.navigationId.size(), &navigationId);
        env->Object_SetPropertyByName_Ref(res, "navigationId", navigationId);

        ani_enum navDesState;
        env->FindEnum(ANI_NAVDESTINATION_STATE_TYPE, &navDesState);
        ani_enum_item navDesStateItem;
        ani_size enumIndex = static_cast<ani_size>(info.state);
        if (info.state == NG::NavDestinationState::ON_BACKPRESS) {
            // value of ON_BACKPRESS is 100, but index of ON_BACKPRESS is 10
            enumIndex = 10;
        }
        ani_status status;
        if ((status = env->Enum_GetEnumItemByIndex(navDesState, enumIndex, &navDesStateItem)) != ANI_OK) {
            LOGE("failed to get NavDestinationState enum value by index:%{public}d, status:%{public}d",
                static_cast<int32_t>(enumIndex), static_cast<int32_t>(status));
        } else {
            env->Object_SetPropertyByName_Ref(res, "state", navDesStateItem);
        }

        ani_enum navMode;
        env->FindEnum(ANI_NAVDESTINATION_MODE_TYPE, &navMode);
        ani_enum_item navModeItem;
        env->Enum_GetEnumItemByIndex(navMode, static_cast<ani_size>(info.mode), &navModeItem);
        env->Object_SetPropertyByName_Ref(res, "mode", navModeItem);

        if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWENTY_THREE) && info.size.has_value()) {
            ani_object sizeObj = CreateSize(env, info.size.value().Width(), info.size.value().Height());
            env->Object_SetPropertyByName_Ref(res, "size", sizeObj);
        }
    }

    static void CreateTabContentUpdateInfo(ani_env* env, const NG::TabContentInfo& tabContentInfo, ani_object& res)
    {
        ani_class cls;
        env->FindClass(ANI_TABCONTENT_INFO_CLS, &cls);
        ani_method tabContentInfoCtor;
        env->Class_FindMethod(cls, "<ctor>", nullptr, &tabContentInfoCtor);
        env->Object_New(cls, tabContentInfoCtor, &res);

        env->Object_SetPropertyByName_Int(res, "tabContentUniqueId",
            static_cast<ani_int>(tabContentInfo.tabContentUniqueId));
        env->Object_SetPropertyByName_Int(res, "index", static_cast<ani_int>(tabContentInfo.index));
        env->Object_SetPropertyByName_Int(res, "uniqueId", static_cast<ani_int>(tabContentInfo.uniqueId));

        ani_string tabContentId {};
        env->String_NewUTF8(tabContentInfo.tabContentId.c_str(), tabContentInfo.tabContentId.size(), &tabContentId);
        env->Object_SetPropertyByName_Ref(res, "tabContentId", tabContentId);

        ani_string id {};
        env->String_NewUTF8(tabContentInfo.id.c_str(), tabContentInfo.id.size(), &id);
        env->Object_SetPropertyByName_Ref(res, "id", id);

        ani_enum tabState;
        env->FindEnum(ANI_TABCONTENT_STATE_TYPE, &tabState);
        ani_enum_item tabStateItem;
        env->Enum_GetEnumItemByIndex(tabState, static_cast<ani_size>(tabContentInfo.state), &tabStateItem);
        env->Object_SetPropertyByName_Ref(res, "state", tabStateItem);
    }

    static void CreateRouterPageInfo(ani_env* env, const NG::RouterPageInfoNG& pageInfo, ani_object& res)
    {
        ani_class cls;
        env->FindClass(ANI_ROUTER_INFO_CLS, &cls);
        ani_method routerInfoCtor;
        env->Class_FindMethod(cls, "<ctor>", ":", &routerInfoCtor);
        env->Object_New(cls, routerInfoCtor, &res);

        env->Object_SetPropertyByName_Int(res, "index", static_cast<ani_int>(pageInfo.index));

        ani_string routerName {};
        env->String_NewUTF8(pageInfo.name.c_str(), pageInfo.name.size(), &routerName);
        env->Object_SetPropertyByName_Ref(res, "name", routerName);

        ani_string routerPath {};
        env->String_NewUTF8(pageInfo.path.c_str(), pageInfo.path.size(), &routerPath);
        env->Object_SetPropertyByName_Ref(res, "path", routerPath);

        ani_string routerPageId {};
        env->String_NewUTF8(pageInfo.pageId.c_str(), pageInfo.pageId.size(), &routerPageId);
        env->Object_SetPropertyByName_Ref(res, "pageId", routerPageId);

        ani_enum routerState;
        env->FindEnum(ANI_ROUTER_STATE_TYPE, &routerState);
        ani_enum_item routerStateItem;
        env->Enum_GetEnumItemByIndex(routerState, static_cast<ani_size>(pageInfo.state), &routerStateItem);
        env->Object_SetPropertyByName_Ref(res, "state", routerStateItem);

        ani_class uiContextUtil;
        ani_status status;
        if ((status = env->FindClass(ANI_UICONTEXT_UTIL_CLS, &uiContextUtil)) != ANI_OK) {
            LOGE("failed to find class: %{public}s, status:%{public}d", ANI_UICONTEXT_UTIL_CLS, (int32_t)status);
        }
        ani_static_method getUiContext;
        env->Class_FindStaticMethod(
            uiContextUtil, "getOrCreateUIContextById", "i:C{@ohos.arkui.UIContext.UIContext}", &getUiContext);
        ani_int instanceId = Container::CurrentIdSafelyWithCheck();
        ani_ref uiContext;
        env->Class_CallStaticMethod_Ref(uiContextUtil, getUiContext, &uiContext, instanceId);
        env->Object_SetPropertyByName_Ref(res, "context", uiContext);

        if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWENTY_THREE) &&
            pageInfo.size.has_value()) {
            ani_object sizeObj = CreateSize(env, pageInfo.size.value().Width(), pageInfo.size.value().Height());
            env->Object_SetPropertyByName_Ref(res, "size", sizeObj);
        }
    }

    static void CreateNavSwitchInfo(ani_env* env, const NG::NavDestinationSwitchInfo& switchInfo, ani_object& res)
    {
        ani_class cls;
        env->FindClass(ANI_NAV_SWITCH_INFO, &cls);
        ani_method navSwitchCtor;
        env->Class_FindMethod(cls, "<ctor>", ":", &navSwitchCtor);
        env->Object_New(cls, navSwitchCtor, &res);

        ani_class uiContextUtil;
        env->FindClass("arkui.base.UIContextUtil.UIContextUtil", &uiContextUtil);
        ani_static_method getUiContext;
        env->Class_FindStaticMethod(
            uiContextUtil, "getOrCreateUIContextById", "i:C{@ohos.arkui.UIContext.UIContext}", &getUiContext);
        ani_int instanceId = Container::CurrentIdSafelyWithCheck();
        ani_ref uiContext;
        env->Class_CallStaticMethod_Ref(uiContextUtil, getUiContext, &uiContext, instanceId);
        env->Object_SetPropertyByName_Ref(res, "context", uiContext);

        std::string navBar = "NavBar";

        if (switchInfo.from.has_value()) {
            ani_object from;
            CreateNavigationInfo(env, switchInfo.from.value(), from);
            env->Object_SetPropertyByName_Ref(res, "from", from);
        } else {
            ani_string fromNavBar {};
            env->String_NewUTF8(navBar.c_str(), navBar.size(), &fromNavBar);
            env->Object_SetPropertyByName_Ref(res, "from", fromNavBar);
        }

        if (switchInfo.to.has_value()) {
            ani_object to;
            CreateNavigationInfo(env, switchInfo.to.value(), to);
            env->Object_SetPropertyByName_Ref(res, "to", to);
        } else {
            ani_string toNavBar {};
            env->String_NewUTF8(navBar.c_str(), navBar.size(), &toNavBar);
            env->Object_SetPropertyByName_Ref(res, "to", toNavBar);
        }

        ani_enum operation;
        env->FindEnum(ANI_NAVIGATION_OPERATION_TYPE, &operation);
        ani_enum_item operationItem;
        env->Enum_GetEnumItemByIndex(operation, static_cast<ani_size>(switchInfo.operation), &operationItem);
        env->Object_SetPropertyByName_Ref(res, "operation", operationItem);
    }

    static void CreateScrollEventInfo(ani_env* env, const NG::ScrollEventInfo& info, ani_object& res)
    {
        ani_class cls;
        env->FindClass(ANI_SCROLL_EVENT_INFO_CLS, &cls);
        ani_method ctor;
        env->Class_FindMethod(cls, "<ctor>", ":", &ctor);
        env->Object_New(cls, ctor, &res);

        ani_string id {};
        env->String_NewUTF8(info.id.c_str(), info.id.size(), &id);
        env->Object_SetPropertyByName_Ref(res, "id", id);

        env->Object_SetPropertyByName_Int(res, "uniqueId", static_cast<ani_int>(info.uniqueId));

        ani_enum scrollEvent;
        env->FindEnum(ANI_SCROLL_EVENT_TYPE, &scrollEvent);
        ani_enum_item scrollEventItem;
        env->Enum_GetEnumItemByIndex(scrollEvent, static_cast<ani_size>(info.scrollEvent), &scrollEventItem);
        env->Object_SetPropertyByName_Ref(res, "scrollEvent", scrollEventItem);

        env->Object_SetPropertyByName_Double(res, "offset", static_cast<ani_double>(info.offset));

        ani_enum axis;
        env->FindEnum(ANI_SCROLL_AXIS, &axis);
        ani_enum_item axisItem;
        if (info.axis == Axis::VERTICAL) {
            env->Enum_GetEnumItemByName(axis, "VERTICAL", &axisItem);
        } else {
            env->Enum_GetEnumItemByName(axis, "HORIZONTAL", &axisItem);
        }
        env->Object_SetPropertyByName_Ref(res, "axis", axisItem);
    }

    void HandleScrollEvent(ani_env* env, const NG::ScrollEventInfo& info)
    {
        auto unspecifiedHolder = unspecifiedScrollEventListeners_;
        std::vector<ani_ref> cbParam;
        ani_ref fnRetrunVal;
        ani_object res;
        CreateScrollEventInfo(env, info, res);
        cbParam.emplace_back(res);
        for (auto& cb : unspecifiedHolder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnRetrunVal);
        }

        auto iter = specifiedScrollEventListeners_.find(info.id);
        if (iter == specifiedScrollEventListeners_.end()) {
            return;
        }

        auto holder = iter->second;
        std::vector<ani_ref> cbParamsWithId;
        ani_ref fnReturnValWithId;
        ani_object resWithId;
        CreateScrollEventInfo(env, info, resWithId);
        cbParamsWithId.emplace_back(resWithId);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParamsWithId.size(), cbParamsWithId.data(), &fnReturnValWithId);
        }
    }

    // UIObserver.on(type: "scrollEvent", callback)
    void RegisterScrollEventCallback(ani_ref& cb)
    {
        if (std::find(unspecifiedScrollEventListeners_.begin(), unspecifiedScrollEventListeners_.end(), cb) !=
            unspecifiedScrollEventListeners_.end()) {
            return;
        }
        unspecifiedScrollEventListeners_.emplace_back(cb);
    }

    // UIObserver.off(type: "scrollEvent", callback)
    void UnRegisterScrollEventCallback(ani_env* env, ani_ref& cb)
    {
        if (cb == nullptr) {
            unspecifiedScrollEventListeners_.clear();
            return;
        }

        unspecifiedScrollEventListeners_.erase(
            std::remove_if(unspecifiedScrollEventListeners_.begin(), unspecifiedScrollEventListeners_.end(),
                [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            unspecifiedScrollEventListeners_.end());
    }

    void RegisterScrollEventCallback(std::string scrollEventId, ani_ref& cb)
    {
        auto iter = specifiedScrollEventListeners_.find(scrollEventId);
        if (iter == specifiedScrollEventListeners_.end()) {
            specifiedScrollEventListeners_.emplace(scrollEventId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    void UnRegisterScrollEventCallback(ani_env* env, std::string scrollEventId, ani_ref& cb)
    {
        auto iter = specifiedScrollEventListeners_.find(scrollEventId);
        if (iter == specifiedScrollEventListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            holder.clear();
            return;
        }
        holder.erase(std::remove_if(
            holder.begin(), holder.end(), [env, cb, this](ani_ref cb1) { return AniEqual(env, cb, cb1); }),
            holder.end());
    }

    static void RegisterRouterPageSizeChangeCallback(ani_ref& cb)
    {
        if (std::find(routerPageSizeChangeListeners_.begin(), routerPageSizeChangeListeners_.end(), cb) !=
            routerPageSizeChangeListeners_.end()) {
            return;
        }
        routerPageSizeChangeListeners_.emplace_back(cb);
    }

    static void UnRegisterRouterPageSizeChangeCallback(ani_env* env, ani_ref& cb)
    {
        if (cb == nullptr) {
            for (auto& callback : routerPageSizeChangeListeners_) {
                env->GlobalReference_Delete(callback);
            }
            routerPageSizeChangeListeners_.clear();
            return;
        }

        routerPageSizeChangeListeners_.erase(
            std::remove_if(routerPageSizeChangeListeners_.begin(), routerPageSizeChangeListeners_.end(),
                [env, cb](ani_ref cb1) {
                    auto result = AniEqual(env, cb, cb1);
                    if (result) {
                        env->GlobalReference_Delete(cb1);
                    }
                    return result;
                }),
            routerPageSizeChangeListeners_.end());
    }

    static void RegisterNavDestinationSizeChangeCallback(ani_ref& cb)
    {
        if (std::find(unspecifiedNavDestinationSizeChangeListeners_.begin(),
            unspecifiedNavDestinationSizeChangeListeners_.end(), cb) !=
            unspecifiedNavDestinationSizeChangeListeners_.end()) {
            return;
        }
        unspecifiedNavDestinationSizeChangeListeners_.emplace_back(cb);
    }

    static void UnRegisterNavDestinationSizeChangeCallback(ani_env* env, ani_ref& cb)
    {
        if (cb == nullptr) {
            for (auto& callback : unspecifiedNavDestinationSizeChangeListeners_) {
                env->GlobalReference_Delete(callback);
            }
            unspecifiedNavDestinationSizeChangeListeners_.clear();
            return;
        }

        unspecifiedNavDestinationSizeChangeListeners_.erase(
            std::remove_if(unspecifiedNavDestinationSizeChangeListeners_.begin(),
                unspecifiedNavDestinationSizeChangeListeners_.end(),
                [env, cb](ani_ref cb1) {
                    auto result = AniEqual(env, cb, cb1);
                    if (result) {
                        env->GlobalReference_Delete(cb1);
                    }
                    return result;
                }),
            unspecifiedNavDestinationSizeChangeListeners_.end());
    }

    static void RegisterNavDestinationSizeChangeByUniqueIdCallback(ani_int uniqueId, ani_ref& cb)
    {
        auto iter = specifiedNavDestinationSizeChangeListeners_.find(uniqueId);
        if (iter == specifiedNavDestinationSizeChangeListeners_.end()) {
            specifiedNavDestinationSizeChangeListeners_.emplace(uniqueId, std::list<ani_ref>({ cb }));
            return;
        }
        auto& holder = iter->second;
        if (std::find(holder.begin(), holder.end(), cb) != holder.end()) {
            return;
        }
        holder.emplace_back(cb);
    }

    static void UnRegisterNavDestinationSizeChangeByUniqueIdCallback(ani_env* env, ani_int uniqueId, ani_ref& cb)
    {
        auto iter = specifiedNavDestinationSizeChangeListeners_.find(uniqueId);
        if (iter == specifiedNavDestinationSizeChangeListeners_.end()) {
            return;
        }
        auto& holder = iter->second;
        if (cb == nullptr) {
            for (auto& callback : holder) {
                env->GlobalReference_Delete(callback);
            }
            holder.clear();
            return;
        }
        holder.erase(
            std::remove_if(holder.begin(), holder.end(),
                [env, cb](ani_ref cb1) {
                    auto result = AniEqual(env, cb, cb1);
                    if (result) {
                        env->GlobalReference_Delete(cb1);
                    }
                    return result;
                }),
            holder.end());
    }

    static void HandleRouterPageSizeChange(ani_env* env, const NG::RouterPageInfoNG& info)
    {
        if (routerPageSizeChangeListeners_.empty()) {
            return;
        }
        ani_object res;
        CreateRouterPageInfo(env, info, res);
        std::vector<ani_ref> cbParam;
        cbParam.emplace_back(res);
        ani_ref fnReturnVal;
        auto listeners = routerPageSizeChangeListeners_;
        for (const auto& cb : listeners) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnReturnVal);
        }
    }

    static void HandleNavDestinationSizeChange(ani_env* env, const NG::NavDestinationInfo& info)
    {
        if (unspecifiedNavDestinationSizeChangeListeners_.empty()) {
            return;
        }
        auto unspecifiedHolder = unspecifiedNavDestinationSizeChangeListeners_;
        std::vector<ani_ref> cbParam;
        ani_ref fnRetrunVal;
        ani_object res;
        CreateNavigationInfo(env, info, res);
        cbParam.emplace_back(res);
        for (auto& cb : unspecifiedHolder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnRetrunVal);
        }
    }

    static void HandleNavDestinationSizeChangeByUniqueId(ani_env* env, const NG::NavDestinationInfo& info)
    {
        auto iter = specifiedNavDestinationSizeChangeListeners_.find(info.navigationUniqueId);
        if (iter == specifiedNavDestinationSizeChangeListeners_.end()) {
            return;
        }
        auto holder = iter->second;
        if (holder.empty()) {
            return;
        }
        std::vector<ani_ref> cbParam;
        ani_ref fnRetrunVal;
        ani_object res;
        CreateNavigationInfo(env, info, res);
        cbParam.emplace_back(res);
        for (auto& cb : holder) {
            env->FunctionalObject_Call(
                reinterpret_cast<ani_fn_object>(cb), cbParam.size(), cbParam.data(), &fnRetrunVal);
        }
    }

private:
    void SetLastIndexForTabContentInfo(ani_env* env, const NG::TabContentInfo& info, ani_class& cls, ani_object& res)
    {
        if (!info.lastIndex) {
            return;
        }
        if (ANI_OK == env->Object_SetPropertyByName_Int(res, "lastIndex",
            static_cast<ani_int>(info.lastIndex.value()))) {
            return;
        }
        ani_static_method setLastIndex;
        if (ANI_OK != env->Class_FindStaticMethod(cls, "setTabContentInfoImplLastIndex",
            "C{@ohos.arkui.observer.uiObserver.TabContentInfoImpl}i:", &setLastIndex)) {
            return;
        }
        env->Class_CallStaticMethod_Void(cls, setLastIndex, res, static_cast<ani_int>(info.lastIndex.value()));
    }

    void CreateTabContentInfo(ani_env* env, const NG::TabContentInfo& info, ani_object& res)
    {
        ani_class cls;
        if (ANI_OK != env->FindClass(ANI_TABCONTENT_INFO_CLS, &cls)) {
            return;
        }
        ani_method tabContentInfoCtor;
        if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &tabContentInfoCtor)) {
            return;
        }
        if (ANI_OK != env->Object_New(cls, tabContentInfoCtor, &res)) {
            return;
        }
        ani_string tabContentId {};
        if (ANI_OK != env->String_NewUTF8(info.tabContentId.c_str(), info.tabContentId.size(), &tabContentId)) {
            return;
        }
        if (ANI_OK != env->Object_SetPropertyByName_Ref(res, "tabContentId", tabContentId)) {
            return;
        }
        if (ANI_OK != env->Object_SetPropertyByName_Int(res, "tabContentUniqueId",
            static_cast<ani_int>(info.tabContentUniqueId))) {
            return;
        }
        ani_enum state;
        if (ANI_OK != env->FindEnum(ANI_TABCONTENT_STATE_TYPE, &state)) {
            return;
        }
        ani_enum_item stateItem;
        if (ANI_OK != env->Enum_GetEnumItemByIndex(state, static_cast<ani_size>(info.state), &stateItem)) {
            return;
        }
        if (ANI_OK != env->Object_SetPropertyByName_Ref(res, "state", stateItem)) {
            return;
        }
        if (ANI_OK != env->Object_SetPropertyByName_Int(res, "index", static_cast<ani_int>(info.index))) {
            return;
        }
        ani_string id {};
        if (ANI_OK != env->String_NewUTF8(info.id.c_str(), info.id.size(), &id)) {
            return;
        }
        if (ANI_OK != env->Object_SetPropertyByName_Ref(res, "id", id)) {
            return;
        }
        if (ANI_OK != env->Object_SetPropertyByName_Int(res, "uniqueId", static_cast<ani_int>(info.uniqueId))) {
            return;
        }
        SetLastIndexForTabContentInfo(env, info, cls, res);
    }

    void CreateTextChangeEventInfo(ani_env* env, const NG::TextChangeEventInfo& info, ani_object& res)
    {
        static const char* className = "@ohos.arkui.observer.uiObserver.TextChangeEventInfoImpl";
        ani_class cls;
        if (ANI_OK != env->FindClass(className, &cls)) {
            LOGE("failed to find class");
            return;
        }

        ani_method ctor;
        if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", ":", &ctor)) {
            LOGE("failed to find constructor");
            return;
        }

        if (ANI_OK != env->Object_New(cls, ctor, &res)) {
            LOGE("failed to create object");
            return;
        }

        ani_string id {};
        env->String_NewUTF8(info.id.c_str(), info.id.size(), &id);
        env->Object_SetPropertyByName_Ref(res, "id", id);
        env->Object_SetPropertyByName_Int(res, "uniqueId", static_cast<ani_int>(info.uniqueId));
        ani_string content {};
        env->String_NewUTF8(info.content.c_str(), info.content.size(), &content);
        env->Object_SetPropertyByName_Ref(res, "content", content);
    }

    void CreateSwiperContentUpdateEventInfo(ani_env* env, const NG::SwiperContentInfo& info, ani_object& res)
    {
        static const char* className = "@ohos.arkui.UIContext.SwiperContentInfoImpl";
        static const char* swiperItemClassName = "@ohos.arkui.UIContext.SwiperItemInfoImpl";
        ani_class cls;
        if (ANI_OK != env->FindClass(className, &cls)) {
            LOGE("failed to find class");
            return;
        }

        ani_method ctor;
        if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", ":", &ctor)) {
            LOGE("failed to find constructor");
            return;
        }

        if (ANI_OK != env->Object_New(cls, ctor, &res)) {
            LOGE("failed to create object");
            return;
        }

        ani_string id {};
        env->String_NewUTF8(info.id.c_str(), info.id.size(), &id);
        env->Object_SetPropertyByName_Ref(res, "id", id);
        env->Object_SetPropertyByName_Int(res, "uniqueId", static_cast<ani_int>(info.uniqueId));
        ani_array swiperItemInfos;
        auto arraySize = info.swiperItemInfos.size();
        ani_ref undefined {};
        env->GetUndefined(&undefined);
        env->Array_New(arraySize, undefined, &swiperItemInfos);
        
        ani_class swiperItemClass {};
        if (ANI_OK != env->FindClass(swiperItemClassName, &swiperItemClass)) {
            LOGE("failed to find class");
            return;
        }

        ani_method swiperItemCtor {};
        if (ANI_OK != env->Class_FindMethod(swiperItemClass, "<ctor>", ":", &swiperItemCtor)) {
            LOGE("failed to find constructor");
            return;
        }

        ani_object item {};
        for (uint32_t index = 0; index < arraySize; index++) {
            env->Object_New(swiperItemClass, swiperItemCtor, &item);
            env->Object_SetPropertyByName_Int(item, "uniqueId",
                static_cast<ani_int>(info.swiperItemInfos[index].uniqueId));
            env->Object_SetPropertyByName_Int(item, "index",
                static_cast<ani_int>(info.swiperItemInfos[index].index));
            env->Array_Set(swiperItemInfos, index, item);
        }
        env->Object_SetPropertyByName_Ref(res, "swiperItemInfos", swiperItemInfos);
    }

    int32_t id_;
    std::unordered_map<int32_t, std::list<ani_ref>> densityCbMap_;

    std::unordered_map<int32_t, std::list<ani_ref>> specifiedBeforePanStartCbMap_;
    std::unordered_map<int32_t, std::list<ani_ref>> specifiedAfterPanStartCbMap_;
    std::unordered_map<int32_t, std::list<ani_ref>> specifiedBeforePanEndCbMap_;
    std::unordered_map<int32_t, std::list<ani_ref>> specifiedAfterPanEndCbMap_;

    std::unordered_map<int32_t, std::list<ani_ref>> specifiedWillClickCbMap_;
    std::unordered_map<int32_t, std::list<ani_ref>> specifiedDidClickCbMap_;
    static std::list<ani_ref> unspecifiedNavigationListeners_;
    static std::unordered_map<std::string, std::list<ani_ref>> specifiedCNavigationListeners_;
    static std::unordered_map<int32_t, std::list<ani_ref>> specifiedRouterPageListeners_;
    static std::unordered_map<int32_t, NavIdAndListenersMap> uiContextNavDesSwitchListeners_;
    static std::list<ani_ref> unspecifiedTabContentListeners_;
    static std::unordered_map<std::string, std::list<ani_ref>> specifiedTabContentUpdateListeners_;
    std::unordered_map<int32_t, std::list<ani_ref>> specifiedWillDrawCbMap_;
    std::unordered_map<int32_t, std::list<ani_ref>> specifiedDidLayoutCbMap_;
    std::list<ani_ref> unspecifiedScrollEventListeners_;
    std::unordered_map<std::string, std::list<ani_ref>> specifiedScrollEventListeners_;

    bool hasSetTabChangeCallback_ = false;
    std::list<ani_ref> unspecifiedTabChangeListeners_;
    std::unordered_map<std::string, std::list<ani_ref>> specifiedTabChangeListeners_;

    static std::list<ani_ref> routerPageSizeChangeListeners_;
    static std::list<ani_ref> unspecifiedNavDestinationSizeChangeListeners_;
    static std::unordered_map<int32_t, std::list<ani_ref>> specifiedNavDestinationSizeChangeListeners_;
    static std::unordered_map<int32_t, std::list<ani_ref>> specifiedWindowSizeBreakpointListeners_;

    bool hasSetTextChangeCallback_ = false;
    std::list<ani_ref> unspecifiedTextChangeListeners_;
    std::unordered_map<std::string, std::list<ani_ref>> specifiedTextChangeListeners_;

    bool hasSetSwiperContentUpdateCallback_ = false;
    std::list<ani_ref> unspecifiedSwiperContentUpdateListeners_;
    std::unordered_map<std::string, std::list<ani_ref>> specifiedSwiperContentUpdateListeners_;
};

std::list<ani_ref> UiObserver::unspecifiedNavigationListeners_;
std::unordered_map<std::string, std::list<ani_ref>> UiObserver::specifiedCNavigationListeners_;
std::unordered_map<int32_t, std::list<ani_ref>> UiObserver::specifiedRouterPageListeners_;
std::unordered_map<int32_t, NavIdAndListenersMap> UiObserver::uiContextNavDesSwitchListeners_;

std::list<ani_ref> UiObserver::routerPageSizeChangeListeners_;
std::list<ani_ref> UiObserver::unspecifiedNavDestinationSizeChangeListeners_;
std::unordered_map<int32_t, std::list<ani_ref>> UiObserver::specifiedNavDestinationSizeChangeListeners_;
std::unordered_map<int32_t, std::list<ani_ref>> UiObserver::specifiedWindowSizeBreakpointListeners_;

std::list<ani_ref> UiObserver::unspecifiedTabContentListeners_;
std::unordered_map<std::string, std::list<ani_ref>> UiObserver::specifiedTabContentUpdateListeners_;

static UiObserver* Unwrapp(ani_env* env, ani_object object)
{
    ani_long nativeAddr;
    if (ANI_OK != env->Object_GetFieldByName_Long(object, "nativeObserverAddr", &nativeAddr)) {
        return nullptr;
    }
    return reinterpret_cast<UiObserver*>(nativeAddr);
}

static std::string ANIUtils_ANIStringToStdString(ani_env* env, ani_string ani_str)
{
    ani_size strSize;
    env->String_GetUTF8Size(ani_str, &strSize);

    std::vector<char> buffer(strSize + 1);
    char* utf8Buffer = buffer.data();

    ani_size bytes_written = 0;
    env->String_GetUTF8(ani_str, utf8Buffer, strSize + 1, &bytes_written);

    utf8Buffer[bytes_written] = '\0';
    std::string content = std::string(utf8Buffer);
    return content;
}

static void On([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_string type, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    std::string typeStr = ANIUtils_ANIStringToStdString(env, type);
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    const int idMs = 100000;
    if (typeStr == "beforePanStart") {
        observer->RegisterBeforePanStartCallback(idMs, fnObjGlobalRef);
    } else if (typeStr == "afterPanStart") {
        observer->RegisterAfterPanStartCallback(idMs, fnObjGlobalRef);
    } else if (typeStr == "beforePanEnd") {
        observer->RegisterBeforePanEndCallback(idMs, fnObjGlobalRef);
    } else if (typeStr == "afterPanEnd") {
        observer->RegisterAfterPanEndCallback(idMs, fnObjGlobalRef);
    } else if (typeStr == "willClick") {
        observer->RegisterWillClickCallback(idMs, fnObjGlobalRef);
    } else if (typeStr == "didClick") {
        observer->RegisterDidClickCallback(idMs, fnObjGlobalRef);
    }
}

static void OnDensityUpdate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    const int idMs = 100000;
    observer->RegisterDensityCallback(idMs, fnObjGlobalRef);
}

static void OnWillDraw([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    auto willDrawCallback = [observer, env]() { observer->HandleWillDraw(env); };
    NG::UIObserverHandler::GetInstance().SetDrawCommandSendHandleFunc(willDrawCallback);
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    const int idMs = 100000;
    observer->RegisterWillDrawCallback(idMs, fnObjGlobalRef);
}

static void OnDidLayout([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    const int idMs = 100000;
    auto didLayoutCallback = [observer, env]() { observer->HandleDidLayout(env); };
    NG::UIObserverHandler::GetInstance().SetLayoutDoneHandleFunc(didLayoutCallback);
    observer->RegisterDidLayoutCallback(idMs, fnObjGlobalRef);
}

static void Off([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_string type, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    std::string typeStr = ANIUtils_ANIStringToStdString(env, type);
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    const int idMs = 100000;
    if (typeStr == "beforePanStart") {
        observer->UnRegisterBeforePanStartCallback(env, idMs, fnObjGlobalRef);
    } else if (typeStr == "afterPanStart") {
        observer->UnRegisterAfterPanStartCallback(env, idMs, fnObjGlobalRef);
    } else if (typeStr == "beforePanEnd") {
        observer->UnRegisterBeforePanEndCallback(env, idMs, fnObjGlobalRef);
    } else if (typeStr == "afterPanEnd") {
        observer->UnRegisterAfterPanEndCallback(env, idMs, fnObjGlobalRef);
    } else if (typeStr == "willClick") {
        observer->UnRegisterWillClickCallback(env, idMs, fnObjGlobalRef);
    } else if (typeStr == "didClick") {
        observer->UnRegisterDidClickCallback(env, idMs, fnObjGlobalRef);
    }
}

static void OffDensityUpdate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    const int idMs = 100000;
    observer->UnRegisterDensityCallback(env, idMs, fnObjGlobalRef);
}

static void OffWillDraw([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    const int idMs = 100000;
    observer->UnRegisterWillDrawCallback(env, idMs, fnObjGlobalRef);
}

static void OffDidLayout([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    const int idMs = 100000;
    observer->UnRegisterDidLayoutCallback(env, idMs, fnObjGlobalRef);
}

static void OnTabContentUpdate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterTabContentUpdateCallback(fnObjGlobalRef);
}

static void OnTabContentUpdateWithOptions([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref aniTabId;
    env->Object_GetPropertyByName_Ref(options, "id", &aniTabId);
    std::string tabContentId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniTabId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterTabContentUpdateCallback(tabContentId, fnObjGlobalRef);
}

static void OffTabContentUpdate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    observer->UnRegisterTabContentUpdateCallback(env, fnObjGlobalRef);
}

static void OffTabContentUpdateWithOptions([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref aniTabId;
    env->Object_GetPropertyByName_Ref(options, "id", &aniTabId);
    std::string tabContentId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniTabId));
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    observer->UnRegisterTabContentUpdateCallback(env, tabContentId, fnObjGlobalRef);
}

static void OnTabContentUpdateForNamespace([[maybe_unused]] ani_env* env, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }

    static std::once_flag onceFlag;
    std::call_once(onceFlag, [&env]() {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in OnTabContentUpdateForNamespace, status:%{public}d", static_cast<int32_t>(status));
            return;
        }
        auto tabContentCallback = [vm](const NG::TabContentInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in OnTabContentUpdateForNamespace, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            UiObserver::HandleTabContentUpdate(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleTabContentUpdateFuncForAni(tabContentCallback);
    });

    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    UiObserver::RegisterTabContentUpdateCallback(fnObjGlobalRef);
}

static void OnTabContentUpdateWithOptionsForNamespace([[maybe_unused]] ani_env* env,
    ani_object options, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }

    static std::once_flag onceFlag;
    std::call_once(onceFlag, [&env]() {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in OnTabContentUpdateWithOptionsForNamespace, status:%{public}d",
                static_cast<int32_t>(status));
            return;
        }
        auto tabContentCallback = [vm](const NG::TabContentInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in OnTabContentUpdateWithOptionsForNamespace, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            UiObserver::HandleTabContentUpdate(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleTabContentUpdateFuncForAni(tabContentCallback);
    });

    ani_ref aniTabId;
    env->Object_GetPropertyByName_Ref(options, "id", &aniTabId);
    std::string tabContentId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniTabId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    UiObserver::RegisterTabContentUpdateCallback(tabContentId, fnObjGlobalRef);
}

static void OffTabContentUpdateForNamespace([[maybe_unused]] ani_env* env, ani_fn_object fnObj)
{
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    UiObserver::UnRegisterTabContentUpdateCallback(env, fnObjGlobalRef);
}

static void OffTabContentUpdateWithOptionsForNamespace([[maybe_unused]] ani_env* env,
    ani_object options, ani_fn_object fnObj)
{
    ani_ref aniTabId;
    env->Object_GetPropertyByName_Ref(options, "id", &aniTabId);
    std::string tabContentId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniTabId));
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    UiObserver::UnRegisterTabContentUpdateCallback(env, tabContentId, fnObjGlobalRef);
}

static void OnNavDestinationUpdateWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref aniNavId;
    env->Object_GetPropertyByName_Ref(options, "navigationId", &aniNavId);
    std::string navigationId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniNavId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterNavigationCallback(navigationId, fnObjGlobalRef);
}

static void OffNavDestinationUpdateWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref aniNavId;
    env->Object_GetPropertyByName_Ref(options, "navigationId", &aniNavId);
    std::string navigationId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniNavId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->UnRegisterNavigationCallback(env, navigationId, fnObjGlobalRef);
}

static void OnNavDestinationUpdateWithIdContext([[maybe_unused]] ani_env* env,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    ani_ref aniNavId;
    env->Object_GetPropertyByName_Ref(options, "navigationId", &aniNavId);
    std::string navigationId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniNavId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    static std::once_flag onceFlag;
    std::call_once(onceFlag, [&env]() {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in OnNavDestinationUpdateWithIdContext, status:%{public}d",
                static_cast<int32_t>(status));
            return;
        }
        auto navigationStateChangeCalback = [vm](const NG::NavDestinationInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in OnNavDestinationUpdateWithIdContext, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            UiObserver::HandleNavigationStateChange(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleNavigationChangeFuncForAni(navigationStateChangeCalback);
    });

    UiObserver::RegisterNavigationCallback(navigationId, fnObjGlobalRef);
}

static void OffNavDestinationUpdateWithIdContext([[maybe_unused]] ani_env* env,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    ani_ref aniNavId;
    env->Object_GetPropertyByName_Ref(options, "navigationId", &aniNavId);
    std::string navigationId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniNavId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    UiObserver::UnRegisterNavigationCallback(env, navigationId, fnObjGlobalRef);
}

static void onNavDestinationUpdate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,

    ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    observer->RegisterNavigationCallback(fnObjGlobalRef);
}

static void offNavDestinationUpdate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    observer->UnRegisterNavigationCallback(env, fnObjGlobalRef);
}

static void onNavDestinationUpdateContext([[maybe_unused]] ani_env* env, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    static std::once_flag onceFlag;
    std::call_once(onceFlag, [&env]() {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in onNavDestinationUpdateContext, status:%{public}d", static_cast<int32_t>(status));
            return;
        }
        auto navigationStateChangeCalback = [vm](const NG::NavDestinationInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in onNavDestinationUpdateContext, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            UiObserver::HandleNavigationStateChange(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleNavigationChangeFuncForAni(navigationStateChangeCalback);
    });

    UiObserver::RegisterNavigationCallback(fnObjGlobalRef);
}

static void offNavDestinationUpdateContext([[maybe_unused]] ani_env* env, ani_fn_object fnObj)
{
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    UiObserver::UnRegisterNavigationCallback(env, fnObjGlobalRef);
}

static void onRouterPageUpdate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    const int idMs = 100000;
    observer->RegisterRouterPageCallback(idMs, fnObjGlobalRef);
}

static void offRouterPageUpdate([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    const int idMs = 100000;
    observer->UnRegisterRouterPageCallback(env, idMs, fnObjGlobalRef);
}

static void onRouterPageUpdateContext([[maybe_unused]] ani_env* env, ani_object uiContext, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    static std::once_flag onceFlag;
    std::call_once(onceFlag, [&env]() {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in onRouterPageUpdateContext, status:%{public}d", static_cast<int32_t>(status));
            return;
        }
        auto routerPageInfoChangeCallback = [vm](
            NG::AbilityContextInfo& context, const NG::RouterPageInfoNG& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in onRouterPageUpdateContext, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            UiObserver::HandleRouterPageStateChange(env, context, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleRouterPageChangeFuncForAni(routerPageInfoChangeCallback);
    });

    ani_int idMs = 0;
    env->Object_GetPropertyByName_Int(uiContext, "instanceId_", &idMs);
    UiObserver::RegisterRouterPageCallback(idMs, fnObjGlobalRef);
}

static void offRouterPageUpdateContext([[maybe_unused]] ani_env* env, ani_object uiContext, ani_fn_object fnObj)
{
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    ani_int idMs = 0;
    env->Object_GetPropertyByName_Int(uiContext, "instanceId_", &idMs);
    UiObserver::UnRegisterRouterPageCallback(env, idMs, fnObjGlobalRef);
}

static void onNavDestinationSwitch([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    std::optional<std::string> navId;
    const int idMs = 100000;
    observer->RegisterNavDestinationSwitchCallback(idMs, navId, fnObjGlobalRef);
}

static void offNavDestinationSwitch([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    std::optional<std::string> navId;
    const int idMs = 100000;
    observer->UnRegisterNavDestinationSwitchCallback(env, idMs, navId, fnObjGlobalRef);
}

static void onNavDestinationSwitchContext([[maybe_unused]] ani_env* env, ani_object uiContext, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    static std::once_flag onceFlag;
    std::call_once(onceFlag, [&env]() {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in onNavDestinationSwitchContext, status:%{public}d", static_cast<int32_t>(status));
            return;
        }
        auto navDestinationSwitchCallback = [vm](NG::NavDestinationSwitchInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in onNavDestinationSwitchContext, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            UiObserver::HandleUIContextNavDestinationSwitch(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleNavDestinationSwitchFuncForAni(navDestinationSwitchCallback);
    });

    std::optional<std::string> navId;
    ani_int idMs = 0;
    env->Object_GetPropertyByName_Int(uiContext, "instanceId_", &idMs);
    UiObserver::RegisterNavDestinationSwitchCallback(idMs, navId, fnObjGlobalRef);
}

static void offNavDestinationSwitchContext([[maybe_unused]] ani_env* env, ani_object uiContext, ani_fn_object fnObj)
{
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    std::optional<std::string> navId;
    ani_int idMs = 0;
    env->Object_GetPropertyByName_Int(uiContext, "instanceId_", &idMs);
    UiObserver::UnRegisterNavDestinationSwitchCallback(env, idMs, navId, fnObjGlobalRef);
}

static void onNavDestinationSwitchWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref aniNavId;
    env->Object_GetPropertyByName_Ref(options, "navigationId", &aniNavId);
    std::string navigationId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniNavId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    const int idMs = 100000;
    observer->RegisterNavDestinationSwitchCallback(idMs, navigationId, fnObjGlobalRef);
}

static void offNavDestinationSwitchWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref aniNavId;
    env->Object_GetPropertyByName_Ref(options, "navigationId", &aniNavId);
    std::string navigationId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniNavId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    const int idMs = 100000;
    observer->UnRegisterNavDestinationSwitchCallback(env, idMs, navigationId, fnObjGlobalRef);
}

static void onNavDestinationSwitchWithIdContext([[maybe_unused]] ani_env* env, ani_object uiContext,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    ani_ref aniNavId;
    env->Object_GetPropertyByName_Ref(options, "navigationId", &aniNavId);
    std::string navigationId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniNavId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    static std::once_flag onceFlag;
    std::call_once(onceFlag, [&env]() {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in onNavDestinationSwitchWithIdContext, status:%{public}d",
                static_cast<int32_t>(status));
            return;
        }
        auto navDestinationSwitchCallback = [vm](NG::NavDestinationSwitchInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in onNavDestinationSwitchWithIdContext, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            UiObserver::HandleUIContextNavDestinationSwitch(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleNavDestinationSwitchFuncForAni(navDestinationSwitchCallback);
    });

    ani_int idMs = 0;
    env->Object_GetPropertyByName_Int(uiContext, "instanceId_", &idMs);
    UiObserver::RegisterNavDestinationSwitchCallback(idMs, navigationId, fnObjGlobalRef);
}

static void offNavDestinationSwitchWithIdContext([[maybe_unused]] ani_env* env, ani_object uiContext,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    ani_ref aniNavId;
    env->Object_GetPropertyByName_Ref(options, "navigationId", &aniNavId);
    std::string navigationId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniNavId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    ani_int idMs = 0;
    env->Object_GetPropertyByName_Int(uiContext, "instanceId_", &idMs);
    UiObserver::UnRegisterNavDestinationSwitchCallback(env, idMs, navigationId, fnObjGlobalRef);
}

static void OnWindowSizeLayoutBreakpointChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    int32_t idMs = Container::CurrentId();
    observer->RegisterWindowSizeBreakpointCallback(idMs, fnObjGlobalRef);
}

static void OffWindowSizeLayoutBreakpointChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    int32_t idMs = Container::CurrentId();
    observer->UnRegisterWindowSizeBreakpointCallback(env, idMs, fnObjGlobalRef);
}
static void onWindowSizeLayoutBreakpointChangeContext([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    int32_t idMs = Container::CurrentId();
    observer->RegisterWindowSizeBreakpointCallback(idMs, fnObjGlobalRef);
}

static void offWindowSizeLayoutBreakpointChangeContext([[maybe_unused]] ani_env* env,
                                                       [[maybe_unused]] ani_object object, ani_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    int32_t idMs = Container::CurrentId();
    observer->UnRegisterWindowSizeBreakpointCallback(env, idMs, fnObjGlobalRef);
}
static void OnTabChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    observer->RegisterTabChangeCallback(fnObjGlobalRef);
}

static void OffTabChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    observer->UnRegisterTabChangeCallback(env, fnObjGlobalRef);
}

static void OnTabChangeWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref id;
    env->Object_GetPropertyByName_Ref(options, "id", &id);
    std::string tabsId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(id));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterTabChangeCallback(tabsId, fnObjGlobalRef);
}

static void OffTabChangeWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref id;
    env->Object_GetPropertyByName_Ref(options, "id", &id);
    std::string tabsId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(id));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->UnRegisterTabChangeCallback(env, tabsId, fnObjGlobalRef);
}

static void OnSwiperContentUpdate([[maybe_unused]] ani_env* env,
    [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    observer->RegisterSwiperContentUpdateCallback(fnObjGlobalRef);
}

static void OffSwiperContentUpdate([[maybe_unused]] ani_env* env,
    [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    observer->UnRegisterSwiperContentUpdateCallback(env, fnObjGlobalRef);
}

static void OnSwiperContentUpdateWithOptions([[maybe_unused]] ani_env* env,
    [[maybe_unused]] ani_object object, ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref id;
    env->Object_GetPropertyByName_Ref(options, "id", &id);
    std::string nodeId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(id));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterSwiperContentUpdateCallback(nodeId, fnObjGlobalRef);
}

static void OffSwiperContentUpdateWithOptions([[maybe_unused]] ani_env* env,
    [[maybe_unused]] ani_object object, ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref id;
    env->Object_GetPropertyByName_Ref(options, "id", &id);
    std::string nodeId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(id));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->UnRegisterSwiperContentUpdateCallback(env, nodeId, fnObjGlobalRef);
}

static void OnTextChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    observer->RegisterTextChangeCallback(fnObjGlobalRef);
}

static void OffTextChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }

    observer->UnRegisterTextChangeCallback(env, fnObjGlobalRef);
}

static void OnTextChangeWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref id;
    env->Object_GetPropertyByName_Ref(options, "id", &id);
    std::string textId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(id));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterTextChangeCallback(textId, fnObjGlobalRef);
}

static void OffTextChangeWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        return;
    }
    ani_ref id;
    env->Object_GetPropertyByName_Ref(options, "id", &id);
    std::string textId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(id));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->UnRegisterTextChangeCallback(env, textId, fnObjGlobalRef);
}

static void OnScrollEventType([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterScrollEventCallback(fnObjGlobalRef);
}

static void OffScrollEvent([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
 
    observer->UnRegisterScrollEventCallback(env, fnObjGlobalRef);
}

static void OnScrollEventWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);

    ani_ref aniScrollId;
    env->Object_GetPropertyByName_Ref(options, "id", &aniScrollId);
    std::string scrollId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniScrollId));
    observer->RegisterScrollEventCallback(scrollId, fnObjGlobalRef);
}

static void OffScrollEventWithId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_object options, ani_fn_object fnObj)
{
    if (!fnObj) {
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (!observer) {
        LOGE("observer-ani context is null.");
        return;
    }
 
    ani_ref aniScrollId;
    env->Object_GetPropertyByName_Ref(options, "id", &aniScrollId);
    std::string scrollId = ANIUtils_ANIStringToStdString(env, reinterpret_cast<ani_string>(aniScrollId));
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->UnRegisterScrollEventCallback(env, scrollId, fnObjGlobalRef);
}

static void OnRouterPageSizeChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterRouterPageSizeChangeCallback(fnObjGlobalRef);
}

static void OffRouterPageSizeChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    observer->UnRegisterRouterPageSizeChangeCallback(env, fnObjGlobalRef);
}

static void OnNavDestinationSizeChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterNavDestinationSizeChangeCallback(fnObjGlobalRef);
}

static void OffNavDestinationSizeChange([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    observer->UnRegisterNavDestinationSizeChangeCallback(env, fnObjGlobalRef);
}

static void OnNavDestinationSizeChangeByUniqueId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_int navUniqueId, ani_fn_object fnObj)
{
    if (fnObj == nullptr) {
        LOGE("observer-ani callback is undefined.");
        return;
    }
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    observer->RegisterNavDestinationSizeChangeByUniqueIdCallback(navUniqueId, fnObjGlobalRef);
}

static void OffNavDestinationSizeChangeByUniqueId([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object object,
    ani_int navUniqueId, ani_fn_object fnObj)
{
    auto* observer = Unwrapp(env, object);
    if (observer == nullptr) {
        LOGE("observer-ani context is null.");
        return;
    }
    ani_ref fnObjGlobalRef = nullptr;
    ani_boolean isUndef = ANI_FALSE;
    env->Reference_IsUndefined(fnObj, &isUndef);
    if (isUndef != ANI_TRUE) {
        env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
    }
    observer->UnRegisterNavDestinationSizeChangeByUniqueIdCallback(env, navUniqueId, fnObjGlobalRef);
}

static ani_object CreateObserver([[maybe_unused]] ani_env* env, ani_int id)
{
    ani_class cls;
    if (ANI_OK != env->FindClass(ANI_OBSERVER_CLS, &cls)) {
        LOGE("observer-ani not found class");
        return nullptr;
    }

    ani_method ctor;
    if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
        LOGE("observer-ani can not get construct method.");
        return nullptr;
    }

    auto* observer = new UiObserver(id);
    auto densityChangeCallback = [observer, env](NG::AbilityContextInfo& info, double density) {
        observer->HandleDensityChange(env, density);
    };
    NG::UIObserverHandler::GetInstance().SetHandleDensityChangeFuncForAni(densityChangeCallback);

    auto beforePanStartCallback = [observer, env]() {
        observer->HandleBeforePanStart(env);
    };
    NG::UIObserverHandler::GetInstance().SetBeforePanStartHandleFuncForAni(beforePanStartCallback);

    auto afterPanStartCallback = [observer, env]() {
        observer->HandleAfterPanStart(env);
    };
    NG::UIObserverHandler::GetInstance().SetAfterPanStartHandleFuncForAni(afterPanStartCallback);

    auto beforePanEndCallback = [observer, env]() {
        observer->HandleBeforePanEnd(env);
    };
    NG::UIObserverHandler::GetInstance().SetBeforePanEndHandleFuncForAni(beforePanEndCallback);

    auto afterPanEndCallback = [observer, env]() {
        observer->HandleAfterPanEnd(env);
    };
    NG::UIObserverHandler::GetInstance().SetAfterPanEndHandleFuncForAni(afterPanEndCallback);

    auto willClickCallback = [observer, env]() {
        observer->HandleWillClick(env);
    };
    NG::UIObserverHandler::GetInstance().SetWillClickHandleFuncForAni(willClickCallback);
    auto didClickCallback = [observer, env]() {
        observer->HandleDidClick(env);
    };
    NG::UIObserverHandler::GetInstance().SetDidClickHandleFuncForAni(didClickCallback);

    do {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get ani vm in CreateObserver, status:%{public}d", static_cast<int32_t>(status));
            break;
        }
        auto navigationStateChangeCalback = [observer, vm](const NG::NavDestinationInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in CreateObserver, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            observer->HandleNavigationStateChange(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleNavigationChangeFuncForAni(navigationStateChangeCalback);
    } while (false);

    auto scrollEventCallback = [observer, env](const NG::ScrollEventInfo &info) {
        observer->HandleScrollEvent(env, info);
    };
    NG::UIObserverHandler::GetInstance().SetHandleScrollEventChangeFuncForAni(scrollEventCallback);

    auto tabChangeCallback = [observer, env](const NG::TabContentInfo& info) {
        observer->HandleTabChange(env, info);
    };
    NG::UIObserverHandler::GetInstance().SetHandleTabChangeFuncForAni(tabChangeCallback);
    auto textChangeCallback = [observer, env](const NG::TextChangeEventInfo& info) {
        observer->HandleTextChange(env, info);
    };
    NG::UIObserverHandler::GetInstance().SetHandleTextChangeEventFuncForAni(std::move(textChangeCallback));

    do {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get ani vm in CreateObserver, status:%{public}d", static_cast<int32_t>(status));
            break;
        }
        auto routerPageInfoChangeCallback = [observer, vm](
                                            NG::AbilityContextInfo& context, const NG::RouterPageInfoNG& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in CreateObserver, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            observer->HandleRouterPageStateChange(env, context, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleRouterPageChangeFuncForAni(routerPageInfoChangeCallback);
    } while (false);

    do {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get ani vm in CreateObserver, status:%{public}d", static_cast<int32_t>(status));
            break;
        }
        auto swiperContentUpdateCallback = [observer, vm](const NG::SwiperContentInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in CreateObserver, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            observer->HandleSwiperContentUpdate(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleSwiperContentUpdateFuncForAni(swiperContentUpdateCallback);
    } while (false);

    auto windowSizeBreakpointChangeCallback = [observer, env](
        int32_t instanceId, const WindowSizeBreakpoint& breakpoint) {
        observer->HandleWindowSizeBreakpointChange(env, instanceId, breakpoint);
    };
    NG::UIObserverHandler::GetInstance().SetWinSizeLayoutBreakpointChangeFuncAni(windowSizeBreakpointChangeCallback);

    do {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in CreateObserver for TabContentUpdate, status:%{public}d",
                static_cast<int32_t>(status));
            break;
        }
        auto tabContentCallback = [observer, vm](const NG::TabContentInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in CreateObserver for TabContentUpdate, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            observer->HandleTabContentUpdate(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleTabContentUpdateFuncForAni(tabContentCallback);
    } while (false);
    do {
        ani_vm* vm = nullptr;
        ani_status status;
        if ((status = env->GetVM(&vm)) != ANI_OK || !vm) {
            LOGE("failed to get vm in CreateObserver for nav switch, status:%{public}d", static_cast<int32_t>(status));
            break;
        }
        auto navDestinationSwitchCallback = [observer, vm](NG::NavDestinationSwitchInfo& info) {
            ani_env* env = nullptr;
            ani_status status;
            if ((status = vm->GetEnv(ANI_VERSION_1, &env)) != ANI_OK || !env) {
                LOGE("failed to get ani env in CreateObserver for nav switch, status:%{public}d",
                    static_cast<int32_t>(status));
                return;
            }
            observer->HandleUIContextNavDestinationSwitch(env, info);
        };
        NG::UIObserverHandler::GetInstance().SetHandleNavDestinationSwitchFuncForAni(navDestinationSwitchCallback);
    } while (false);

    auto routerPageSizeChangeCallback = [observer, env](const NG::RouterPageInfoNG& info) {
        observer->HandleRouterPageSizeChange(env, info);
    };
    NG::UIObserverHandler::GetInstance().SetRouterPageSizeChangeHandleFuncForAni(
        std::move(routerPageSizeChangeCallback));
    auto navDestinationSizeChangeCallback = [observer, env](const NG::NavDestinationInfo& info) {
        observer->HandleNavDestinationSizeChange(env, info);
    };
    NG::UIObserverHandler::GetInstance().SetNavDestinationSizeChangeHandleFuncForAni(
        std::move(navDestinationSizeChangeCallback));
    auto navDestinationSizeChangeByUniqueIdCallback = [observer, env](const NG::NavDestinationInfo& info) {
        observer->HandleNavDestinationSizeChangeByUniqueId(env, info);
    };
    NG::UIObserverHandler::GetInstance().SetNavDestinationSizeChangeByUniqueIdHandleFuncForAni(
        std::move(navDestinationSizeChangeByUniqueIdCallback));

    ani_object context_object;
    if (ANI_OK != env->Object_New(cls, ctor, &context_object, reinterpret_cast<ani_long>(observer))) {
        LOGE("observer-ani Can not new object.");
        return nullptr;
    }
    return context_object;
}
} // namespace OHOS::Ace
bool ANI_ConstructorForAni(ani_env* env)
{
    ani_namespace ns;
    if (ANI_OK != env->FindNamespace(ANI_OBSERVER_NS, &ns)) {
        LOGE("observer-ani Not found ns");
        return false;
    }
    std::array methods = {
        ani_native_function { "createUIObserver", nullptr, reinterpret_cast<void*>(OHOS::Ace::CreateObserver) },
        ani_native_function { "onRouterPageUpdate", ROUTER_NAVIGATION_PARAM,
            reinterpret_cast<void*>(OHOS::Ace::onRouterPageUpdateContext) },
        ani_native_function { "offRouterPageUpdate", ROUTER_NAVIGATION_PARAM,
            reinterpret_cast<void*>(OHOS::Ace::offRouterPageUpdateContext) },
        ani_native_function { "onNavDestinationUpdate",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::onNavDestinationUpdateContext) },
        ani_native_function { "offNavDestinationUpdate",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::offNavDestinationUpdateContext) },
        ani_native_function {"onNavDestinationUpdate",
            "C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OnNavDestinationUpdateWithIdContext) },
        ani_native_function { "offNavDestinationUpdate",
            "C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OffNavDestinationUpdateWithIdContext) },
        ani_native_function { "onTabContentUpdate", ANI_TABCONTENT_WITH_OPTIONS_CLS,
            reinterpret_cast<void*>(OHOS::Ace::OnTabContentUpdateWithOptionsForNamespace) },
        ani_native_function { "offTabContentUpdate", ANI_TABCONTENT_WITH_OPTIONS_CLS,
            reinterpret_cast<void*>(OHOS::Ace::OffTabContentUpdateWithOptionsForNamespace) },
        ani_native_function { "onTabContentUpdate", ANI_TABCONTENT_CLS,
            reinterpret_cast<void*>(OHOS::Ace::OnTabContentUpdateForNamespace) },
        ani_native_function { "offTabContentUpdate", ANI_TABCONTENT_CLS,
            reinterpret_cast<void*>(OHOS::Ace::OffTabContentUpdateForNamespace) },
        ani_native_function { "onNavDestinationSwitch", ROUTER_NAVIGATION_PARAM,
            reinterpret_cast<void*>(OHOS::Ace::onNavDestinationSwitchContext) },
        ani_native_function { "offNavDestinationSwitch", ROUTER_NAVIGATION_PARAM,
            reinterpret_cast<void*>(OHOS::Ace::offNavDestinationSwitchContext) },
        ani_native_function { "onNavDestinationSwitch",
            "X{C{application.UIAbilityContext.UIAbilityContext}C{@ohos.arkui.UIContext.UIContext}}"
            "C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::onNavDestinationSwitchWithIdContext) },
        ani_native_function { "offNavDestinationSwitch",
            "X{C{application.UIAbilityContext.UIAbilityContext}C{@ohos.arkui.UIContext.UIContext}}"
            "C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::offNavDestinationSwitchWithIdContext) },
        ani_native_function { "onWindowSizeLayoutBreakpointChange",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::onWindowSizeLayoutBreakpointChangeContext) },
        ani_native_function { "offWindowSizeLayoutBreakpointChange",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::offWindowSizeLayoutBreakpointChangeContext) },
    };

    if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) {
        LOGE("observer-ani Namespace_BindNativeFunctions error");
        return false;
    }

    ani_class clsObserver;
    if (ANI_OK != env->FindClass(ANI_OBSERVER_CLS, &clsObserver)) {
        LOGE("observer-ani not found class");
        return false;
    }

    std::array methodsObserver = {
        ani_native_function { "on", "C{std.core.String}C{std.core.Object}:", reinterpret_cast<void*>(OHOS::Ace::On) },
        ani_native_function { "off", "C{std.core.String}C{std.core.Object}:", reinterpret_cast<void*>(OHOS::Ace::Off) },
        ani_native_function {
            "on", NAVDESTINATION_PARAM_WITHID, reinterpret_cast<void*>(OHOS::Ace::OnNavDestinationUpdateWithId) },
        ani_native_function {
            "off", NAVDESTINATION_PARAM_WITHID, reinterpret_cast<void*>(OHOS::Ace::OffNavDestinationUpdateWithId) },
        ani_native_function { "onNavDestinationUpdate",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::onNavDestinationUpdate) },
        ani_native_function { "offNavDestinationUpdate",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::offNavDestinationUpdate) },
        ani_native_function { "onNavDestinationUpdate",
            "C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OnNavDestinationUpdateWithId) },
        ani_native_function { "offNavDestinationUpdate",
            "C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OffNavDestinationUpdateWithId) },
        ani_native_function {
            "onRouterPageUpdate", "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::onRouterPageUpdate) },
        ani_native_function {
            "offRouterPageUpdate", "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::offRouterPageUpdate) },
        ani_native_function { "onNavDestinationSwitch",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::onNavDestinationSwitch) },
        ani_native_function { "offNavDestinationSwitch",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::offNavDestinationSwitch) },
        ani_native_function { "onNavDestinationSwitch",
            "C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::onNavDestinationSwitchWithId) },
        ani_native_function { "offNavDestinationSwitch",
            "C{@ohos.arkui.observer.uiObserver.NavDestinationSwitchObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::offNavDestinationSwitchWithId) },
        ani_native_function { "onTabChange", TAB_CHANGE_PARAM, reinterpret_cast<void*>(OHOS::Ace::OnTabChange) },
        ani_native_function { "offTabChange", TAB_CHANGE_PARAM, reinterpret_cast<void*>(OHOS::Ace::OffTabChange) },
        ani_native_function {
            "onTabChange", TAB_CHANGE_PARAM_WITHID, reinterpret_cast<void*>(OHOS::Ace::OnTabChangeWithId) },
        ani_native_function {
            "offTabChange", TAB_CHANGE_PARAM_WITHID, reinterpret_cast<void*>(OHOS::Ace::OffTabChangeWithId) },
        ani_native_function { "onTextChange",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::OnTextChange) },
        ani_native_function { "offTextChange",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::OffTextChange) },
        ani_native_function { "onTextChange",
            "C{@ohos.arkui.observer.uiObserver.ObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OnTextChangeWithId) },
        ani_native_function { "offTextChange",
            "C{@ohos.arkui.observer.uiObserver.ObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OffTextChangeWithId) },
        ani_native_function { "onTabContentUpdate",
            ANI_TABCONTENT_WITH_OPTIONS_CLS, reinterpret_cast<void*>(OHOS::Ace::OnTabContentUpdateWithOptions) },
        ani_native_function { "offTabContentUpdate",
            ANI_TABCONTENT_WITH_OPTIONS_CLS, reinterpret_cast<void*>(OHOS::Ace::OffTabContentUpdateWithOptions) },
        ani_native_function {
            "onTabContentUpdate", ANI_TABCONTENT_CLS, reinterpret_cast<void*>(OHOS::Ace::OnTabContentUpdate) },
        ani_native_function {
            "offTabContentUpdate", ANI_TABCONTENT_CLS, reinterpret_cast<void*>(OHOS::Ace::OffTabContentUpdate) },

        ani_native_function { "onDensityUpdate", nullptr, reinterpret_cast<void*>(OHOS::Ace::OnDensityUpdate) },
        ani_native_function { "offDensityUpdate", nullptr, reinterpret_cast<void*>(OHOS::Ace::OffDensityUpdate) },
        ani_native_function { "onWillDraw", nullptr, reinterpret_cast<void*>(OHOS::Ace::OnWillDraw) },
        ani_native_function { "offWillDraw", nullptr, reinterpret_cast<void*>(OHOS::Ace::OffWillDraw) },
        ani_native_function { "onDidLayout", nullptr, reinterpret_cast<void*>(OHOS::Ace::OnDidLayout) },
        ani_native_function { "offDidLayout", nullptr, reinterpret_cast<void*>(OHOS::Ace::OffDidLayout) },

        ani_native_function { "onWindowSizeLayoutBreakpointChange",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::OnWindowSizeLayoutBreakpointChange) },
        ani_native_function { "offWindowSizeLayoutBreakpointChange",
            "C{std.core.Function1}:", reinterpret_cast<void*>(OHOS::Ace::OffWindowSizeLayoutBreakpointChange) },

        ani_native_function{ "onScrollEvent",
            "C{@ohos.arkui.observer.uiObserver.ObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void *>(OHOS::Ace::OnScrollEventWithId)},
        ani_native_function{ "offScrollEvent",
            "C{@ohos.arkui.observer.uiObserver.ObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void *>(OHOS::Ace::OffScrollEventWithId)},
        ani_native_function{
            "onScrollEvent", "C{std.core.Function1}:", reinterpret_cast<void *>(OHOS::Ace::OnScrollEventType)},
        ani_native_function{
            "offScrollEvent", "C{std.core.Function1}:", reinterpret_cast<void *>(OHOS::Ace::OffScrollEvent)},

        ani_native_function { "onRouterPageSizeChange", "C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OnRouterPageSizeChange) },
        ani_native_function { "offRouterPageSizeChange", "C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OffRouterPageSizeChange) },
        ani_native_function { "onNavDestinationSizeChange", "C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OnNavDestinationSizeChange) },
        ani_native_function { "offNavDestinationSizeChange", "C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OffNavDestinationSizeChange) },
        ani_native_function { "onNavDestinationSizeChangeByUniqueId", "iC{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OnNavDestinationSizeChangeByUniqueId) },
        ani_native_function { "offNavDestinationSizeChangeByUniqueId", "iC{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OffNavDestinationSizeChangeByUniqueId) },

        ani_native_function { "onSwiperContentUpdate", "C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OnSwiperContentUpdate) },
        ani_native_function { "offSwiperContentUpdate", "C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OffSwiperContentUpdate) },
        ani_native_function { "onSwiperContentUpdate",
            "C{@ohos.arkui.observer.uiObserver.ObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OnSwiperContentUpdateWithOptions) },
        ani_native_function { "offSwiperContentUpdate",
            "C{@ohos.arkui.observer.uiObserver.ObserverOptions}C{std.core.Function1}:",
            reinterpret_cast<void*>(OHOS::Ace::OffSwiperContentUpdateWithOptions) },
    };
    if (ANI_OK != env->Class_BindNativeMethods(clsObserver, methodsObserver.data(), methodsObserver.size())) {
        return false;
    }
    return true;
}

ANI_EXPORT ani_status ANI_Constructor(ani_vm* vm, uint32_t* result)
{
    ani_env* env;
    if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
        LOGE("observer-ani Unsupported ANI_VERSION_1");
        return ANI_ERROR;
    }
    if (ANI_ConstructorForAni(env)) {
        *result = ANI_VERSION_1;
        return ANI_OK;
    }
    return ANI_ERROR;
}