Description:可变帧率提供分级管控NDK接口

Feature or Bugfix:Feature

Signed-off-by: xuweinan <xuweinan5@huawei.com>
This commit is contained in:
xuweinan 2024-05-30 14:34:23 +08:00
parent 85d864e660
commit 472539db0f
52 changed files with 2091 additions and 0 deletions

View File

@ -661,6 +661,11 @@ Note:If the text contains special characters, please escape them according to th
<filteritem type="filepath" name="code/BasicFeature/DeviceManagement/Sensor/Capi/entry/src/main/resources/base/media/compass.png" desc="Provided by code/BasicFeature/DeviceManagement/Sensor"/>
<filteritem type="filepath" name=" code/BasicFeature/DeviceManagement/Vibrator/CustomHaptic/entry/src/main/resources/base/media/select.png" desc="Provided by code/BasicFeature/DeviceManagement/Vibrator"/>
<filteritem type="filepath" name="code/BasicFeature/Graphics/DisplaySync/screenshots/device/animator.jpg" desc="Provided by code/BasicFeature/Graphics/DisplaySync"/>
<filteritem type="filepath" name="code/BasicFeature/Graphics/DisplaySoloist/screenshots/device/displaySoloist.jpg" desc="Provided by code/BasicFeature/Graphics/DisplaySoloist"/>
<filteritem type="filepath" name="code/BasicFeature/Graphics/DisplaySoloist/entry/src/ohosTest/resources/base/media/icon.png" desc="Provided by code/BasicFeature/Graphics/DisplaySoloist"/>
<filteritem type="filepath" name="code/BasicFeature/Graphics/DisplaySoloist/entry/src/main/resources/base/media/startIcon.png" desc="Provided by code/BasicFeature/Graphics/DisplaySoloist"/>
<filteritem type="filepath" name="code/BasicFeature/Graphics/DisplaySoloist/AppScope/resources/base/media/app_icon.png" desc="Provided by code/BasicFeature/Graphics/DisplaySoloist"/>
<filteritem type="filepath" name="code/BasicFeature/Graphics/DisplaySoloist/entry/src/main/resources/base/media/icon.png" desc="Provided by code/BasicFeature/Graphics/DisplaySoloist"/>
<filteritem type="filepath" name="code/Solutions/Social/GrapeSquare/feature/authorizedControl/src/main/resources/base/media/photo120.jpg" desc="Provided by code/Solutions/Social/GrapeSquare"/>
<filteritem type="filepath" name="code/BasicFeature/WindowManagement/WindowManage/screenshots/devices/getPropertiesOfSystemBar.jpg" desc="Provided by code/BasicFeature/WindowManagement/WindowManage"/>
<filteritem type="filepath" name="code/BasicFeature/WindowManagement/WindowManage/screenshots/devices/mainWindow.jpg" desc="Provided by code/BasicFeature/WindowManagement/WindowManage"/>

View File

@ -0,0 +1,11 @@
/node_modules
/oh_modules
/local.properties
/.idea
**/build
/.hvigor
.cxx
/.clangd
/.clang-format
/.clang-tidy
**/.test

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2024 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"
}
}

View File

@ -0,0 +1,8 @@
{
"string": [
{
"name": "app_name",
"value": "DisplaySoloist"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,82 @@
# DisplaySoloist分级管控
### 介绍
本示例通过DisplaySoloist分级管控功能使用UI以外的线程对XComponent的绘制内容设置开发者所期望的帧率。
### 效果预览
| XComponent |
|---------------------------------------------------------------|
| <img src="./screenshots/device/displaySoloist.jpg" width="100%"/> |
使用说明
1.进入XComponent页面依次点击“**Start**”三个方块分别按照30Hz、60Hz、120Hz移动点击“**Stop**”动画停止;
### 工程目录
```
├──entry/src/main
│ ├──cpp // C++代码区
│ │ ├──CMakeLists.txt // CMake配置文件
│ │ ├──hello.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++ 工程在c++代码中定义对外接口为register、unregister以及destroy并调用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.本示例仅支持在标准系统上运行支持设备RK3568。
2.本示例为Stage模型已适配API version 12版本SDKSDK版本号(API Version 12 5.0.0.26),镜像版本号(5.0.0.26)。
3.本示例需要使用DevEco Studio 版本号(4.1.3.500)及以上版本才可编译运行。
### 下载
如需单独下载本工程,执行如下命令:
```
git init
git config core.sparsecheckout true
echo code/SystemFeature/Graphics/DisplaySoloist/ > .git/info/sparse-checkout
git remote add origin https://gitee.com/openharmony/applications_app_samples.git
git pull origin master
```

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2024 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": [
{
"compileSdkVersion": 12,
"compatibleSdkVersion": 12,
"name": "default",
"signingConfig": "default",
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}

View File

@ -0,0 +1,6 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2024 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": "",
"abiFilters": ["arm64-v8a", "armeabi-v7a", "x86_64"]
}
},
"targets": [
{
"name": "default",
"runtimeOS": "OpenHarmony"
},
{
"name": "ohosTest",
}
]
}

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 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.
*/
export { hapTasks } from '@ohos/hvigor-ohos-plugin';

View File

@ -0,0 +1,12 @@
{
"license": "",
"devDependencies": {},
"author": "",
"name": "entry",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {
"libentry.so": "file:./src/main/cpp/types/libentry"
}
}

View File

@ -0,0 +1,23 @@
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(drawing_test)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
add_library(entry SHARED
hello.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)

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 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 <hilog/log.h>
#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

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 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 <hilog/log.h>
#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);
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2024 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 <ace/xcomponent/native_interface_xcomponent.h>
#include <cstdint>
#include <hilog/log.h>
#include <string>
#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();
}
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<void **>(&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");
}
}
}
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];
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 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 <ace/xcomponent/native_interface_xcomponent.h>
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <string>
#include <unordered_map>
#include "samples/sample_xcomponent.h"
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<std::string, OH_NativeXComponent *> nativeXComponentMap_;
std::unordered_map<std::string, SampleXComponent *> pluginRenderMap_;
};
#endif // PLUGIN_MANAGER_H

View File

@ -0,0 +1,498 @@
/*
* Copyright (c) 2024 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 <bits/alltypes.h>
#include <native_drawing/drawing_text_typography.h>
#include <native_display_soloist/native_display_soloist.h>
#include <unistd.h>
#include "common/log_common.h"
#include "sample_xcomponent.h"
static std::unordered_map<std::string, OH_DisplaySoloist *> 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<OHNativeWindow *>(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);
}
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<OH_NativeXComponent *>(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();
// 每帧移动8像素
render->ConstructPath(8, 8, render->defaultOffsetY);
render->SetPenAndBrush();
render->DrawPath();
render->DisPlay();
render->Destroy();
}
}
static std::unordered_map<std::string, SampleXComponent *> 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;
}
// 这里的nativeWindow是从上一步骤中的回调函数中获得的
// 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
int ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_);
SAMPLE_LOGI("request buffer ret = %{public}d", ret);
// 通过 OH_NativeWindow_GetBufferHandleFromNative 获取 buffer 的 handle
bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
// 使用系统mmap接口拿到bufferHandle的内存虚拟地址
mappedAddr_ = static_cast<uint32_t *>(
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<uint32_t *>(bitmapAddr);
uint32_t *pixel = static_cast<uint32_t *>(mappedAddr_); // 使用mmap获取到的地址来访问内存
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中的Rect为nullptr,或者rectNumber为0则认为OHNativeWindowBuffer全部有内容更改。
Region region{nullptr, 0};
// 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
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<uint32_t>(bufferHandle_->stride / 4);
// 创建一个bitmap对象
cBitmap_ = OH_Drawing_BitmapCreate();
// 定义bitmap的像素格式
OH_Drawing_BitmapFormat cFormat{COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
// 构造对应格式的bitmap
OH_Drawing_BitmapBuild(cBitmap_, width, height_, &cFormat);
// 创建一个canvas对象
cCanvas_ = OH_Drawing_CanvasCreate();
// 将画布与bitmap绑定画布画的内容会输出到绑定的bitmap内存中
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)
{
// 初始的矩形A点纵坐标为100.0
aY = 100.0 + offsetY;
// 初始的矩形C点纵坐标为200.0
cY = 200.0 + offsetY;
if (desc) {
aX -= x * 1.0;
bX -= x * 1.0;
} else {
aX += x * 1.0;
bX += x * 1.0;
}
if (bX >= width_) {
desc = true;
}
if (aX <= 0) {
desc = false;
}
float bY = aY;
float cX = bX;
float dX = aX;
float dY = cY;
// 创建一个path对象然后使用接口连接成一个矩形形状
cPath_ = OH_Drawing_PathCreate();
// 指定path的起始位置
OH_Drawing_PathMoveTo(cPath_, aX, aY);
// 用直线连接到目标点
OH_Drawing_PathLineTo(cPath_, bX, bY);
OH_Drawing_PathLineTo(cPath_, cX, cY);
OH_Drawing_PathLineTo(cPath_, dX, dY);
// 闭合形状path绘制完毕
OH_Drawing_PathClose(cPath_);
}
void SampleXComponent::SetPenAndBrush()
{
constexpr float penWidth = 10.0f; // pen width 10
// 创建一个画笔Pen对象Pen对象用于形状的边框线绘制
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);
// 将Pen画笔设置到canvas中
OH_Drawing_CanvasAttachPen(cCanvas_, cPen_);
// 创建一个画刷Brush对象Brush对象用于形状的填充
cBrush_ = OH_Drawing_BrushCreate();
OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00));
// 将Brush画刷设置到canvas中
OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_);
}
void SampleXComponent::DrawPath()
{
// 在画布上画path的形状矩形的边框样式为pen设置颜色填充为Brush设置
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);
}
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<void **>(&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") {
// 第一个按照期望30HZ的帧率来移动
range = {30, 120, 30};
}
if (id == "xcomponentId60") {
// 第二个按照期望60HZ的帧率来移动
range = {30, 120, 60};
useExclusiveThread = true;
}
if (id == "xcomponentId120") {
// 第三个按照期望120HZ的帧率来移动
range = {30, 120, 120};
}
ExecuteDisplaySoloist(id, range, useExclusiveThread, nativeXComponent);
}
return nullptr;
}
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<void **>(&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<void **>(&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;
// 销毁canvas对象
OH_Drawing_CanvasDestroy(cCanvas_);
cCanvas_ = nullptr;
// 销毁bitmap对象
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;
// 销毁canvas对象
OH_Drawing_CanvasDestroy(cCanvas_);
cCanvas_ = nullptr;
// 销毁bitmap对象
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];
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2024 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
#include <ace/xcomponent/native_interface_xcomponent.h>
#include <arpa/nameser.h>
#include <bits/alltypes.h>
#include <native_window/external_window.h>
#include <native_drawing/drawing_bitmap.h>
#include <native_drawing/drawing_color.h>
#include <native_drawing/drawing_canvas.h>
#include <native_drawing/drawing_pen.h>
#include <native_drawing/drawing_brush.h>
#include <native_drawing/drawing_path.h>
#include <cstdint>
#include <map>
#include <sys/mman.h>
#include <string>
#include "napi/native_api.h"
class SampleXComponent {
public:
SampleXComponent() = default;
~SampleXComponent();
explicit SampleXComponent(std::string id) : id_(id) {}
static napi_value NapiRegister(napi_env env, napi_callback_info info);
static napi_value NapiUnregister(napi_env env, napi_callback_info info);
static napi_value NapiDestroy(napi_env env, napi_callback_info info);
static void Release(std::string &id);
void DrawPath();
void SetWidth(uint64_t width);
void SetHeight(uint64_t height);
void SetNativeWindow(OHNativeWindow *nativeWindow);
OHNativeWindow* GetNativeWindow();
void Prepare();
void Create();
void DisPlay();
void ConstructPath(int x, int y, int offsetY);
void SetPenAndBrush();
void Export(napi_env env, napi_value exports);
void RegisterCallback(OH_NativeXComponent *nativeXComponent);
void Destroy();
static SampleXComponent *GetInstance(std::string &id);
std::string id_;
int defaultOffsetY = 100;
private:
OH_NativeXComponent_Callback renderCallback_;
uint64_t width_ = 0;
uint64_t height_ = 0;
float aX = 0.0;
float aY = 0.0;
float bX = 80.0;
float cY = 0.0;
bool desc = false;
OH_Drawing_Bitmap *cBitmap_ = nullptr;
OH_Drawing_Canvas *cCanvas_ = nullptr;
OH_Drawing_Path *cPath_ = nullptr;
OH_Drawing_Brush *cBrush_ = nullptr;
OH_Drawing_Pen *cPen_ = nullptr;
OHNativeWindow *nativeWindow_ = nullptr;
uint32_t *mappedAddr_ = nullptr;
BufferHandle *bufferHandle_ = nullptr;
struct NativeWindowBuffer *buffer_ = nullptr;
int fenceFd_ = 0;
};
#endif

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2024 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.
*/
export const add: (a: number, b: number) => number;

View File

@ -0,0 +1,6 @@
{
"name": "libentry.so",
"types": "./index.d.ts",
"version": "",
"description": "Please describe the basic information."
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2024 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 AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
};

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2024 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 UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import { BusinessError } from '@ohos.base';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/XComponentDisplaySync', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
};

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2024 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.
*/
export default interface XComponentContext {
register(): void;
unregister(): void;
destroy():void;
};

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2024 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 XComponentContext from '../interface/XComponentContext';
import Logger from '../utils/Logger';
const TAG = '[XComponentDisplaySoloist]';
const START = 'Start';
const STOP = 'Stop';
@Entry
@Component
struct Index {
@State status1: string = START;
@State isOn1: boolean = false;
@State status2: string = START;
@State isOn2: boolean = false;
@State status3: string = START;
@State isOn3: boolean = false;
private xComponentContext1: XComponentContext | undefined = undefined;
private xComponentContext2: XComponentContext | undefined = undefined;
private xComponentContext3: XComponentContext | undefined = undefined;
aboutToDisappear(): void {
// 离开当前页面时解除注册的回调销毁申请的DisplaySoloist
Logger.info(TAG, 'aboutToDisappear');
if (this.xComponentContext1) {
this.xComponentContext1.unregister();
this.xComponentContext1.destroy();
}
if (this.xComponentContext2) {
this.xComponentContext2.unregister();
this.xComponentContext2.destroy();
}
if (this.xComponentContext3) {
this.xComponentContext3.unregister();
this.xComponentContext3.destroy();
}
}
Execute(component: XComponentContext, flg: boolean): string {
if (flg) {
// 注册回调函数并开启每帧回调
component.register();
return STOP;
} else {
// 解注册回调函数并停止启每帧回调
component.unregister();
return START;
}
}
build() {
Column() {
Row() {
Text('30hz')
.fontWeight(FontWeight.Bold)
.fontSize(12)
.fontColor(Color.Red)
.textAlign(TextAlign.End)
.width(40)
.height(30)
Button(this.status1)
.id('Start30')
.controlSize(ControlSize.SMALL)
.onClick((): void => {
if (this.xComponentContext1) {
// 每次点击切换按钮上的显示Start/Stop
this.isOn1 = !(this.isOn1);
this.status1 = this.Execute(this.xComponentContext1, this.isOn1);
}
}).margin(4)
XComponent({ id: 'xcomponentId30', type: 'surface', libraryname: 'entry' })
.onLoad((xComponentContext) => {
this.xComponentContext1 = xComponentContext as XComponentContext;
}).width('640px')
}.height('30%')
.backgroundColor(Color.White);
Row() {
Text('60hz')
.fontWeight(FontWeight.Bold)
.fontSize(12)
.fontColor(Color.Red)
.textAlign(TextAlign.End)
.width(40)
.height(30)
Button(this.status2)
.id('Start60')
.controlSize(ControlSize.SMALL)
.onClick((): void => {
if (this.xComponentContext2) {
this.isOn2 = !(this.isOn2);
this.status2 = this.Execute(this.xComponentContext2, this.isOn2);
}
}).margin(4)
XComponent({ id: 'xcomponentId60', type: 'surface', libraryname: 'entry' })
.onLoad((xComponentContext) => {
this.xComponentContext2 = xComponentContext as XComponentContext;
}).width('640px')
}.height('30%')
.backgroundColor(Color.White);
Row() {
Text('120hz')
.fontWeight(FontWeight.Bold)
.fontSize(12)
.fontColor(Color.Red)
.textAlign(TextAlign.End)
.width(40)
.height(30)
Button(this.status3)
.id('Start120')
.controlSize(ControlSize.SMALL)
.onClick((): void => {
if (this.xComponentContext3) {
this.isOn3 = !(this.isOn3);
this.status3 = this.Execute(this.xComponentContext3, this.isOn3);
}
}).margin(4)
XComponent({ id: 'xcomponentId120', type: 'surface', libraryname: 'entry' })
.onLoad((xComponentContext) => {
this.xComponentContext3 = xComponentContext as XComponentContext;
}).width('640px')
}.height('30%')
.backgroundColor(Color.White);
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2024 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 hilog from '@ohos.hilog';
class Logger {
private domain: number;
private prefix: string;
private format: string = '%{public}s, %{public}s';
constructor(prefix: string) {
this.prefix = prefix;
this.domain = 0xFF00;
}
debug(...args: string[]) {
hilog.debug(this.domain, this.prefix, this.format, args);
}
info(...args: string[]) {
hilog.info(this.domain, this.prefix, this.format, args);
}
warn(...args: string[]) {
hilog.warn(this.domain, this.prefix, this.format, args);
}
error(...args: string[]) {
hilog.error(this.domain, this.prefix, this.format, args);
}
}
export default new Logger('[Sample_DisplaySync]');

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2024 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.
*/
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"default",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
]
}
}

View File

@ -0,0 +1,8 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "DisplaySoloist"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,5 @@
{
"src": [
"pages/Index"
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "DisplaySoloist"
}
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "DisplaySoloist"
}
]
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2024 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 { describe, it, beforeAll, expect } from '@ohos/hypium';
import { Driver, ON } from '@ohos.UiTest';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import Logger from '../utils/Logger';
const TAG = '[Sample_DisplaySoloist]';
const DELAYMS1S = 1000;
export default function abilityTest() {
describe('ActsAbilityTest', () => {
beforeAll(async (done: Function) => {
Logger.info(TAG, 'beforeAll begin');
let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
try {
await abilityDelegator.startAbility({
bundleName: 'com.samples.DisplaySoloist',
abilityName: 'EntryAbility'
});
} catch (err) {
Logger.info(TAG, `beforeAll exception = ${JSON.stringify(err)}`);
}
Logger.info(TAG, 'beforeAll end');
done();
});
/**
* @tc.number:SUB_GRAPHIC_2D_HGM_DISPLAYSOLOIST_0100
* @tc.name:DisplaySoloist_001
* @tc.desc:DisplaySoloist
* @tc.size:MediumTest
* @tc.type:Function
* @tc.level:Level 1
*/
it('DisplaySoloist_001', 0, async (done: Function) => {
try {
Logger.info(TAG, 'DisplaySoloist_001 begin');
let driver = Driver.create();
await driver.assertComponentExist(ON.id('Start30'));
let Start30Button = await driver.findComponent(ON.id('Start30'));
await Start30Button.click();
await driver.assertComponentExist(ON.id('Start60'));
let start60Button = await driver.findComponent(ON.id('Start60'));
await start60Button.click();
await driver.assertComponentExist(ON.id('Start120'));
let Start120Button = await driver.findComponent(ON.id('Start120'));
await Start120Button.click();
await driver.assertComponentExist(ON.id('Start30'));
let Stop30Button = await driver.findComponent(ON.id('Start30'));
await Stop30Button.click();
await driver.assertComponentExist(ON.id('Start60'));
let Stop60Button = await driver.findComponent(ON.id('Start60'));
await Stop60Button.click();
await driver.assertComponentExist(ON.id('Start120'));
let Stop120Button = await driver.findComponent(ON.id('Start120'));
await Stop120Button.click();
await driver.delayMs(DELAYMS1S);
Logger.info(TAG, 'DisplaySoloist_001 end');
done();
} catch (error) {
Logger.info(TAG, `DisplaySoloist_001 exception = ${JSON.stringify(error)}`);
expect().assertFail();
}
});
})
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2024 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 abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2024 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 UIAbility from '@ohos.app.ability.UIAbility';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import hilog from '@ohos.hilog';
import { Hypium } from '@ohos/hypium';
import testsuite from '../test/List.test';
import window from '@ohos.window';
import Want from '@ohos.app.ability.Want';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
export default class TestAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator;
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs;
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments();
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
windowStage.loadContent('testability/pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
}
onForeground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
}
onBackground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024 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.
*/
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2024 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 hilog from '@ohos.hilog';
import TestRunner from '@ohos.application.testRunner';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import Want from '@ohos.app.ability.Want';
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator | undefined = undefined
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs | undefined = undefined
async function onAbilityCreateCallback() {
hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
}
async function addAbilityMonitorCallback(err : Error) {
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
}
export default class OpenHarmonyTestRunner implements TestRunner {
constructor() {
}
onPrepare() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
}
async onRun() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
const bundleName = abilityDelegatorArguments.bundleName;
const testAbilityName = 'TestAbility';
let lMonitor: AbilityDelegatorRegistry.AbilityMonitor = {
abilityName: testAbilityName,
onAbilityCreate: onAbilityCreateCallback,
};
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
const want: Want = {
bundleName: bundleName,
abilityName: testAbilityName
};
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.startAbility(want, (err, data) => {
hilog.info(0x0000, 'testTag', 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
hilog.info(0x0000, 'testTag', 'startAbility : data : %{public}s',JSON.stringify(data) ?? '');
})
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2024 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 hilog from '@ohos.hilog';
class Logger {
private domain: number = 0xF811;
private prefix: string = '';
private format: string = '%{public}s, %{public}s';
constructor(prefix: string) {
this.prefix = prefix;
this.domain = 0xF811;
}
debug(...args: string[]): void {
hilog.debug(this.domain, this.prefix, this.format, args);
}
info(...args: string[]): void {
hilog.info(this.domain, this.prefix, this.format, args);
}
warn(...args: string[]): void {
hilog.warn(this.domain, this.prefix, this.format, args);
}
error(...args: string[]): void {
hilog.error(this.domain, this.prefix, this.format, args);
}
}
export default new Logger('[Sample_DisplaySync]');

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2024 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.
*/
{
"module": {
"name": "entry_test",
"type": "feature",
"description": "$string:module_test_desc",
"mainElement": "TestAbility",
"deviceTypes": [
"default",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:test_pages",
"abilities": [
{
"name": "TestAbility",
"srcEntry": "./ets/testability/TestAbility.ets",
"description": "$string:TestAbility_desc",
"icon": "$media:icon",
"label": "$string:TestAbility_label",
"exported": true,
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"skills": [
{
"actions": [
"action.system.home"
],
"entities": [
"entity.system.home"
]
}
]
}
]
}
}

View File

@ -0,0 +1,8 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,5 @@
{
"src": [
"testability/pages/Index"
]
}

View File

@ -0,0 +1,6 @@
{
"hvigorVersion": "4.0.2",
"dependencies": {
"@ohos/hvigor-ohos-plugin": "4.0.2"
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) 2024 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.
*/
export { appTasks } from '@ohos/hvigor-ohos-plugin';

View File

@ -0,0 +1,48 @@
#!/bin/bash
# ----------------------------------------------------------------------------
# Hvigor startup script, version 1.0.0
#
# Required ENV vars:
# ------------------
# NODE_HOME - location of a Node home dir
# or
# Add /usr/local/nodejs/bin to the PATH environment variable
# ----------------------------------------------------------------------------
HVIGOR_APP_HOME="`pwd -P`"
HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js
warn() {
echo ""
echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
error() {
echo ""
echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
fail() {
error "$@"
exit 1
}
# Determine node to start hvigor wrapper script
if [ -n "${NODE_HOME}" ];then
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
if [ ! -x "$EXECUTABLE_NODE" ];then
fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed"
fi
else
EXECUTABLE_NODE="node"
which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path"
fi
# Check hvigor wrapper script
if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then
fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}"
fi
# start hvigor-wrapper script
exec "${EXECUTABLE_NODE}" \
"${HVIGOR_WRAPPER_SCRIPT}" "$@"

View File

@ -0,0 +1,64 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Hvigor startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js
set NODE_EXE=node.exe
goto start
:start
@rem Find node.exe
if defined NODE_HOME goto findNodeFromNodeHome
%NODE_EXE% --version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:findNodeFromNodeHome
set NODE_HOME=%NODE_HOME:"=%
set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE%
if exist "%NODE_EXE_PATH%" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:execute
@rem Execute hvigor
"%NODE_EXE%" "%WRAPPER_MODULE_PATH%" %*
if "%ERRORLEVEL%" == "0" goto hvigorwEnd
:fail
exit /b 1
:hvigorwEnd
if "%OS%" == "Windows_NT" endlocal
:end

View File

@ -0,0 +1,12 @@
{
"license": "",
"devDependencies": {
"@ohos/hypium": "1.0.6"
},
"author": "",
"name": "drawing",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -0,0 +1,13 @@
# DisplaySoloist测试用例归档
## 用例表
| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 |
|---------|--------------|----------------|-----------------------|------|------|
| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass |
| 按钮点击 | 位于主页 | 点击30hz右侧Start | 方块按照30hz频率移动同时按钮显示为Stop | 是 | Pass |
| 按钮点击 | 位于主页 | 点击30hz右侧Stop | 方块停止移动同时按钮显示为Start | 是 | Pass |
| 按钮点击 | 位于主页 | 点击60hz右侧Start | 方块按照60hz频率移动同时按钮显示为Stop | 是 | Pass | 是 | Pass |
| 按钮点击 | 位于主页 | 点击60hz右侧Stop | 方块停止移动同时按钮显示为Start | 是 | Pass | 是 | Pass |
| 按钮点击 | 位于主页 | 点击120hz右侧Start | 方块按照120hz频率移动同时按钮显示为Stop | 是 | Pass | 是 | Pass |
| 按钮点击 | 位于主页 | 点击120hz右侧Stop | 方块停止移动同时按钮显示为Start | 是 | Pass | 是 | Pass |

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB