diff --git a/ArkGraphics2D/DisplaySoloist/.gitignore b/ArkGraphics2D/DisplaySoloist/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ea27eaff8c3ecef3e9ebe6399a5f9073cd962a7b
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/.gitignore
@@ -0,0 +1,13 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+/.appanalyzer
+oh-package-lock.json5
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/AppScope/app.json5 b/ArkGraphics2D/DisplaySoloist/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..feca14423759e8b0358a04fa19b0917d01b6da04
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/AppScope/app.json5
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+{
+ "app": {
+ "bundleName": "com.samples.Displaysoloist",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/ArkGraphics2D/DisplaySoloist/AppScope/resources/base/element/string.json b/ArkGraphics2D/DisplaySoloist/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..8f27bbd6363b153e19eb343ee29e37f4a2813c8e
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "DisplaySoloist"
+ }
+ ]
+}
diff --git a/ArkGraphics2D/DisplaySoloist/AppScope/resources/base/media/app_icon.png b/ArkGraphics2D/DisplaySoloist/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3
Binary files /dev/null and b/ArkGraphics2D/DisplaySoloist/AppScope/resources/base/media/app_icon.png differ
diff --git a/ArkGraphics2D/DisplaySoloist/README.md b/ArkGraphics2D/DisplaySoloist/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..71b3f9ce2d82ceadb112876f9503c87acf1d147c
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/README.md
@@ -0,0 +1,83 @@
+# DisplaySoloist分级管控
+
+### 介绍
+
+本示例通过 DisplaySoloist 系列功能,使用 UI 外的线程对 XComponent 的绘制内容,设置开发者所期望的帧率。使用 [NativeDisplaySoloist](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/displaysoloist-native-guidelines) 和 [Drawing](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/graphic-drawing-overview) 来实现图像绘制和显示。
+
+### 效果预览
+
+| XComponent |
+| :------------------------------------------------------: |
+|
|
+
+使用说明
+
+1.进入 XComponent 页面,依次点击“**Start**”,三个方块分别按照 30Hz、60Hz、120Hz 移动;点击“**Stop**”动画停止。
+
+### 工程目录
+
+```
+├──entry/src/main
+│ ├──cpp // C++代码区
+│ │ ├──CMakeLists.txt // CMake配置文件
+│ │ ├──napi_init.cpp // Napi模块注册
+│ │ ├──common
+│ │ │ └──log_common.h // 日志封装定义文件
+│ │ ├──plugin // 生命周期管理模块
+│ │ │ ├──plugin_manager.cpp
+│ │ │ └──plugin_manager.h
+│ │ ├──samples // samples渲染模块
+│ │ │ ├──sample_xcomponent.cpp
+│ │ │ └──sample_xcomponent.h
+│ ├──ets // ets代码区
+│ │ ├──entryability
+│ │ │ ├──EntryAbility.ts // 程序入口类
+| | | └──EntryAbility.ets
+| | ├──interface
+│ │ │ └──XComponentContext.ts // XComponentContext
+│ │ ├──pages // 页面文件
+│ │ | └──Index.ets // XComponent页面
+│ │ ├──utils // 工具类
+| ├──resources // 资源文件目录
+```
+
+### 具体实现
+
+* XComponent:通过在 IDE 中的 Native C++ 工程,在 TS 侧中声明对外接口为 register、unregister 以及 destroy;在 C++ 侧调用 NativeDisplaySoloist 分级管控接口,并在使用 drawing 来绘制期望帧率图像。
+
+ | 接口名 | 描述 |
+ | ------------------------------------------- | --------------------------------------------------- |
+ | OH_DisplaySoloist_Create | 创建一个OH_DisplaySoloist实例 |
+ | OH_DisplaySoloist_Destroy | 销毁一个OH_DisplaySoloist实例 |
+ | OH_DisplaySoloist_Start | 设置每帧回调函数,每次vsync信号到来时启动每帧回调 |
+ | OH_DisplaySoloist_Stop | 停止请求下一次vsync信号,并停止调用回调函数callback |
+ | OH_DisplaySoloist_SetExpectedFrameRateRange | 设置期望帧率范围 |
+
+
+### 相关权限
+
+不涉及。
+
+### 依赖
+
+不涉及。
+
+### 约束与限制
+
+1.本示例仅支持在标准系统上运行;
+
+2.本示例为 Stage 模型,已适配 API version 14 版本 SDK,SDK 版本号(API Version 14 5.0.2.57);
+
+3.本示例需要使用 DevEco Studio 版本号(5.0.5.306)及以上版本才可编译运行。
+
+### 下载
+
+如需单独下载本工程,执行如下命令:
+
+```
+git init
+git config core.sparsecheckout true
+echo code/DocsSample/graphic/DisplaySoloist/ > .git/info/sparse-checkout
+git remote add origin https://gitee.com/openharmony/applications_app_samples.git
+git pull origin master
+```
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/build-profile.json5 b/ArkGraphics2D/DisplaySoloist/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..ee9f710ef18f2965ae1469bdb5d65f02591834f5
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/build-profile.json5
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+{
+ "app": {
+ "signingConfigs": [],
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compatibleSdkVersion": "5.0.2(14)",
+ "targetSdkVersion": "5.0.2(14)",
+ "runtimeOS": "HarmonyOS"
+ }
+ ]
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/code-linter.json5 b/ArkGraphics2D/DisplaySoloist/code-linter.json5
new file mode 100644
index 0000000000000000000000000000000000000000..44d50304643a42f437232b908c9b44c51cea8f60
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/code-linter.json5
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+{
+ "files": [
+ "**/*.ets"
+ ],
+ "ignore": [
+ "**/src/ohosTest/**/*",
+ "**/src/test/**/*",
+ "**/src/mock/**/*",
+ "**/node_modules/**/*",
+ "**/oh_modules/**/*",
+ "**/build/**/*",
+ "**/.preview/**/*"
+ ],
+ "ruleSet": [
+ "plugin:@performance/recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "rules": {
+ }
+}
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/entry/.gitignore b/ArkGraphics2D/DisplaySoloist/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..eadab4e1522296628f32a70228b2c758ecab4759
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/.gitignore
@@ -0,0 +1,7 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
+/oh-package-lock.json5
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/entry/build-profile.json5 b/ArkGraphics2D/DisplaySoloist/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..98128447b577770b257af752b1d5e91c850f64f4
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/build-profile.json5
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ "externalNativeOptions": {
+ "path": "./src/main/cpp/CMakeLists.txt",
+ "arguments": "",
+ "cppFlags": "",
+ }
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": false,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ }
+ }
+ },
+ "nativeLib": {
+ "debugSymbol": {
+ "strip": true,
+ "exclude": []
+ }
+ }
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/entry/hvigorfile.ts b/ArkGraphics2D/DisplaySoloist/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90e5d264bb75363bfb6969f0b832c2f1b9a02a75
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/hvigorfile.ts
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+import { hapTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/ArkGraphics2D/DisplaySoloist/entry/obfuscation-rules.txt b/ArkGraphics2D/DisplaySoloist/entry/obfuscation-rules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/obfuscation-rules.txt
@@ -0,0 +1,23 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
+
+-enable-property-obfuscation
+-enable-toplevel-obfuscation
+-enable-filename-obfuscation
+-enable-export-obfuscation
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/entry/oh-package.json5 b/ArkGraphics2D/DisplaySoloist/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..5b21e253af246edab8b6ef4f10938f4417e8bc25
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/oh-package.json5
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+{
+ "name": "entry",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "libentry.so": "file:./src/main/cpp/types/libentry"
+ }
+}
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0e5253594a889deea00f2e32cdc8cff59ca626a7
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,23 @@
+# the minimum version of CMake.
+cmake_minimum_required(VERSION 3.5.0)
+project(drawing_test)
+
+set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(${NATIVERENDER_ROOT_PATH}
+ ${NATIVERENDER_ROOT_PATH}/include)
+
+add_library(entry SHARED
+ napi_init.cpp
+ samples/sample_xcomponent.cpp
+ plugin/plugin_manager.cpp
+)
+find_library(
+ # Sets the name of the path variable.
+ hilog-lib
+ # Specifies the name of the NDK library that
+ # you want CMake to locate.
+ hilog_ndk.z
+)
+target_link_libraries(entry PUBLIC ${hilog-lib})
+target_link_libraries(entry PUBLIC libace_napi.z.so libnative_drawing.so libnative_window.so libace_ndk.z.so libnative_display_soloist.so)
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/common/log_common.h b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/common/log_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..db232e78289ae5cddb36f10c8e98b389d19b0a47
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/common/log_common.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+#ifndef LOG_COMMON_H
+#define LOG_COMMON_H
+#include
+#define LOG_PRINT_DOMAIN 0xFF00
+#define APP_LOG_DOMAIN 0x0001
+constexpr const char *APP_LOG_TAG = "DisplaySoloistSample";
+#define SAMPLE_LOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
+#define SAMPLE_LOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
+#define SAMPLE_LOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
+#define SAMPLE_LOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
+
+#endif // LOG_COMMON_H
diff --git a/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/napi_init.cpp b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/napi_init.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..43e51b0018c9d42e3e9831a4953e3ef1b3eee3c0
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/napi_init.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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
+#include "napi/native_api.h"
+#include "common/log_common.h"
+#include "plugin/plugin_manager.h"
+
+EXTERN_C_START
+static napi_value Init(napi_env env, napi_value exports)
+{
+ SAMPLE_LOGI("napi init");
+ PluginManager::GetInstance()->Export(env, exports);
+ return exports;
+}
+EXTERN_C_END
+
+static napi_module demoModule = {
+ .nm_version = 1,
+ .nm_flags = 0,
+ .nm_filename = nullptr,
+ .nm_register_func = Init,
+ .nm_modname = "entry",
+ .nm_priv = ((void *)0),
+ .reserved = {0},
+};
+
+extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
diff --git a/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b71c471ab9250ce025eba9f2f0a561960adb6c58
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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
+#include
+#include
+#include
+#include "common/log_common.h"
+#include "plugin_manager.h"
+
+PluginManager *PluginManager::GetInstance()
+{
+ static PluginManager pluginManager;
+ return &pluginManager;
+}
+
+PluginManager::~PluginManager()
+{
+ SAMPLE_LOGI("~PluginManager");
+ for (auto iter = nativeXComponentMap_.begin(); iter != nativeXComponentMap_.end(); ++iter) {
+ if (iter->second != nullptr) {
+ delete iter->second;
+ iter->second = nullptr;
+ }
+ }
+ nativeXComponentMap_.clear();
+
+ for (auto iter = pluginRenderMap_.begin(); iter != pluginRenderMap_.end(); ++iter) {
+ if (iter->second != nullptr) {
+ delete iter->second;
+ iter->second = nullptr;
+ }
+ }
+ pluginRenderMap_.clear();
+}
+
+// [Start display_soloist_export_api]
+void PluginManager::Export(napi_env env, napi_value exports)
+{
+ nativeXComponentMap_.clear();
+ pluginRenderMap_.clear();
+ if ((env == nullptr) || (exports == nullptr)) {
+ SAMPLE_LOGE("Export: env or exports is null");
+ return;
+ }
+
+ napi_value exportInstance = nullptr;
+ if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
+ SAMPLE_LOGE("Export: napi_get_named_property fail");
+ return;
+ }
+
+ OH_NativeXComponent *nativeXComponent = nullptr;
+ if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) {
+ SAMPLE_LOGE("Export: napi_unwrap fail");
+ return;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("Export: OH_NativeXComponent_GetXComponentId fail");
+ return;
+ }
+
+ std::string id(idStr);
+ auto context = PluginManager::GetInstance();
+ if ((context != nullptr) && (nativeXComponent != nullptr)) {
+ context->SetNativeXComponent(id, nativeXComponent);
+ auto render = context->GetRender(id);
+ if (render != nullptr) {
+ render->RegisterCallback(nativeXComponent);
+ render->Export(env, exports);
+ } else {
+ SAMPLE_LOGE("render is nullptr");
+ }
+ }
+}
+// [End display_soloist_export_api]
+
+void PluginManager::SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent)
+{
+ SAMPLE_LOGI("set native xComponent, ID = %{public}s.", id.c_str());
+ if (nativeXComponent == nullptr) {
+ SAMPLE_LOGE("xcomponent null");
+ return;
+ }
+
+ if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) {
+ nativeXComponentMap_[id] = nativeXComponent;
+ return;
+ }
+
+ if (nativeXComponentMap_[id] != nativeXComponent) {
+ OH_NativeXComponent *tmp = nativeXComponentMap_[id];
+ delete tmp;
+ tmp = nullptr;
+ nativeXComponentMap_[id] = nativeXComponent;
+ }
+}
+
+SampleXComponent *PluginManager::GetRender(std::string &id)
+{
+ if (pluginRenderMap_.find(id) == pluginRenderMap_.end()) {
+ SampleXComponent *instance = SampleXComponent::GetInstance(id);
+ pluginRenderMap_[id] = instance;
+ return instance;
+ }
+ return pluginRenderMap_[id];
+}
diff --git a/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c323bb130ada5130718aea50a50c6c5789e3904
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/plugin/plugin_manager.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+#ifndef PLUGIN_MANAGER_H
+#define PLUGIN_MANAGER_H
+
+#include
+#include
+#include
+#include
+#include
+#include "samples/sample_xcomponent.h"
+
+// [Start display_soloist_create_plugin_manager]
+class PluginManager {
+public:
+ ~PluginManager();
+
+ static PluginManager *GetInstance();
+
+ void SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent);
+ SampleXComponent *GetRender(std::string &id);
+ void Export(napi_env env, napi_value exports);
+
+private:
+ std::unordered_map nativeXComponentMap_;
+ std::unordered_map pluginRenderMap_;
+};
+// [End display_soloist_create_plugin_manager]
+#endif // PLUGIN_MANAGER_H
diff --git a/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..464f21b74af20dcae486375cd16e4c928a9bd56f
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.cpp
@@ -0,0 +1,473 @@
+/*
+ * 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
+#include
+#include
+#include
+#include "common/log_common.h"
+#include "sample_xcomponent.h"
+
+static std::unordered_map g_displaySync;
+
+static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window)
+{
+ SAMPLE_LOGI("OnSurfaceCreatedCB");
+ if ((component == nullptr) || (window == nullptr)) {
+ SAMPLE_LOGE("OnSurfaceCreatedCB: component or window is null");
+ return;
+ }
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("OnSurfaceCreatedCB: Unable to get XComponent id");
+ return;
+ }
+ std::string id(idStr);
+ auto render = SampleXComponent::GetInstance(id);
+ OHNativeWindow *nativeWindow = static_cast(window);
+ render->SetNativeWindow(nativeWindow);
+
+ uint64_t width;
+ uint64_t height;
+ int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
+ if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
+ render->SetHeight(height);
+ render->SetWidth(width);
+ SAMPLE_LOGI("xComponent width = %{public}llu, height = %{public}llu", width, height);
+ }
+}
+
+static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window)
+{
+ SAMPLE_LOGI("OnSurfaceDestroyedCB");
+ if ((component == nullptr) || (window == nullptr)) {
+ SAMPLE_LOGE("OnSurfaceDestroyedCB: component or window is null");
+ return;
+ }
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("OnSurfaceDestroyedCB: Unable to get XComponent id");
+ return;
+ }
+ std::string id(idStr);
+ SampleXComponent::Release(id);
+}
+
+// [Start display_soloist_frame_rate_setting_and_subscription_function_registration]
+static void TestCallback(long long timestamp, long long targetTimestamp, void *data)
+{
+ SAMPLE_LOGI("test callback timestamp = %{public}llu, ", timestamp);
+ OH_NativeXComponent *component = nullptr;
+ component = static_cast(data);
+ if (component == nullptr) {
+ SAMPLE_LOGE("TestCallback: component is null");
+ return;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("TestCallback: Unable to get XComponent id");
+ return;
+ }
+
+ std::string id(idStr);
+ auto render = SampleXComponent::GetInstance(id);
+ OHNativeWindow *nativeWindow = render->GetNativeWindow();
+ uint64_t width;
+ uint64_t height;
+
+ int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, nativeWindow, &width, &height);
+ if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
+ render->Prepare();
+ render->Create();
+ if (id == "xcomponentId_30") {
+ int offset = 16;
+ render->ConstructPath(offset, offset, render->defaultOffsetY);
+ }
+ if (id == "xcomponentId_120") {
+ int offset = 4;
+ render->ConstructPath(offset, offset, render->defaultOffsetY);
+ }
+ render->SetPenAndBrush();
+ render->DrawPath();
+ render->DisPlay();
+ render->Destroy();
+ }
+}
+// [End display_soloist_frame_rate_setting_and_subscription_function_registration]
+
+static std::unordered_map g_instance;
+
+void SampleXComponent::SetWidth(uint64_t width) { width_ = width; }
+
+void SampleXComponent::SetHeight(uint64_t height) { height_ = height; }
+
+void SampleXComponent::SetNativeWindow(OHNativeWindow *nativeWindow) { nativeWindow_ = nativeWindow; }
+
+OHNativeWindow *SampleXComponent::GetNativeWindow() { return nativeWindow_; }
+
+void SampleXComponent::Prepare()
+{
+ if (nativeWindow_ == nullptr) {
+ SAMPLE_LOGE("nativeWindow_ is nullptr");
+ return;
+ }
+ int ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_);
+ SAMPLE_LOGI("request buffer ret = %{public}d", ret);
+ bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
+ mappedAddr_ = static_cast(
+ mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0));
+ if (mappedAddr_ == MAP_FAILED) {
+ SAMPLE_LOGE("mmap failed");
+ }
+}
+
+void SampleXComponent::DisPlay()
+{
+ void *bitmapAddr = OH_Drawing_BitmapGetPixels(cBitmap_);
+ uint32_t *value = static_cast(bitmapAddr);
+
+ uint32_t *pixel = static_cast(mappedAddr_);
+ if (pixel == nullptr) {
+ SAMPLE_LOGE("pixel is null");
+ return;
+ }
+ if (value == nullptr) {
+ SAMPLE_LOGE("value is null");
+ return;
+ }
+ for (uint32_t x = 0; x < width_; x++) {
+ for (uint32_t y = 0; y < height_; y++) {
+ *pixel++ = *value++;
+ }
+ }
+ Region region{nullptr, 0};
+ OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region);
+ int result = munmap(mappedAddr_, bufferHandle_->size);
+ if (result == -1) {
+ SAMPLE_LOGE("munmap failed!");
+ }
+}
+
+void SampleXComponent::Create()
+{
+ uint32_t width = static_cast(bufferHandle_->stride / 4);
+ cBitmap_ = OH_Drawing_BitmapCreate();
+ OH_Drawing_BitmapFormat cFormat{COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
+ OH_Drawing_BitmapBuild(cBitmap_, width, height_, &cFormat);
+
+ cCanvas_ = OH_Drawing_CanvasCreate();
+ OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
+ OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
+}
+
+void SampleXComponent::ConstructPath(int x, int y, int offsetY)
+{
+ float offsetOfAy = 100.0;
+ float offsetOfCy = 200.0;
+
+ aY = offsetOfAy + offsetY;
+ cY = offsetOfCy + offsetY;
+
+ if (desc) {
+ float offset = 1.0;
+ aX -= x * offset;
+ bX -= x * offset;
+ } else {
+ float offset = 1.0;
+ aX += x * offset;
+ bX += x * offset;
+ }
+
+ if (bX >= width_) {
+ desc = true;
+ }
+
+ if (aX <= 0) {
+ desc = false;
+ }
+
+ float bY = aY;
+ float cX = bX;
+ float dX = aX;
+ float dY = cY;
+
+ cPath_ = OH_Drawing_PathCreate();
+ OH_Drawing_PathMoveTo(cPath_, aX, aY);
+ OH_Drawing_PathLineTo(cPath_, bX, bY);
+ OH_Drawing_PathLineTo(cPath_, cX, cY);
+ OH_Drawing_PathLineTo(cPath_, dX, dY);
+
+ OH_Drawing_PathClose(cPath_);
+}
+
+void SampleXComponent::SetPenAndBrush()
+{
+ constexpr float penWidth = 10.0f; // pen width 10
+ cPen_ = OH_Drawing_PenCreate();
+ OH_Drawing_PenSetAntiAlias(cPen_, true);
+ OH_Drawing_PenSetColor(cPen_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
+ OH_Drawing_PenSetWidth(cPen_, penWidth);
+ OH_Drawing_PenSetJoin(cPen_, LINE_ROUND_JOIN);
+ OH_Drawing_CanvasAttachPen(cCanvas_, cPen_);
+
+ cBrush_ = OH_Drawing_BrushCreate();
+ OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00));
+
+ OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_);
+}
+
+void SampleXComponent::DrawPath()
+{
+ OH_Drawing_CanvasDrawPath(cCanvas_, cPath_);
+}
+
+void ExecuteDisplaySoloist(std::string id, DisplaySoloist_ExpectedRateRange range, bool useExclusiveThread,
+ OH_NativeXComponent *nativeXComponent)
+{
+ OH_DisplaySoloist *nativeDisplaySoloist = nullptr;
+ if (g_displaySync.find(id) == g_displaySync.end()) {
+ g_displaySync[id] = OH_DisplaySoloist_Create(useExclusiveThread);
+ }
+ nativeDisplaySoloist = g_displaySync[id];
+ OH_DisplaySoloist_SetExpectedFrameRateRange(nativeDisplaySoloist, &range);
+ OH_DisplaySoloist_Start(nativeDisplaySoloist, TestCallback, nativeXComponent);
+}
+
+// [Start display_soloist_napi_register]
+napi_value SampleXComponent::NapiRegister(napi_env env, napi_callback_info info)
+{
+ SAMPLE_LOGI("NapiRegister");
+ if ((env == nullptr) || (info == nullptr)) {
+ SAMPLE_LOGE("NapiRegister: env or info is null");
+ return nullptr;
+ }
+
+ napi_value thisArg;
+ if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
+ SAMPLE_LOGE("NapiRegister: napi_get_cb_info fail");
+ return nullptr;
+ }
+
+ napi_value exportInstance;
+ if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
+ SAMPLE_LOGE("NapiRegister: napi_get_named_property fail");
+ return nullptr;
+ }
+
+ OH_NativeXComponent *nativeXComponent = nullptr;
+ if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) {
+ SAMPLE_LOGE("NapiRegister: napi_unwrap fail");
+ return nullptr;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("NapiRegister: Unable to get XComponent id");
+ return nullptr;
+ }
+ SAMPLE_LOGI("RegisterID = %{public}s", idStr);
+ std::string id(idStr);
+ SampleXComponent *render = SampleXComponent().GetInstance(id);
+ if (render != nullptr) {
+ DisplaySoloist_ExpectedRateRange range;
+ bool useExclusiveThread = false;
+ if (id == "xcomponentId30") {
+ range = {30, 120, 30};
+ }
+
+ if (id == "xcomponentId120") {
+ range = {30, 120, 120};
+ }
+ ExecuteDisplaySoloist(id, range, useExclusiveThread, nativeXComponent);
+ }
+ return nullptr;
+}
+// [End display_soloist_napi_register]
+
+napi_value SampleXComponent::NapiUnregister(napi_env env, napi_callback_info info)
+{
+ SAMPLE_LOGI("NapiUnregister");
+ if ((env == nullptr) || (info == nullptr)) {
+ SAMPLE_LOGE("NapiUnregister: env or info is null");
+ return nullptr;
+ }
+
+ napi_value thisArg;
+ if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
+ SAMPLE_LOGE("NapiUnregister: napi_get_cb_info fail");
+ return nullptr;
+ }
+
+ napi_value exportInstance;
+ if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
+ SAMPLE_LOGE("NapiUnregister: napi_get_named_property fail");
+ return nullptr;
+ }
+
+ OH_NativeXComponent *nativeXComponent = nullptr;
+ if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) {
+ SAMPLE_LOGE("NapiUnregister: napi_unwrap fail");
+ return nullptr;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("NapiUnregister: Unable to get XComponent id");
+ return nullptr;
+ }
+ SAMPLE_LOGI("ID = %{public}s", idStr);
+ std::string id(idStr);
+ SampleXComponent *render = SampleXComponent().GetInstance(id);
+ if (render != nullptr) {
+ OH_DisplaySoloist_Stop(g_displaySync[id]);
+ SAMPLE_LOGI("NapiUnregister executed");
+ } else {
+ SAMPLE_LOGE("render is nullptr");
+ }
+ return nullptr;
+}
+
+napi_value SampleXComponent::NapiDestroy(napi_env env, napi_callback_info info)
+{
+ SAMPLE_LOGI("NapiUnregister");
+ if ((env == nullptr) || (info == nullptr)) {
+ SAMPLE_LOGE("NapiDestroy: env or info is null");
+ return nullptr;
+ }
+
+ napi_value thisArg;
+ if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) {
+ SAMPLE_LOGE("NapiDestroy: napi_get_cb_info fail");
+ return nullptr;
+ }
+
+ napi_value exportInstance;
+ if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
+ SAMPLE_LOGE("NapiDestroy: napi_get_named_property fail");
+ return nullptr;
+ }
+
+ OH_NativeXComponent *nativeXComponent = nullptr;
+ if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) {
+ SAMPLE_LOGE("NapiDestroy: napi_unwrap fail");
+ return nullptr;
+ }
+
+ char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
+ uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
+ if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
+ SAMPLE_LOGE("NapiDestroy: Unable to get XComponent id");
+ return nullptr;
+ }
+ SAMPLE_LOGI("ID = %{public}s", idStr);
+ std::string id(idStr);
+ SampleXComponent *render = SampleXComponent().GetInstance(id);
+ if (render != nullptr) {
+ OH_DisplaySoloist_Destroy(g_displaySync[id]);
+ g_displaySync.erase(id);
+ SAMPLE_LOGI("NapiUnregister executed");
+ } else {
+ SAMPLE_LOGE("render is nullptr");
+ }
+ return nullptr;
+}
+
+SampleXComponent::~SampleXComponent()
+{
+ OH_Drawing_BrushDestroy(cBrush_);
+ cBrush_ = nullptr;
+ OH_Drawing_PenDestroy(cPen_);
+ cPen_ = nullptr;
+ OH_Drawing_PathDestroy(cPath_);
+ cPath_ = nullptr;
+ OH_Drawing_CanvasDestroy(cCanvas_);
+ cCanvas_ = nullptr;
+ OH_Drawing_BitmapDestroy(cBitmap_);
+ cBitmap_ = nullptr;
+
+ buffer_ = nullptr;
+ bufferHandle_ = nullptr;
+ nativeWindow_ = nullptr;
+ mappedAddr_ = nullptr;
+}
+
+void SampleXComponent::Destroy()
+{
+ OH_Drawing_BrushDestroy(cBrush_);
+ cBrush_ = nullptr;
+ OH_Drawing_PenDestroy(cPen_);
+ cPen_ = nullptr;
+ OH_Drawing_PathDestroy(cPath_);
+ cPath_ = nullptr;
+ OH_Drawing_CanvasDestroy(cCanvas_);
+ cCanvas_ = nullptr;
+ OH_Drawing_BitmapDestroy(cBitmap_);
+ cBitmap_ = nullptr;
+}
+
+void SampleXComponent::Release(std::string &id)
+{
+ SampleXComponent *render = SampleXComponent::GetInstance(id);
+ if (render != nullptr) {
+ delete render;
+ render = nullptr;
+ g_instance.erase(g_instance.find(id));
+ }
+}
+
+void SampleXComponent::Export(napi_env env, napi_value exports)
+{
+ if ((env == nullptr) || (exports == nullptr)) {
+ SAMPLE_LOGE("Export: env or exports is null");
+ return;
+ }
+ napi_property_descriptor desc[] = {
+ {"register", nullptr, SampleXComponent::NapiRegister, nullptr, nullptr, nullptr, napi_default, nullptr},
+ {"unregister", nullptr, SampleXComponent::NapiUnregister, nullptr, nullptr, nullptr, napi_default, nullptr},
+ {"destroy", nullptr, SampleXComponent::NapiDestroy, nullptr, nullptr, nullptr, napi_default, nullptr}};
+
+ napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
+ if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
+ SAMPLE_LOGE("Export: napi_define_properties failed");
+ }
+}
+
+void SampleXComponent::RegisterCallback(OH_NativeXComponent *nativeXComponent)
+{
+ SAMPLE_LOGI("register callback");
+ renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB;
+ renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
+ // Callback must be initialized
+ renderCallback_.DispatchTouchEvent = nullptr;
+ renderCallback_.OnSurfaceChanged = nullptr;
+ OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_);
+}
+
+SampleXComponent *SampleXComponent::GetInstance(std::string &id)
+{
+ if (g_instance.find(id) == g_instance.end()) {
+ SampleXComponent *render = new SampleXComponent(id);
+ g_instance[id] = render;
+ return render;
+ } else {
+ return g_instance[id];
+ }
+}
\ No newline at end of file
diff --git a/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h
new file mode 100644
index 0000000000000000000000000000000000000000..9ced152ef6a1c5ad7d19ed8ac8b41d123042e26f
--- /dev/null
+++ b/ArkGraphics2D/DisplaySoloist/entry/src/main/cpp/samples/sample_xcomponent.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+#ifndef SAMPLE_XCOMPONENT_H
+#define SAMPLE_XCOMPONENT_H
+// [Start display_soloist_import_module]
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include