!4533 【Sample】新增MindSporeLite C Demo

Merge pull request !4533 from 钱丹/master
This commit is contained in:
openharmony_ci 2024-06-26 11:21:57 +00:00 committed by Gitee
commit ce43beb72a
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
48 changed files with 1491 additions and 0 deletions

View File

@ -271,6 +271,13 @@ Note:If the text contains special characters, please escape them according to th
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteArkTSDemo/entry/src/main/resources/base/media/icon.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteArkTSDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteArkTSDemo/AppScope/resources/base/media/app_icon.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteArkTSDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteArkTSDemo/screenshots/MindSporeLiteArkTSDemo.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteArkTSDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteCDemo/entry/src/ohosTest/resources/base/media/icon.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteCDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteCDemo/entry/src/main/resources/base/media/startIcon.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteCDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteCDemo/entry/src/main/resources/base/media/background.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteCDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteCDemo/entry/src/main/resources/base/media/foreground.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteCDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteCDemo/entry/src/main/resources/base/media/icon.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteCDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteCDemo/AppScope/resources/base/media/app_icon.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteCDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/MindSporeLiteCDemo/screenshots/MindSporeLiteCDemoPic.png" desc="Provided by code/DocsSample/ApplicationModels/MindSporeLiteCDemo"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/ImplicitStartByTypeRely/entry/src/main/resources/base/media/icon.png" desc="Provided by code/DocsSample/ApplicationModels/ImplicitStartByTypeRely"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/ImplicitStartByTypeRely/screenshots/newability.png" desc="Provided by code/DocsSample/ApplicationModels/ImplicitStartByTypeRely"/>
<filteritem type="filepath" name="code/DocsSample/ApplicationModels/StageModelAbilityInteraction/screenshot/coldstartuppage.png" desc="Provided by code/DocsSample/ApplicationModels/StageModelAbilityInteraction"/>

View File

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

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.mindsporelitecdemo",
"vendor": "samples",
"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": "MindSporeLiteCDemo"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,85 @@
# **基于**Native**接口的MindSpore Lite应用开发**
### 介绍
本文基于MindSpore Lite提供的[Native API](https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/reference/apis-mindspore-lite-kit/_mind_spore.md),实现“图像分类”示例程序,来演示端侧部署的流程。
1. 选择图像分类模型。
2. 将模型转换成MindSpore Lite模型格式。
3. 使用MindSpore Lite推理模型显示出可能的分类结果。
### 效果预览
| 主页 |
| -------------------------------------------------- |
| <img src="screenshots/MindSporeLiteCDemoPic.png"/> |
#### 使用说明
1. 在主界面可以点击photo按钮进入相册选择图片界面
2. 在相册界面,选择图片,点击确定按钮;
3. 自动进行选择图片的图像分类模型推理,部分推理结果显示在主界面。
### 工程目录
```
entry
├── src/main
│   ├── etc
|   |   └── pages
|   |       └── Index.ets // 首页,获取图片及预处理
│   ├── cpp
|   |   └── mslite_napi.cpp // 推理函数
|   |   └── CMakeLists.txt // 编译脚本
|   |   └── types
|   |   └── libentry
|   |       └── Index.t.ts // 将C++动态库封装成JS模块
│   ├── resources // 资源文件
|   |   └── rawfile
|   |       └── mobilenetv2.ms // 存放的模型文件
```
### 具体实现
* 本示例程序中使用的终端图像分类模型文件为mobilenetv2.ms放置在entry\src\main\resources\rawfile工程目录下。
注:可手工下载模型文件[mobilenetv2.ms](https://download.mindspore.cn/model_zoo/official/lite/mobilenetv2_openimage_lite/1.5/mobilenetv2.ms)。
* 调用[@ohos.file.picker](https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/reference/apis-core-file-kit/js-apis-file-picker.md) (图片文件选择)、[@ohos.multimedia.image](https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/reference/apis-image-kit/js-apis-image.md) (图片处理效果)、[@ohos.file.fs](https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/reference/apis-core-file-kit/js-apis-file-fs.md) (基础文件操作) 等API实现相册图片获取及图片处理。完整代码请参见Index.ets。
* 调用[MindSpore Lite Native API](https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/reference/apis-mindspore-lite-kit/_mind_spore.md)实现推理。完整代码请参见mslite_napi.cpp。
* 编写CMake脚本。链接MindSpore Lite动态库完整代码请参见CMakeLists.txt。
* 使用N-API将C++动态库封装成JS模块。在 entry/src/main/cpp/types/libentry/index.d.ts定义JS接口`runDemo()` 。
* 调用推理函数并处理结果。完整代码请参见Index.ets
### 相关权限
无。
### 依赖
无。
### 约束与限制
1.本示例仅支持标准系统上运行测试设备RK3568;
2.本示例为Stage模型已适配API version 11版本SDK;
3.本示例需要使用DevEco Studio 4.1 Release及以上版本才可编译运行。
### 下载
如需单独下载本工程,执行如下命令:
```
git init
git config core.sparsecheckout true
echo code/BasicFeature/ApplicationModels/MindSporeLiteCDemo/ > .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,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.
*/
{
"app": {
"signingConfigs": [
],
"products": [
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": 11,
"compileSdkVersion": 11,
"runtimeOS": "OpenHarmony"
}
],
"buildModeSet": [
{
"name": "debug",
},
{
"name": "release"
}
]
},
"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,55 @@
/*
* 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",
"abiFilters": ['arm64-v8a', 'armeabi-v7a', 'x86_64'],
"arguments": "",
"cppFlags": "",
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
}
}
},
"nativeLib": {
"debugSymbol": {
"strip": true,
"exclude": []
}
}
},
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest",
}
]
}

View File

@ -0,0 +1,6 @@
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. */
}

View File

@ -0,0 +1,18 @@
# 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://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
# 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

View File

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

View File

@ -0,0 +1,18 @@
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(MindSporeLiteCDemo)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
add_library(entry SHARED mslite_napi.cpp)
target_link_libraries(entry PUBLIC mindspore_lite_ndk)
target_link_libraries(entry PUBLIC hilog_ndk.z)
target_link_libraries(entry PUBLIC rawfile.z)
target_link_libraries(entry PUBLIC ace_napi.z)

View File

@ -0,0 +1,230 @@
/*
* 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 "napi/native_api.h"
#include <hilog/log.h>
#include <rawfile/raw_file_manager.h>
#include <iostream>
#include <cstdlib>
#include <mindspore/types.h>
#include <mindspore/model.h>
#include <mindspore/context.h>
#include <mindspore/status.h>
#include <mindspore/tensor.h>
#include <sstream>
#define LOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "[MSLiteNapi]", __VA_ARGS__))
#define LOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_DOMAIN, "[MSLiteNapi]", __VA_ARGS__))
#define LOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, LOG_DOMAIN, "[MSLiteNapi]", __VA_ARGS__))
#define LOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "[MSLiteNapi]", __VA_ARGS__))
constexpr int K_NUM_PRINT_OF_OUT_DATA = 20;
int FillInputTensor(OH_AI_TensorHandle input, std::vector<float> input_data)
{
if (OH_AI_TensorGetDataType(input) == OH_AI_DATATYPE_NUMBERTYPE_FLOAT32) {
float *data = (float *)OH_AI_TensorGetMutableData(input);
for (size_t i = 0; i < OH_AI_TensorGetElementNum(input); i++) {
data[i] = input_data[i];
}
return OH_AI_STATUS_SUCCESS;
} else {
return OH_AI_STATUS_LITE_ERROR;
}
}
void *ReadModelFile(NativeResourceManager *nativeResourceManager, const std::string &modelName, size_t *modelSize)
{
auto rawFile = OH_ResourceManager_OpenRawFile(nativeResourceManager, modelName.c_str());
if (rawFile == nullptr) {
LOGE("MS_LITE_ERR: Open model file failed");
return nullptr;
}
long fileSize = OH_ResourceManager_GetRawFileSize(rawFile);
if (fileSize <= 0) {
LOGE("MS_LITE_ERR: FileSize not correct");
}
void *modelBuffer = malloc(fileSize);
if (modelBuffer == nullptr) {
LOGE("MS_LITE_ERR: OH_ResourceManager_ReadRawFile failed");
}
int ret = OH_ResourceManager_ReadRawFile(rawFile, modelBuffer, fileSize);
if (ret == 0) {
LOGI("MS_LITE_LOG: OH_ResourceManager_ReadRawFile failed");
OH_ResourceManager_CloseRawFile(rawFile);
return nullptr;
}
OH_ResourceManager_CloseRawFile(rawFile);
*modelSize = fileSize;
return modelBuffer;
}
void DestroyModelBuffer(void **buffer)
{
if (buffer == nullptr) {
return;
}
free(*buffer);
*buffer = nullptr;
}
OH_AI_ModelHandle CreateMSLiteModel(void *modelBuffer, size_t modelSize)
{
// Set executing context for model.
auto context = OH_AI_ContextCreate();
if (context == nullptr) {
DestroyModelBuffer(&modelBuffer);
LOGE("MS_LITE_ERR: Create MSLite context failed.\n");
return nullptr;
}
auto cpu_device_info = OH_AI_DeviceInfoCreate(OH_AI_DEVICETYPE_CPU);
OH_AI_DeviceInfoSetEnableFP16(cpu_device_info, true);
OH_AI_ContextAddDeviceInfo(context, cpu_device_info);
// Create model
auto model = OH_AI_ModelCreate();
if (model == nullptr) {
DestroyModelBuffer(&modelBuffer);
LOGE("MS_LITE_ERR: Allocate MSLite Model failed.\n");
return nullptr;
}
// Build model object
auto build_ret = OH_AI_ModelBuild(model, modelBuffer, modelSize, OH_AI_MODELTYPE_MINDIR, context);
DestroyModelBuffer(&modelBuffer);
if (build_ret != OH_AI_STATUS_SUCCESS) {
OH_AI_ModelDestroy(&model);
LOGE("MS_LITE_ERR: Build MSLite model failed.\n");
return nullptr;
}
LOGI("MS_LITE_LOG: Build MSLite model success.\n");
return model;
}
int RunMSLiteModel(OH_AI_ModelHandle model, std::vector<float> input_data)
{
// Set input data for model.
auto inputs = OH_AI_ModelGetInputs(model);
auto ret = FillInputTensor(inputs.handle_list[0], input_data);
if (ret != OH_AI_STATUS_SUCCESS) {
LOGE("MS_LITE_ERR: RunMSLiteModel set input error.\n");
return OH_AI_STATUS_LITE_ERROR;
}
// Get model output.
auto outputs = OH_AI_ModelGetOutputs(model);
// Predict model.
auto predict_ret = OH_AI_ModelPredict(model, inputs, &outputs, nullptr, nullptr);
if (predict_ret != OH_AI_STATUS_SUCCESS) {
OH_AI_ModelDestroy(&model);
LOGE("MS_LITE_ERR: MSLite Predict error.\n");
return OH_AI_STATUS_LITE_ERROR;
}
LOGI("MS_LITE_LOG: Run MSLite model Predict success.\n");
// Print output tensor data.
LOGI("MS_LITE_LOG: Get model outputs:\n");
for (size_t i = 0; i < outputs.handle_num; i++) {
auto tensor = outputs.handle_list[i];
LOGI("MS_LITE_LOG: - Tensor %{public}d name is: %{public}s.\n", static_cast<int>(i),
OH_AI_TensorGetName(tensor));
LOGI("MS_LITE_LOG: - Tensor %{public}d size is: %{public}d.\n", static_cast<int>(i),
(int)OH_AI_TensorGetDataSize(tensor));
LOGI("MS_LITE_LOG: - Tensor data is:\n");
auto out_data = reinterpret_cast<const float *>(OH_AI_TensorGetData(tensor));
std::stringstream outStr;
for (int i = 0; (i < OH_AI_TensorGetElementNum(tensor)) && (i <= K_NUM_PRINT_OF_OUT_DATA); i++) {
outStr << out_data[i] << " ";
}
LOGI("MS_LITE_LOG: %{public}s", outStr.str().c_str());
}
return OH_AI_STATUS_SUCCESS;
}
static napi_value RunDemo(napi_env env, napi_callback_info info)
{
// run demo
napi_value error_ret;
napi_create_int32(env, -1, &error_ret);
// 传入数据处理
size_t argc = 2;
napi_value argv[2] = {nullptr};
napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
bool isArray = false;
napi_is_array(env, argv[0], &isArray);
uint32_t length = 0;
// 获取数组的长度
napi_get_array_length(env, argv[0], &length);
std::vector<float> input_data;
double param = 0;
for (int i = 0; i < length; i++) {
napi_value value;
napi_get_element(env, argv[0], i, &value);
napi_get_value_double(env, value, &param);
input_data.push_back(static_cast<float>(param));
}
std::stringstream outstr;
for (int i = 0; i < K_NUM_PRINT_OF_OUT_DATA; i++) {
outstr << input_data[i] << " ";
}
// Read model file
const std::string modelName = "mobilenetv2.ms";
size_t modelSize;
auto resourcesManager = OH_ResourceManager_InitNativeResourceManager(env, argv[1]);
auto modelBuffer = ReadModelFile(resourcesManager, modelName, &modelSize);
if (modelBuffer == nullptr) {
return error_ret;
}
auto model = CreateMSLiteModel(modelBuffer, modelSize);
int ret = RunMSLiteModel(model, input_data);
if (ret != OH_AI_STATUS_SUCCESS) {
OH_AI_ModelDestroy(&model);
return error_ret;
}
napi_value out_data;
napi_create_array(env, &out_data);
auto outputs = OH_AI_ModelGetOutputs(model);
OH_AI_TensorHandle output_0 = outputs.handle_list[0];
float *output0Data = reinterpret_cast<float *>(OH_AI_TensorGetMutableData(output_0));
for (size_t i = 0; i < OH_AI_TensorGetElementNum(output_0); i++) {
napi_value element;
napi_create_double(env, static_cast<double>(output0Data[i]), &element);
napi_set_element(env, out_data, i, element);
}
OH_AI_ModelDestroy(&model);
return out_data;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {{"runDemo", nullptr, RunDemo, nullptr, nullptr, nullptr, napi_default, nullptr}};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
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,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 runDemo: (a: number[], b:Object) => Array<number>;

View File

@ -0,0 +1,6 @@
{
"name": "libentry.so",
"types": "./index.d.ts",
"version": "",
"description": "MindSpore Lite inference module"
}

View File

@ -0,0 +1,41 @@
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
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) => {
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.');
});
}
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,264 @@
import resourceManager from '@ohos.resourceManager'
import fileIo from '@ohos.file.fs';
import msliteNapi from 'libentry.so'
import picker from '@ohos.file.picker';
import { BusinessError } from '@ohos.base';
import image from '@ohos.multimedia.image';
const TAG = 'MindSporeLite';
@Entry
@Component
struct Index {
@State message: string = 'MindSporeLite C Demo';
@State modelName: string = 'mobilenetv2.ms';
@State modelInputHeight: number = 224;
@State modelInputWidth: number = 224;
@State uris: Array<string> = [];
@State max: number = 0;
@State maxIndex: number = 0;
@State maxArray: Array<number> = [];
@State maxIndexArray: Array<number> = [];
@State labelsNameMap: string[] = [
'Herd', 'Safari', 'Bangle', 'Cushion', 'Countertop',
'Prom', 'Branch', 'Sports', 'Sky', 'Community',
'Wheel', 'Cola', 'Tuxedo', 'Flowerpot', 'Team',
'Computer', 'Unicycle', 'Brig', 'Aerospace engineering', 'Scuba diving',
'Goggles', 'Fruit', 'Badminton', 'Horse', 'Sunglasses',
'Fun', 'Prairie', 'Poster', 'Flag', 'Speedboat',
'Eyelash', 'Veil', 'Mobile phone', 'Wheelbarrow', 'Saucer',
'Leather', 'Drawer', 'Paper', 'Pier', 'Waterfowl',
'Tights', 'Rickshaw', 'Vegetable', 'Handrail', 'Ice',
'Metal', 'Flower', 'Wing', 'Silverware', 'Event',
'Skyline', 'Money', 'Comics', 'Handbag', 'Porcelain',
'Rodeo', 'Curtain', 'Tile', 'Human mouth', 'Army',
'Menu', 'Boat', 'Snowboarding', 'Cairn terrier', 'Net',
'Pasteles', 'Cup', 'Rugby', 'Pho', 'Cap',
'Human hair', 'Surfing', 'Loveseat', 'Museum', 'Shipwreck',
'Trunk (Tree)', 'Plush', 'Monochrome', 'Volcano', 'Rock',
'Pillow', 'Presentation', 'Nebula', 'Subwoofer', 'Lake',
'Sledding', 'Bangs', 'Tablecloth', 'Necklace', 'Swimwear',
'Standing', 'Jeans', 'Carnival', 'Softball', 'Centrepiece',
'Skateboarder', 'Cake', 'Dragon', 'Aurora', 'Skiing',
'Bathroom', 'Dog', 'Needlework', 'Umbrella', 'Church',
'Fire', 'Piano', 'Denim', 'Bridle', 'Cabinetry',
'Lipstick', 'Ring', 'Television', 'Roller', 'Seal',
'Concert', 'Product', 'News', 'Fast food', 'Horn (Animal)',
'Tattoo', 'Bird', 'Bridegroom', 'Love', 'Helmet',
'Dinosaur', 'Icing', 'Miniature', 'Tire', 'Toy',
'Icicle', 'Jacket', 'Coffee', 'Mosque', 'Rowing',
'Wetsuit', 'Camping', 'Underwater', 'Christmas', 'Gelato',
'Whiteboard', 'Field', 'Ragdoll', 'Construction', 'Lampshade',
'Palace', 'Meal', 'Factory', 'Cage', 'Clipper (Boat)',
'Gymnastics', 'Turtle', 'Human foot', 'Marriage', 'Web page',
'Human beard', 'Fog', 'Wool', 'Cappuccino', 'Lighthouse',
'Lego', 'Sparkler', 'Sari', 'Model', 'Temple',
'Beanie', 'Building', 'Waterfall', 'Penguin', 'Cave',
'Stadium', 'Smile', 'Human hand', 'Park', 'Desk',
'Shetland sheepdog', 'Bar', 'Eating', 'Neon', 'Dalmatian',
'Crocodile', 'Wakeboarding', 'Longboard', 'Road', 'Race',
'Kitchen', 'Odometer', 'Cliff', 'Fiction', 'School',
'Interaction', 'Bullfighting', 'Boxer', 'Gown', 'Aquarium',
'Superhero', 'Pie', 'Asphalt', 'Surfboard', 'Cheeseburger',
'Screenshot', 'Supper', 'Laugh', 'Lunch', 'Party ',
'Glacier', 'Bench', 'Grandparent', 'Sink', 'Pomacentridae',
'Blazer', 'Brick', 'Space', 'Backpacking', 'Stuffed toy',
'Sushi', 'Glitter', 'Bonfire', 'Castle', 'Marathon',
'Pizza', 'Beach', 'Human ear', 'Racing', 'Sitting',
'Iceberg', 'Shelf', 'Vehicle', 'Pop music', 'Playground',
'Clown', 'Car', 'Rein', 'Fur', 'Musician',
'Casino', 'Baby', 'Alcohol', 'Strap', 'Reef',
'Balloon', 'Outerwear', 'Cathedral', 'Competition', 'Joker',
'Blackboard', 'Bunk bed', 'Bear', 'Moon', 'Archery',
'Polo', 'River', 'Fishing', 'Ferris wheel', 'Mortarboard',
'Bracelet', 'Flesh', 'Statue', 'Farm', 'Desert',
'Chain', 'Aircraft', 'Textile', 'Hot dog', 'Knitting',
'Singer', 'Juice', 'Circus', 'Chair', 'Musical instrument',
'Room', 'Crochet', 'Sailboat', 'Newspaper', 'Santa claus',
'Swamp', 'Skyscraper', 'Skin', 'Rocket', 'Aviation',
'Airliner', 'Garden', 'Ruins', 'Storm', 'Glasses',
'Balance', 'Nail (Body part)', 'Rainbow', 'Soil ', 'Vacation ',
'Moustache', 'Doily', 'Food', 'Bride ', 'Cattle',
'Pocket', 'Infrastructure', 'Train', 'Gerbil', 'Fireworks',
'Pet', 'Dam', 'Crew', 'Couch', 'Bathing',
'Quilting', 'Motorcycle', 'Butterfly', 'Sled', 'Watercolor paint',
'Rafting', 'Monument', 'Lightning', 'Sunset', 'Bumper',
'Shoe', 'Waterskiing', 'Sneakers', 'Tower', 'Insect',
'Pool', 'Placemat', 'Airplane', 'Plant', 'Jungle',
'Armrest', 'Duck', 'Dress', 'Tableware', 'Petal',
'Bus', 'Hanukkah', 'Forest', 'Hat', 'Barn',
'Tubing', 'Snorkeling', 'Cool', 'Cookware and bakeware', 'Cycling',
'Swing (Seat)', 'Muscle', 'Cat', 'Skateboard', 'Star',
'Toe', 'Junk', 'Bicycle', 'Bedroom', 'Person',
'Sand', 'Canyon', 'Tie', 'Twig', 'Sphynx',
'Supervillain', 'Nightclub', 'Ranch', 'Pattern', 'Shorts',
'Himalayan', 'Wall', 'Leggings', 'Windsurfing', 'Deejay',
'Dance', 'Van', 'Bento', 'Sleep', 'Wine',
'Picnic', 'Leisure', 'Dune', 'Crowd', 'Kayak',
'Ballroom', 'Selfie', 'Graduation', 'Frigate', 'Mountain',
'Dude', 'Windshield', 'Skiff', 'Class', 'Scarf',
'Bull', 'Soccer', 'Bag', 'Basset hound', 'Tractor',
'Swimming', 'Running', 'Track', 'Helicopter', 'Pitch',
'Clock', 'Song', 'Jersey', 'Stairs', 'Flap',
'Jewellery', 'Bridge', 'Cuisine', 'Bread', 'Caving',
'Shell', 'Wreath', 'Roof', 'Cookie', 'Canoe'
];
build() {
Row() {
Column() {
Text(this.message)
.fontSize(30)
.fontWeight(FontWeight.Bold);
//图片显示
Image(this.uris[0]).width(320).height(540).margin(15)
//显示分类最大值
if (this.max) {
Text(this.labelsNameMap[this.maxIndexArray[0]] +
': ' +
(this.maxArray[0] / 100).toString() +
'%\n' +
this.labelsNameMap[this.maxIndexArray[1]] +
': ' +
(this.maxArray[1] / 100).toString() +
'%\n' +
this.labelsNameMap[this.maxIndexArray[2]] +
': ' +
(this.maxArray[2] / 100).toString() +
'%\n' +
this.labelsNameMap[this.maxIndexArray[3]] +
': ' +
(this.maxArray[3] / 100).toString() +
'%').focusable(true).fontSize(20)
}
Button() {
Text('photo')
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
.type(ButtonType.Capsule)
.margin({
top: 20
})
.backgroundColor('#0D9FFB')
.width('40%')
.height('5%')
.onClick(() => {
let resMgr: resourceManager.ResourceManager = getContext().getApplicationContext().resourceManager;
//获取相册图片
//1.创建图片-视频类型文件选择选项实例
let PhotoSelectOptions = new picker.PhotoSelectOptions();
//2.选择媒体文件类型和选择媒体文件的最大数目
PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; // 过滤选择媒体文件类型为IMAGE
PhotoSelectOptions.maxSelectNumber = 1; // 选择媒体文件的最大数目
//3.创建图库选择器实例调用select()接口拉起图库界面进行文件选择。文件选择成功后,返回 photoSelectResult 结果集。
let photoPicker = new picker.PhotoViewPicker();
photoPicker.select(PhotoSelectOptions,
async (err: BusinessError, photoSelectResult: picker.PhotoSelectResult) => {
if (err) {
console.error('MS_LITE_ERR: PhotoViewPicker.select failed with err: ' + JSON.stringify(err));
return;
}
console.info('MS_LITE_LOG: PhotoViewPicker.select successfully, photoSelectResult uri: ' +
JSON.stringify(photoSelectResult));
this.uris = photoSelectResult.photoUris;
console.info('MS_LITE_LOG: uri: ' + this.uris);
try {
// 预处理图片数据
// 1.使用fs.openSync接口通过uri打开这个文件得到fd
let file = fileIo.openSync(this.uris[0], fileIo.OpenMode.READ_ONLY);
console.info('MS_LITE_LOG: file fd: ' + file.fd);
// 2.通过fd使用fs.readSync接口读取这个文件内的数据
let inputBuffer = new ArrayBuffer(4096000);
let readLen = fileIo.readSync(file.fd, inputBuffer);
console.info('MS_LITE_LOG: readSync data to file succeed and inputBuffer size is:' + readLen);
// 3.通过 PixelMap 预处理
let imageSource = image.createImageSource(file.fd);
let pixelMap = await imageSource.createPixelMap({ editable: true });
let info = await pixelMap.getImageInfo();
console.info('MS_LITE_LOG: info.width = ' + info.size.width);
console.info('MS_LITE_LOG: info.height = ' + info.size.height);
// 4. 获取图片buffer数据readBuffer并进行处理
pixelMap.scale(256.0 / info.size.width, 256.0 / info.size.height).then(() => {
pixelMap.crop({
x: 16,
y: 16,
size: { height: this.modelInputHeight, width: this.modelInputWidth }
})
.then(async () => {
let info = await pixelMap.getImageInfo();
console.info('MS_LITE_LOG: crop info.width = ' + info.size.width);
console.info('MS_LITE_LOG: crop info.height = ' + info.size.height);
// 需要创建的像素buffer大小
let readBuffer = new ArrayBuffer(this.modelInputHeight * this.modelInputWidth * 4);
await pixelMap.readPixelsToBuffer(readBuffer);
console.info('MS_LITE_LOG: Succeeded in reading image pixel data, buffer: ' + readBuffer.byteLength);
// 处理readBuffer
const imageArr =
new Uint8Array(readBuffer.slice(0, this.modelInputHeight * this.modelInputWidth * 4));
console.info('MS_LITE_LOG: imageArr length: ' + imageArr.length);
let means = [0.485, 0.456, 0.406];
let stds = [0.229, 0.224, 0.225];
let float32View = new Float32Array(this.modelInputHeight * this.modelInputWidth * 3);
let index = 0;
for (let i = 0; i < imageArr.length; i++) {
if ((i + 1) % 4 == 0) {
float32View[index] = (imageArr[i - 3] / 255.0 - means[0]) / stds[0]; // B
float32View[index+1] = (imageArr[i - 2] / 255.0 - means[1]) / stds[1]; // G
float32View[index+2] = (imageArr[i - 1] / 255.0 - means[2]) / stds[2]; // R
index += 3;
}
}
console.info('MS_LITE_LOG: float32View length: ' + float32View.length);
let printStr = 'float32View data:';
for (let i = 0; i < 20; i++) {
printStr += ' ' + float32View[i];
}
console.info('MS_LITE_LOG: float32View data: ' + printStr);
// 调用c++的runDemo
console.info('MS_LITE_LOG: *** Start MSLite Demo ***');
let output: Array<number> = msliteNapi.runDemo(Array.from(float32View), resMgr);
console.warn('MS_LITE_WARN: output length = ', output.length, ';value = ', output.slice(0, 20));
// 取分类最大值top5
let newArray = output.filter(value => value !== this.max);
for (let n = 0; n < 5; n++) {
this.max = output[0];
this.maxIndex = 0;
// 取最大值
for (let m = 0; m < newArray.length; m++) {
if (newArray[m] > this.max) {
this.max = newArray[m];
this.maxIndex = m;
}
}
this.maxArray.push(Math.round(this.max * 10000));
this.maxIndexArray.push(this.maxIndex);
// filter函数 数组过滤函数
newArray = newArray.filter(value => value !== this.max);
}
console.info('MS_LITE_LOG: max:' + this.maxArray);
console.info('MS_LITE_LOG: maxIndex:' + this.maxIndexArray);
console.info('MS_LITE_LOG: *** Finished MSLite Demo ***');
})
})
// 5.关闭文件
fileIo.closeSync(file);
} catch (err) {
console.error('MS_LITE_LOG: uri: open file fd failed.' + err);
}
})
})
}.width('100%')
}
.height('100%')
}
}

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,20 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "MindSporeLiteC"
},
{
"name": "completed",
"value": "完成"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,6 @@
{
"layered-image": {
"background": "$media:background",
"foreground": "$media:foreground"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

View File

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

View File

@ -0,0 +1,20 @@
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "MindSporeLiteC"
},
{
"name": "completed",
"value": "完成"
}
]
}

View File

@ -0,0 +1,17 @@
/*
* 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.
*/
{
}

View File

@ -0,0 +1,96 @@
import { hilog } from '@kit.PerformanceAnalysisKit';
import { describe, it, expect } from '@ohos/hypium';
import Want from '@ohos.app.ability.Want';
import Base from '@ohos.base';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import { Driver, ON } from '@ohos.UiTest';
import { getString } from '../utils/ResourceUtil';
const BUNDLE = 'MindSporeLiteCDemo_';
const TAG = 'abilityTest';
const DOMAIN: number = 0xF811;
export default function abilityTest() {
let driver: Driver = Driver.create();
describe('MindSporeLiteCDemoTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
/*
* @tc.number: MindSporeLiteCDemoTest_000
* @tc.name: Start Ability
* @tc.desc: Start Ability
* @tc.size: MediumTest
* @tc.type: Function
* @tc.level Level 1
*/
it('EntryAbility', 0, async (done: Function) => {
hilog.info(DOMAIN, TAG, BUNDLE + 'EntryAbility_001 begin');
// Start Ability
let want: Want = {
bundleName: 'com.samples.mindsporelitecdemo',
abilityName: 'EntryAbility'
};
let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.startAbility(want, (err: Base.BusinessError) => {
hilog.info(DOMAIN, TAG, 'StartAbility get err ' + JSON.stringify(err));
expect(err).assertNull();
})
await driver.delayMs(3000);
hilog.info(DOMAIN, TAG, BUNDLE + 'EntryAbility_001 end');
done();
})
/**
* @tc.number : MindSporeLiteCDemoTest_001
* @tc.name : open photo
* @tc.desc : open photo
* @tc.size : MEDIUM
* @tc.type : Function
* @tc.level : Level 1
*/
it('IfExists', 0, async (done: Function) => {
hilog.info(DOMAIN, TAG, BUNDLE + 'IfExists_001 begin');
await driver.delayMs(1000);
await driver.assertComponentExist(ON.text('MindSporeLite C Demo'));
await driver.assertComponentExist(ON.text('photo'));
expect(true).assertTrue();
hilog.info(DOMAIN, TAG, BUNDLE + 'IfExists_001 end');
done();
})
/**
* @tc.number : MindSporeLiteCDemoTest_002
* @tc.name : open photo and predict
* @tc.desc : open photo and predict
* @tc.size : MEDIUM
* @tc.type : Function
* @tc.level : Level 1
*/
it('PhotoPredict', 0, async (done: Function) => {
hilog.info(DOMAIN, TAG, BUNDLE + 'PhotoPredict_001 begin');
await driver.delayMs(1000);
// click MindSporeLite C Demo
hilog.info(DOMAIN, TAG, BUNDLE + 'PhotoPredict_001 click photo button');
await driver.assertComponentExist(ON.text('photo'));
let msPhoto = await driver.findComponent(ON.text('photo'));
await msPhoto.click();
await driver.delayMs(1000);
// chose a photo
let gridItems = await driver.findComponents(ON.type('GridItem'));
await gridItems[1].click();
await driver.delayMs(5000);
// click complete
let tipCompleted: string = getString($r('app.string.completed'));
await driver.assertComponentExist(ON.text(tipCompleted));
let finish = await driver.findComponent(ON.text(tipCompleted));
await driver.delayMs(5000);
await finish.click();
await driver.delayMs(5000);
// predict
await driver.assertComponentExist(ON.text('MindSporeLite C Demo'));
await driver.assertComponentExist(ON.text('%', 1));
await driver.delayMs(5000);
expect(true).assertTrue();
hilog.info(DOMAIN, TAG, BUNDLE + 'PhotoPredict_001 end');
done();
})
})
}

View File

@ -0,0 +1,5 @@
import abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}

View File

@ -0,0 +1,47 @@
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { abilityDelegatorRegistry } from '@kit.TestKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { Hypium } from '@ohos/hypium';
import testsuite from '../test/List.test';
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) => {
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.');
});
}
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,17 @@
@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,91 @@
import { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit';
import { UIAbility, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { resourceManager } from '@kit.LocalizationKit';
import { util } from '@kit.ArkTS';
let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
let jsonPath: string = 'mock/mock-config.json';
let tag: string = 'testTag';
async function onAbilityCreateCallback(data: UIAbility) {
hilog.info(0x0000, 'testTag', 'onAbilityCreateCallback, data: ${}', JSON.stringify(data));
}
async function addAbilityMonitorCallback(err: BusinessError) {
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() {
let tag = 'testTag';
hilog.info(0x0000, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run');
abilityDelegatorArguments = abilityDelegatorRegistry.getArguments()
abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator()
let moduleName = abilityDelegatorArguments.parameters['-m'];
let context = abilityDelegator.getAppContext().getApplicationContext().createModuleContext(moduleName);
let mResourceManager = context.resourceManager;
await checkMock(abilityDelegator, mResourceManager);
const bundleName = abilityDelegatorArguments.bundleName;
const testAbilityName: string = 'TestAbility';
let lMonitor: abilityDelegatorRegistry.AbilityMonitor = {
abilityName: testAbilityName,
onAbilityCreate: onAbilityCreateCallback,
moduleName: moduleName
};
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
const want: Want = {
bundleName: bundleName,
abilityName: testAbilityName,
moduleName: moduleName
};
abilityDelegator.startAbility(want, (err: BusinessError, data: void) => {
hilog.info(0x0000, tag, 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
hilog.info(0x0000, tag, 'startAbility : data : %{public}s', JSON.stringify(data) ?? '');
})
hilog.info(0x0000, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end');
}
}
async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator,
resourceManager: resourceManager.ResourceManager) {
let rawFile: Uint8Array;
try {
rawFile = resourceManager.getRawFileContentSync(jsonPath);
hilog.info(0x0000, tag, 'MockList file exists');
let mockStr: string = util.TextDecoder.create('utf-8', { ignoreBOM: true }).decodeWithStream(rawFile);
let mockMap: Record<string, string> = getMockList(mockStr);
try {
abilityDelegator.setMockList(mockMap)
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
hilog.error(0x0000, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`);
}
} catch (error) {
let code = (error as BusinessError).code;
let message = (error as BusinessError).message;
hilog.error(0x0000, tag, `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`);
}
}
function getMockList(jsonStr: string) {
let jsonObj: Record<string, Object> = JSON.parse(jsonStr);
let map: Map<string, object> = new Map<string, object>(Object.entries(jsonObj));
let mockList: Record<string, string> = {};
map.forEach((value: object, key: string) => {
let realValue: string = value['source'].toString();
mockList[key] = realValue;
});
hilog.info(0x0000, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? '');
return mockList;
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2024 Hunan OpenValley Digital Industry Development 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 AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
const delegator = AbilityDelegatorRegistry.getAbilityDelegator();
export function getString(resourceData: Resource): string {
let manage = delegator.getAppContext().resourceManager;
return manage.getStringSync(resourceData);
}

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,20 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
},
{
"name": "completed",
"value": "完成"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

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

View File

@ -0,0 +1,5 @@
import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}

View File

@ -0,0 +1,33 @@
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function localUnitTest() {
describe('localUnitTest',() => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
});
});
}

View File

@ -0,0 +1,37 @@
/*
* 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.
*/
{
"hvigorVersion": "4.1.2",
"dependencies": {
"@ohos/hvigor-ohos-plugin": "4.1.2"
},
"execution": {
// "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */
// "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
// "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
// "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
// "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
},
"logging": {
// "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
},
"debugging": {
// "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
},
"nodeOptions": {
// "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */
}
}

View File

@ -0,0 +1,6 @@
import { appTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}

View File

@ -0,0 +1,29 @@
/*
* 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.
*/
{
"name": "mindsporelitecdemo",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "",
"author": "",
"license": "",
"dependencies": {
},
"devDependencies": {
"@ohos/hypium": "1.0.16",
"@ohos/hamock": "1.0.0"
}
}

View File

@ -0,0 +1,9 @@
# MindSporeLiteCDemo 测试用例归档
## 用例表
|测试功能|预置条件|输入|预期输出|是否自动|测试结果|
|--------------------------------|--------------------------------|--------------------------------|--------------------------------|--------------------------------|--------------------------------|
|拉起应用| 设备正常运行| |成功拉起应用|是|Pass|
|查看预览界面Text和Button| 进入预览界面 | |预览界面存在Text和Button|是|Pass|
|选取图片推理功能测试| 进入预览界面 | 点击photo按钮 |选取图片后进行推理|是|Pass|

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB