OpenCAX/entry/src/main/cpp/NativeEGLOCCT/NativeManager.cpp

428 lines
19 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 <random>
#include <map>
#define COLUMN_MARGIN 10
#define XC_WIDTH 800
#define XC_HEIGHT 600
#define ARG_CNT 2
#ifndef NATIVE_TAG
#define NATIVE_TAG "NativeManager"
#endif
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::xSurfaceTouchEventCallBack;
OH_NativeXComponent_MouseEvent_Callback NativeManager::xMouseEventCallBack;
std::string comId;
std::string nodeId;
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();
}
std::string uuid_v4() {
// 使用当前时间戳和随机数生成UUID
auto timestamp = std::chrono::high_resolution_clock::now().time_since_epoch().count();
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<uint64_t> dis(0, std::numeric_limits<uint64_t>::max());
uint64_t random_part = dis(gen);
// 合并时间戳和随机数并转换为UUID格式
uint64_t full_uuid = (timestamp << 32) | (random_part & 0xFFFFFFFF);
std::stringstream ss;
ss << std::hex << std::uppercase << std::setw(8) << std::setfill('0') << (full_uuid & 0xFFFFFFFF)
<< "-" << std::setw(4) << std::setfill('0') << (full_uuid >> 32 & 0xFFFF)
<< "-4" // UUID版本4中间四位固定为04xx
<< std::setw(3) << std::setfill('0') << (random_part >> 48 & 0x0FFF | 0x4000) // 设置版本号和一些随机位
<< "-" << std::setw(4) << std::setfill('0') << (random_part >> 32 & 0xFFFF)
<< "-" << std::setw(12) << std::setfill('0') << (random_part & 0xFFFFFFFFFFFF);
return ss.str();
}
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");
//主动关闭CPU访问窗口缓冲区数据降低功耗
uint64_t usage = 0;
int32_t ret2 = OH_NativeWindow_NativeWindowHandleOpt((OHNativeWindow*)window, SET_USAGE, usage);
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()) {
HILOG_ERROR(NATIVE_TAG,"uint32_t Size:%{public}dX%{public}d",width_,height_);
renderThreadMap[id]->resizeWindow(width_, height_);
}
}
}
void onEvent(ArkUI_NodeEvent *event) {
auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); // 获取组件事件类型
HILOG_ERROR(NATIVE_TAG,"EventType:%{public}d",eventType);
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");
}
}
void OnMouseEventCB(OH_NativeXComponent* component, void* window) {
auto* pluginManager = NativeManager::GetInstance();
if (!pluginManager || !window) {
return;
}
auto *pluginManger = NativeManager::GetInstance();
pluginManger->OnMouseEvent(component, window);
}
void NativeManager::OnMouseEvent(OH_NativeXComponent *component, void *window) {
OH_NativeXComponent_MouseEvent event;
int32_t ret;
ret=OH_NativeXComponent_GetMouseEvent(component, window, &event);
std::lock_guard<std::mutex> lock(mapMutex);
//通过时间戳判断事件唯一性.保证单一时间戳只触发一次事件
if(event.timestamp==NativeManager::timestamp){
return;
}
NativeManager::timestamp=event.timestamp;
int64_t id = 0;
auto it = renderThreadMap.find(id);
if (it == renderThreadMap.end()) {
HILOG_WARN(NATIVE_TAG, "Render thread not found for rotation.");
return;
}
auto renderThread = it->second;
float curtX,curtY;
HILOG_WARN(NATIVE_TAG, "ALLButton:%{public}d",event.button);
HILOG_WARN(NATIVE_TAG, "ALLAction:%{public}d",event.action);
HILOG_WARN(NATIVE_TAG, "ALLTimestamp:%{public}d",event.timestamp);
//鼠标按下并且事件为鼠标中键
if(event.button==OH_NATIVEXCOMPONENT_LEFT_BUTTON&&event.action==OH_NATIVEXCOMPONENT_MOUSE_PRESS){
//记录按下时候的X.Y坐标
NativeManager::lastMouseX_=event.x;
NativeManager::lastMouseY_=event.y;
NativeManager::isMouseMiddleBtnPressed = true;
HILOG_WARN(NATIVE_TAG, "AtlastMouseX:%{public}d",NativeManager::lastMouseX_);
HILOG_WARN(NATIVE_TAG, "AtlastMouseY:%{public}d",NativeManager::lastMouseY_);
HILOG_WARN(NATIVE_TAG, "AtButton:%{public}d",event.button);
HILOG_WARN(NATIVE_TAG, "AtButtonAction:%{public}d",event.action);
HILOG_WARN(NATIVE_TAG, "AtisMouseMiddleBtnPressed:%{public}d",NativeManager::isMouseMiddleBtnPressed);
}else if(NativeManager::isMouseMiddleBtnPressed&&event.action==OH_NATIVEXCOMPONENT_MOUSE_MOVE){
// 计算鼠标移动距离
float deltaX = curtX - NativeManager::lastMouseX_;
float deltaY = curtY - NativeManager::lastMouseY_;
// 将像素移动量映射到旋转角度
// 这里的系数可以根据需要调整灵敏度
float rotationSpeed = 0.005f;
float angleX = deltaX * rotationSpeed;
float angleY = deltaY * rotationSpeed;
// 通知渲染线程执行旋转
// 由于渲染在线程里,需要通过命令队列发送指令
renderThread->setRotation(angleX, angleY);
// 更新最后的位置
//NativeManager::lastMouseX_ = deltaX;
//NativeManager::lastMouseY_ = deltaY;
HILOG_WARN(NATIVE_TAG, "MoveAngleX:%{public}d",angleX);
HILOG_WARN(NATIVE_TAG, "MoveAngleY:%{public}d",angleY);
HILOG_WARN(NATIVE_TAG, "MoveButton:%{public}d",event.button);
HILOG_WARN(NATIVE_TAG, "MoveButtonAction:%{public}d",event.action);
HILOG_WARN(NATIVE_TAG, "MoveIsMouseMiddleBtnPressed:%{public}d",NativeManager::isMouseMiddleBtnPressed);
}
else if(event.button==OH_NATIVEXCOMPONENT_LEFT_BUTTON&&event.action==OH_NATIVEXCOMPONENT_MOUSE_RELEASE){
//NativeManager::isMouseMiddleBtnPressed = false;
HILOG_WARN(NATIVE_TAG, "ReleaseIsMouseMiddleBtnPressed:%{public}d",NativeManager::isMouseMiddleBtnPressed);
}
}
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() {
xSurfaceTouchEventCallBack.OnSurfaceCreated = OnSurfaceCreatedCB;
xSurfaceTouchEventCallBack.OnSurfaceChanged = OnSurfaceChangedCB;
xSurfaceTouchEventCallBack.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
xMouseEventCallBack.DispatchMouseEvent= OnMouseEventCB;
}
// 创建节点组件
ArkUI_NodeHandle CreateNodeHandle(const std::string &tag) {
nodeId=tag;
// 创建Node也名创建ROW Column等容器
ArkUI_NodeHandle nodeHandel = nodeAPI->createNode(ARKUI_NODE_RELATIVE_CONTAINER);
// 节点默认宽度or高度
ArkUI_NumberValue nodeMarginData[] = {{.u32 = 0}, {.f32 = 0}};
// ArkUI_AttributeItem
// 参数1:指向数值数组
// 参数2:数组元素个数
// 参数3:属性名(可隐藏)
ArkUI_AttributeItem nodeMarginItem = {nodeMarginData, 2};
// 设置Node宽度or高度
nodeAPI->setAttribute(nodeHandel, NODE_MARGIN, &nodeMarginItem);
NativeManager::nodeHandleMap_[tag]=nodeHandel;
// 创建XComponent组件
// 组件类型Item
ArkUI_NumberValue comTypeData[] = {ARKUI_XCOMPONENT_TYPE_SURFACE};
ArkUI_AttributeItem comTypeItem = {comTypeData, 1};
// 组件ID Item
comId=uuid_v4();
ArkUI_AttributeItem comIdItem = {.string = comId.c_str(), .size = 1};
// 组件Surface Size
// 创建组件
ArkUI_NodeHandle xc;
xc = nodeAPI->createNode(ARKUI_NODE_XCOMPONENT);
// 设置XComponent组件属性
nodeAPI->setAttribute(xc, NODE_XCOMPONENT_TYPE, &comTypeItem);
nodeAPI->setAttribute(xc, NODE_XCOMPONENT_ID, &comIdItem);
// 焦点设置
ArkUI_NumberValue focusable[] = {1};
focusable[0].i32 = 1;
ArkUI_AttributeItem focusableItem = {focusable, 1};
nodeAPI->setAttribute(xc, NODE_FOCUSABLE, &focusableItem);
// 节点ID
ArkUI_AttributeItem nodeIdItem = {.string = uuid_v4().c_str(), .size = 1};
nodeAPI->setAttribute(xc, NODE_ID, &nodeIdItem);
auto *nativeXComponent = OH_NativeXComponent_GetNativeXComponent(xc);
if (!nativeXComponent) {
HILOG_ERROR(NATIVE_TAG,"GetNativeXComponent error");
return nodeHandel;
}
// 注册XComponent回调函数
OH_NativeXComponent_RegisterCallback(nativeXComponent, &NativeManager::xSurfaceTouchEventCallBack);
//注册XComponent组件鼠标回调事件
OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &NativeManager::xMouseEventCallBack);
// 组件类型
auto comTypeRet = nodeAPI->getAttribute(xc, NODE_XCOMPONENT_TYPE);
HILOG_INFO(NATIVE_TAG,"XCom type: %{public}d",comTypeRet->value[0].i32);
// 组件ID
auto comIdRet = nodeAPI->getAttribute(xc, NODE_XCOMPONENT_ID);
HILOG_INFO(NATIVE_TAG,"XCom ID: %{public}d",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)) {
HILOG_ERROR(NATIVE_TAG,"CreateNativeNode env or info is null");
return nullptr;
}
//获取传入NodeContent实例
size_t argCnt = 1;
napi_value args[1] = {nullptr};
if (napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr) != napi_ok) {
HILOG_ERROR(NATIVE_TAG,"CreateNativeNode napi_get_cb_info failed");
}
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"));
//下面的代码主要用于创建一个Native侧和arkui侧绑定数据的结构传递传输的操作
//node_data可以理解为一个结构体等等之类的指针
// 生成节点名采用NODE_ID_+UUID
std::string node_data = uuid_v4();
HILOG_INFO(NATIVE_TAG,"NODE_DATA:%{public}d",node_data.c_str());
// 在NodeContent对象上保存自定义数据。
int32_t ret = OH_ArkUI_NodeContent_SetUserData(_nodeContentHandle, new std::string(node_data));
if (ret != ARKUI_ERROR_CODE_NO_ERROR) {
HILOG_ERROR(NATIVE_TAG,"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