380 lines
17 KiB
C++
380 lines
17 KiB
C++
/*
|
||
* 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 "NativeManager.h"
|
||
#include <ace/xcomponent/native_interface_xcomponent.h>
|
||
#include <cstdint>
|
||
#include <cstdio>
|
||
#include <hilog/log.h>
|
||
#include <string>
|
||
#include "arkui/native_node.h"
|
||
#include "arkui/native_node_napi.h"
|
||
#include "arkui/native_interface.h"
|
||
#include "common.h"
|
||
#include <map>
|
||
#define COLUMN_MARGIN 10
|
||
#define XC_WIDTH 800
|
||
#define XC_HEIGHT 600
|
||
#define ARG_CNT 2
|
||
|
||
namespace NativeOpenCAX {
|
||
// [Start plugin_manager_cpp]
|
||
// plugin_manager.cpp
|
||
std::unordered_map<std::string, ArkUI_NodeHandle> NativeManager::nodeHandleMap_;
|
||
std::unordered_map<void *, OH_ArkUI_SurfaceCallback *> NativeManager::callbackMap_;
|
||
std::unordered_map<void *, OH_ArkUI_SurfaceHolder *> NativeManager::surfaceHolderMap_;
|
||
ArkUI_AccessibilityProvider *NativeManager::provider_ = nullptr;
|
||
ArkUI_NativeNodeAPI_1 *nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>(
|
||
OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));
|
||
// [StartExclude plugin_manager_cpp]
|
||
NativeManager NativeManager::pluginManager_;
|
||
OH_NativeXComponent_Callback NativeManager::callback_;
|
||
ArkUI_NodeHandle xc;
|
||
int32_t NativeManager::hasDraw_ = 0;
|
||
int32_t NativeManager::hasChangeColor_ = 0;
|
||
static std::map<int64_t, std::shared_ptr<NativeRenderThread>> renderThreadMap;
|
||
static std::mutex mapMutex;
|
||
|
||
NativeManager::~NativeManager() {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "~NativeManager");
|
||
nativeXComponentMap_.clear();
|
||
int64_t id = 0;
|
||
std::lock_guard<std::mutex> lock(mapMutex);
|
||
if (renderThreadMap.find(id) != renderThreadMap.end()) {
|
||
renderThreadMap[id]->stop();
|
||
renderThreadMap.erase(id);
|
||
}
|
||
|
||
for (auto iter = pluginManagerMap_.begin(); iter != pluginManagerMap_.end(); ++iter) {
|
||
if (iter->second != nullptr) {
|
||
delete iter->second;
|
||
iter->second = nullptr;
|
||
}
|
||
}
|
||
pluginManagerMap_.clear();
|
||
}
|
||
// Surface回调事件
|
||
//void OnSurfaceCreatedNative(OH_ArkUI_SurfaceHolder *holder) {
|
||
// auto window = OH_ArkUI_XComponent_GetNativeWindow(holder); // 获取native window
|
||
// auto eglCore = reinterpret_cast<EGLCore *>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
|
||
// eglCore->EglContextInit(window, 800, 600);
|
||
//}
|
||
//void OnSurfaceChangedNative(OH_ArkUI_SurfaceHolder *holder, uint64_t width, uint64_t height) {
|
||
// EGLCore *render = reinterpret_cast<EGLCore *>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
|
||
// render->UpdateSize(width, height); // 设置绘制区域大小
|
||
// //render->Draw(NativeManager::hasDraw_); // 绘制五角星
|
||
//}
|
||
//void OnSurfaceDestroyedNative(OH_ArkUI_SurfaceHolder *holder) {
|
||
// OH_LOG_Print(LOG_APP, LOG_ERROR, 0xff00, "onBind", "on destroyed");
|
||
// EGLCore *render = reinterpret_cast<EGLCore *>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
|
||
// render->Release(); // 销毁eglSurface相关资源
|
||
//}
|
||
//void OnSurfaceShowNative(OH_ArkUI_SurfaceHolder *holder) {
|
||
// OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "on surface show");
|
||
//}
|
||
//void OnSurfaceHideNative(OH_ArkUI_SurfaceHolder *holder) {
|
||
// OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "on surface hide");
|
||
//}
|
||
//void OnFrameCallbackNative(ArkUI_NodeHandle node, uint64_t timestamp, uint64_t targetTimestamp) {
|
||
// if (!NativeManager::surfaceHolderMap_.count(node)) {
|
||
// return;
|
||
// }
|
||
// static uint64_t count = 0;
|
||
// count++;
|
||
// // 在头文件plugin_manager.h中定义,FRAME_COUNT的值为50
|
||
// if (count % FRAME_COUNT == 0) {
|
||
// OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "OnFrameCallback count = %{public}ld", count);
|
||
// }
|
||
//}
|
||
void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) {
|
||
// [StartExclude plugin_on_surface_created]
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "OnSurfaceCreatedCB");
|
||
int32_t ret;
|
||
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
|
||
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
|
||
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
|
||
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
|
||
return;
|
||
}
|
||
|
||
std::string id(idStr);
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "OnSurfaceCreatedCB id=%{public}s",
|
||
id.c_str());
|
||
// [EndExclude plugin_on_surface_created]
|
||
// 初始化环境与绘制背景
|
||
auto *pluginManger = NativeManager::GetInstance();
|
||
pluginManger->OnSurfaceCreated(component, window);
|
||
}
|
||
void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) {
|
||
// [StartExclude plugin_on_surface_changed]
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "OnSurfaceChangedCB");
|
||
int32_t ret;
|
||
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
|
||
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
|
||
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
|
||
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
|
||
return;
|
||
}
|
||
std::string id(idStr);
|
||
// [EndExclude plugin_on_surface_changed]
|
||
auto *pluginManger = NativeManager::GetInstance();
|
||
// 封装OnSurfaceChanged方法
|
||
pluginManger->OnSurfaceChanged(component, window);
|
||
}
|
||
void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) {
|
||
// [StartExclude plugin_on_surface_destroyed]
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB");
|
||
int32_t ret;
|
||
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
|
||
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
|
||
ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
|
||
if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
|
||
return;
|
||
}
|
||
std::string id(idStr);
|
||
// [EndExclude plugin_on_surface_destroyed]
|
||
auto *pluginManger = NativeManager::GetInstance();
|
||
pluginManger->OnSurfaceDestroyed(component, window);
|
||
}
|
||
//NativeManager回调
|
||
void NativeManager::OnSurfaceCreated(OH_NativeXComponent *component, void *window) {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "PluginManager::OnSurfaceCreated");
|
||
if (!window) {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native",
|
||
"ERROR: window is NULL in OnSurfaceCreated!");
|
||
return;
|
||
}
|
||
OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
|
||
int64_t id = 0;
|
||
std::lock_guard<std::mutex> lock(mapMutex);
|
||
if (renderThreadMap.find(id) == renderThreadMap.end()) {
|
||
auto renderThread = std::make_shared<NativeRenderThread>();
|
||
renderThreadMap[id] = renderThread;
|
||
renderThread->start(reinterpret_cast<OHNativeWindow*>(window));
|
||
}
|
||
}
|
||
void NativeManager::OnSurfaceDestroyed(OH_NativeXComponent *component, void *window) {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "PluginManager::OnSurfaceDestroyed");
|
||
int64_t id = 0;
|
||
{
|
||
std::lock_guard<std::mutex> lock(mapMutex);
|
||
if (renderThreadMap.find(id) != renderThreadMap.end()) {
|
||
renderThreadMap[id]->stop();
|
||
renderThreadMap.erase(id);
|
||
}
|
||
}
|
||
}
|
||
void NativeManager::OnSurfaceChanged(OH_NativeXComponent *component, void *window) {
|
||
OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
|
||
int64_t id = 0;
|
||
{
|
||
std::lock_guard<std::mutex> lock(mapMutex);
|
||
if (renderThreadMap.find(id) != renderThreadMap.end()) {
|
||
renderThreadMap[id]->resizeWindow(width_, height_);
|
||
}
|
||
}
|
||
}
|
||
void onEvent(ArkUI_NodeEvent *event) {
|
||
auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); // 获取组件事件类型
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "on event");
|
||
if (eventType == NODE_TOUCH_EVENT) {
|
||
ArkUI_NodeHandle handle = OH_ArkUI_NodeEvent_GetNodeHandle(event); // 获取触发该事件的组件对象
|
||
auto holder = NativeManager::surfaceHolderMap_[handle];
|
||
EGLCore *render = reinterpret_cast<EGLCore *>(OH_ArkUI_SurfaceHolder_GetUserData(holder));
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "onBind", "on touch");
|
||
}
|
||
}
|
||
static std::string value2String(napi_env env, napi_value value) {
|
||
size_t stringSize = 0;
|
||
napi_get_value_string_utf8(env, value, nullptr, 0, &stringSize);
|
||
std::string valueString;
|
||
valueString.resize(stringSize);
|
||
napi_get_value_string_utf8(env, value, &valueString[0], stringSize + 1, &stringSize);
|
||
return valueString;
|
||
}
|
||
// XComponent回调事件
|
||
NativeManager::NativeManager() {
|
||
callback_.OnSurfaceCreated = OnSurfaceCreatedCB;
|
||
callback_.OnSurfaceChanged = OnSurfaceChangedCB;
|
||
callback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
|
||
}
|
||
// 创建节点组件
|
||
ArkUI_NodeHandle CreateNodeHandle(const std::string &tag) {
|
||
// 创建Node也名创建ROW Column等容器
|
||
ArkUI_NodeHandle nodeHandel = nodeAPI->createNode(ARKUI_NODE_RELATIVE_CONTAINER);
|
||
// 节点默认宽度or高度
|
||
ArkUI_NumberValue nodeSizeData[] = {800, 600};
|
||
ArkUI_NumberValue nodeMarginData[] = {{.u32 = 15}, {.f32 = 15}};
|
||
// ArkUI_AttributeItem
|
||
// 参数1:指向数值数组
|
||
// 参数2:数组元素个数
|
||
// 参数3:属性名(可隐藏)
|
||
ArkUI_AttributeItem nodeSizeItem = {nodeSizeData, 2};
|
||
ArkUI_AttributeItem nodeMarginItem = {nodeMarginData, 2};
|
||
// 设置Node宽度or高度
|
||
nodeAPI->setAttribute(nodeHandel, NODE_SIZE, &nodeSizeItem);
|
||
nodeAPI->setAttribute(nodeHandel, NODE_MARGIN, &nodeMarginItem);
|
||
// 创建XComponent组件
|
||
// 组件类型Item
|
||
ArkUI_NumberValue comTypeData[] = {ARKUI_XCOMPONENT_TYPE_SURFACE};
|
||
ArkUI_AttributeItem comTypeItem = {comTypeData, 1};
|
||
// 组件ID Item
|
||
ArkUI_AttributeItem comIdItem = {.string = tag.c_str(), .size = 1};
|
||
// 组件Surface Size
|
||
ArkUI_NumberValue surfaceSizeData[] = {800, 600};
|
||
ArkUI_AttributeItem surfaceSizeItem = {surfaceSizeData, 2};
|
||
// 创建组件
|
||
xc = nodeAPI->createNode(ARKUI_NODE_XCOMPONENT);
|
||
// 设置XComponent组件属性
|
||
nodeAPI->setAttribute(xc, NODE_XCOMPONENT_TYPE, &comTypeItem);
|
||
nodeAPI->setAttribute(xc, NODE_XCOMPONENT_ID, &comIdItem);
|
||
nodeAPI->setAttribute(xc, NODE_XCOMPONENT_SURFACE_SIZE, &surfaceSizeItem);
|
||
// 焦点设置
|
||
ArkUI_NumberValue focusable[] = {1};
|
||
focusable[0].i32 = 1;
|
||
ArkUI_AttributeItem focusableItem = {focusable, 1};
|
||
nodeAPI->setAttribute(xc, NODE_FOCUSABLE, &focusableItem);
|
||
// 设置组件Size
|
||
nodeAPI->setAttribute(xc, NODE_WIDTH, &surfaceSizeItem);
|
||
nodeAPI->setAttribute(xc, NODE_HEIGHT, &surfaceSizeItem);
|
||
// 节点ID
|
||
ArkUI_AttributeItem nodeIdItem = {.string = "ndkxcomponent", .size = 1};
|
||
nodeAPI->setAttribute(xc, NODE_ID, &nodeIdItem);
|
||
|
||
auto *nativeXComponent = OH_NativeXComponent_GetNativeXComponent(xc);
|
||
if (!nativeXComponent) {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "GetNativeXComponent error");
|
||
return nodeHandel;
|
||
}
|
||
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeManager", "GetNativeXComponent success");
|
||
// 注册XComponent回调函数
|
||
|
||
OH_NativeXComponent_RegisterCallback(nativeXComponent, &NativeManager::callback_);
|
||
// 组件类型
|
||
auto comTypeRet = nodeAPI->getAttribute(xc, NODE_XCOMPONENT_TYPE);
|
||
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeManager", "com type: %{public}d",
|
||
comTypeRet->value[0].i32);
|
||
// 组件ID
|
||
auto comIdRet = nodeAPI->getAttribute(xc, NODE_XCOMPONENT_ID);
|
||
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeManager", "com id: %{public}s", comIdRet->string);
|
||
// 增加组件到节点
|
||
nodeAPI->addChild(nodeHandel, xc);
|
||
return nodeHandel;
|
||
}
|
||
// Native侧创建Node
|
||
napi_value NativeManager::createNativeNode(napi_env env, napi_callback_info info) {
|
||
if ((env == nullptr) || (info == nullptr)) {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "CreateNativeNode env or info is null");
|
||
return nullptr;
|
||
}
|
||
size_t argCnt = 2;
|
||
napi_value args[2] = {nullptr, nullptr};
|
||
if (napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr) != napi_ok) {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "CreateNativeNode napi_get_cb_info failed");
|
||
}
|
||
if (argCnt != ARG_CNT) {
|
||
napi_throw_type_error(env, NULL, "Wrong number of arguments");
|
||
return nullptr;
|
||
}
|
||
ArkUI_NodeContentHandle _nodeContentHandle = nullptr;
|
||
// 获取ArkTS侧创建的NodeContent对象,映射到Native侧的
|
||
OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &_nodeContentHandle);
|
||
// 查询指定的模块接口名
|
||
nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 *>(
|
||
OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));
|
||
// 节点名
|
||
std::string node_id = value2String(env, args[1]);
|
||
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "NativeManager", "CreateNativeNode_Node_ID:", node_id.c_str());
|
||
// 设置用户自定义数据
|
||
int32_t ret = OH_ArkUI_NodeContent_SetUserData(_nodeContentHandle, new std::string(node_id));
|
||
if (ret != ARKUI_ERROR_CODE_NO_ERROR) {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "NativeManager", "setUserData failed error=%{public}d", ret);
|
||
}
|
||
if (nodeAPI != nullptr && nodeAPI->createNode != nullptr && nodeAPI->addChild != nullptr) {
|
||
auto nodeContentEvent = [](ArkUI_NodeContentEvent *event) {
|
||
// 获取Node连接事件的对应Node的Handle
|
||
ArkUI_NodeContentHandle handle = OH_ArkUI_NodeContentEvent_GetNodeContentHandle(event);
|
||
// 获取对应Handle的UserData
|
||
std::string *userDate = reinterpret_cast<std::string *>(OH_ArkUI_NodeContent_GetUserData(handle));
|
||
if (OH_ArkUI_NodeContentEvent_GetEventType(event) == NODE_CONTENT_EVENT_ON_ATTACH_TO_WINDOW) {
|
||
ArkUI_NodeHandle testNode;
|
||
if (userDate) {
|
||
testNode = CreateNodeHandle(*userDate);
|
||
delete userDate;
|
||
userDate = nullptr;
|
||
} else {
|
||
testNode = CreateNodeHandle("noUserData");
|
||
}
|
||
// 向NodeContent中添加子组件
|
||
OH_ArkUI_NodeContent_AddNode(handle, testNode);
|
||
}
|
||
};
|
||
OH_ArkUI_NodeContent_RegisterCallback(_nodeContentHandle, nodeContentEvent);
|
||
}
|
||
return nullptr;
|
||
}
|
||
//设置期望帧率
|
||
napi_value NativeManager::SetFrameRate(napi_env env, napi_callback_info info) {
|
||
size_t argc = 4;
|
||
napi_value args[4] = {nullptr};
|
||
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
|
||
std::string nodeId = value2String(env, args[0]);
|
||
auto node = nodeHandleMap_[nodeId];
|
||
|
||
int32_t min = 0;
|
||
napi_get_value_int32(env, args[FIRST_ARG], &min);
|
||
|
||
int32_t max = 0;
|
||
napi_get_value_int32(env, args[SECOND_ARG], &max);
|
||
|
||
int32_t expected = 0;
|
||
napi_get_value_int32(env, args[THIRD_ARG], &expected);
|
||
OH_NativeXComponent_ExpectedRateRange range = {.min = min, .max = max, .expected = expected};
|
||
OH_ArkUI_XComponent_SetExpectedFrameRateRange(node, range); // 设置期望帧率
|
||
return nullptr;
|
||
}
|
||
napi_value NativeManager::SetNeedSoftKeyboard(napi_env env, napi_callback_info info) {
|
||
size_t argc = 2;
|
||
napi_value args[2] = {nullptr};
|
||
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
|
||
std::string nodeId = value2String(env, args[0]);
|
||
ArkUI_NodeHandle node;
|
||
if (nodeHandleMap_.find(nodeId) == nodeHandleMap_.end()) {
|
||
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "SetNeedSoftKeyboard", "nodeId not exit error");
|
||
return nullptr;
|
||
}
|
||
node = nodeHandleMap_[nodeId];
|
||
|
||
bool needSoftKeyboard = false;
|
||
napi_get_value_bool(env, args[1], &needSoftKeyboard);
|
||
OH_ArkUI_XComponent_SetNeedSoftKeyboard(node, needSoftKeyboard); // 设置是否需要软键盘
|
||
return nullptr;
|
||
}
|
||
napi_value NativeManager::NapiLoadModel(napi_env env, napi_callback_info info) {
|
||
size_t argc = 1;
|
||
napi_value args[1];
|
||
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
|
||
std::string path = value2String(env, args[0]);
|
||
int64_t id = 0;
|
||
{
|
||
std::lock_guard<std::mutex> lock(mapMutex);
|
||
if (renderThreadMap.find(id) != renderThreadMap.end()) {
|
||
renderThreadMap[id]->loadModel(std::string(path));
|
||
}
|
||
}
|
||
return nullptr;
|
||
}
|
||
} // namespace NativeOpenCAX
|