diff --git a/Ability/AccessPermission/AppScope/app.json5 b/Ability/AccessPermission/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5bb3dd05a4bb9b30d8dbad1876998a92604f4df8 --- /dev/null +++ b/Ability/AccessPermission/AppScope/app.json5 @@ -0,0 +1,13 @@ +{ + "app": { + "bundleName": "com.example.helloworld0218", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true, + "minAPIVersion": 9, + "targetAPIVersion": 9 + } +} diff --git a/Ability/AccessPermission/AppScope/resources/base/element/string.json b/Ability/AccessPermission/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..5e90218e713a1fab45130d25f6a162c03d31dfb1 --- /dev/null +++ b/Ability/AccessPermission/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "AccessPermission" + } + ] +} diff --git a/Ability/AccessPermission/AppScope/resources/base/media/app_icon.png b/Ability/AccessPermission/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/Ability/AccessPermission/AppScope/resources/base/media/app_icon.png differ diff --git a/Ability/AccessPermission/README.md b/Ability/AccessPermission/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1985f6ae3b0cefdd09b3b20d88532cdb4d0ef9c7 --- /dev/null +++ b/Ability/AccessPermission/README.md @@ -0,0 +1,351 @@ +# 介绍 + +本篇Codelab实现了一个简单的动态权限申请示例。该示例采用基于TS扩展的声明式开发范式进行开发,需要使用OpenHarmony允许不同设备间的数据交换权限。 + +本篇Codelab主要讲述以下内容: + +- 如何配置动态权限。 +- 如何动态申请权限。 +- 如何查询应用是否允许某个权限。 +- 用户权限与系统权限的差异。 +- 如何通过首选项数据库保存、修改、查询数据。 + +最终效果图如下: + +![](figures/video1.gif) ![](figures/video2.gif) + +# 相关概念 + +- [权限类型说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#%E6%9D%83%E9%99%90%E7%B1%BB%E5%9E%8B%E8%AF%B4%E6%98%8E):根据授权方式的不同,权限类型可分为system\_grant(系统授权)和user\_grant(用户授权)。 +- [权限定义列表](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#%E6%9D%83%E9%99%90%E5%AE%9A%E4%B9%89%E5%88%97%E8%A1%A8):展示系统定义的权限信息列表。 +- [访问控制管理](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-abilityAccessCtrl.md#%E8%AE%BF%E9%97%AE%E6%8E%A7%E5%88%B6%E7%AE%A1%E7%90%86):获取访问控制模块对象,管理访问控制模块的实例。 +- [首选项](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-data-preferences.md):为应用提供key-value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。数据存储形式为键值对,键的类型为字符串型,值的存储数据类型包括数字型、字符型、布尔型。 + +# 搭建OpenHarmony环境 + +完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: + +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。 + + 以3.1版本为例: + + ![](figures/zh-cn_image_0000001214154402.png) + +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-standard-env-setup.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-standard-running-rk3568-burning.md) + +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E5%88%9B%E5%BB%BAets%E5%B7%A5%E7%A8%8B)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E4%BD%BF%E7%94%A8%E7%9C%9F%E6%9C%BA%E8%BF%90%E8%A1%8C%E5%BA%94%E7%94%A8)。 + +# 代码结构解读 + +![](figures/1.png) + +``` +└── ets // ets代码区 + └── Application + │ └── AbilityStage.ts // Hap包运行时类 + ├── MainAbility + │ └── MainAbility.ts // Ability,提供对Ability生命周期、上下文环境等调用管理 + │── model + │ └── RemoteDeviceModel.ets // 远程设备模型类 + └── pages + └── index.ets // 主页面 +``` + +# 相关权限 + +本篇Codelab需要在module.json5中配置如下权限: + +``` +"requestPermissions": [ + { + // 允许不同设备间的数据交换 + "name" : "ohos.permission.DISTRIBUTED_DATASYNC", + } +] +``` + +>![](public_sys-resources/icon-note.gif) **说明:** +>应用获取权限的流程取决于相应的权限类型: +>- 如果目标权限是system\_grant类型,开发者需要在module.json5文件中[声明目标权限](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-guidelines.md),系统会在安装应用时为其进行权限预授予。 +>- 如果目标权限是user\_grant类型,开发者需要先在module.json5文件中[声明目标权限](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-guidelines.md),然后运行时发送弹窗,请求用户授权。 +>- 本篇Codelab用user\_grant类型权限进行讲解,具体可参考[权限定义列表](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/accesstoken-overview.md#%E6%9D%83%E9%99%90%E5%AE%9A%E4%B9%89%E5%88%97%E8%A1%A8)。 + +# 总体流程 + +1. 用户进入程序主界面,不会弹出权限申请框。 +2. 点击【查询内网设备】按钮,查询首选项数据库中标识判断是否为第一次查询。 +3. 若为第一次查询,首选项数据库中该标识默认值为空,打开授权弹框(可点击【禁止】(权限未被允许)、【允许】(权限被允许)按钮设置权限)。 +4. 若不是第一次查询,查询是否已授权。已授权则打开设备列表弹框,禁止授权则打开无授权说明弹框。 +5. 在设备列表、无授权说明弹框中点击【确定】按钮,关闭弹框,流程结束。 + +![](figures/1-0.png) + +# 界面设计 + +1. 程序主界面中“授权状态”默认为“未授权”,当授权允许之后,“授权状态”更改为“已授权”,如下图所示: + + ![](figures/1-1.png) ![](figures/2.png) + +2. 弹框界面分为:授权弹框、设备列表弹框(有数据)、设备列表弹框(无数据)、无权限说明弹框。依次如下图所示: + + ![](figures/3.png) ![](figures/4.png) ![](figures/6.png) ![](figures/5.png) + +# 逻辑说明 + +点击【查询内网设备】按钮,首先查询首选项数据库的requestPermissionFlag字段是否有值,若为空(未进行过授权操作)打开权限设置弹框,若有值(进行过授权操作)则判断是否有权限,若有权限则打开设备列表弹框,若无权限则打开无权限说明弹框。 + +1. 点击【查询内网设备】按钮,判断是否第一次查询,流程图如下所示: + + ![](figures/f1.png) + + 从数据库中获得是否第一次查询标识,示例代码如下: + + ``` + globalThis.getData = (() => { + let promise = data_preferences.getPreferences(this.context, 'mystore') + return promise + }) + ``` + +2. 若是第一次查询,流程图如下所示: + + ![](figures/f2.png) + + 打开权限设置弹框,对权限进行【禁止】或【允许】操作,并将数据库中是否操作过权限字段设置为true,示例代码如下: + + ``` + globalThis.requestPermission = (() => { + console.log("AccessPermission[MainAbility] request permissions from user") + this.context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'],(result) => { + // 判断是否授权,用于界面展示 + globalThis.judgePermission() + // 设置已进行授权操作 + globalThis.putData(true) + console.log('requestPermissionsFromUserResult:' + JSON.stringify(result)); + }); + }) + + globalThis.putData = ((requestPermissionFlag: boolean) => { + let promise = data_preferences.getPreferences(this.context, 'mystore') + promise.then((preferences) => { + let promisePut = preferences.put('requestPermissionFlag', requestPermissionFlag) + promisePut.then(() => { + console.info("Put the value of startup successfully.") + }).catch((err) => { + console.info("Put the value of startup failed, err: " + err) + }) + }).catch((err) => { + console.info("Get the preferences failed, err: " + err) + }) + }) + ``` + +3. 若不是第一次查询(进行过授权操作),则判断是否已授权,流程图如下所示: + + ![](figures/f3.png) + + 示例代码如下: + + ``` + let promiseGet = preferences.get('requestPermissionFlag', false) + promiseGet.then((value) => { + if(value) { + // 进行过授权操作,判断是否授权 + globalThis.checkPermission().then(res => { + if (res == globalThis.permissionGranted) { + // 有权限,查询内网设备 + ... + this.dialogController.open(); + } else { + // 无权限,给出提示 + ... + } + }) + } else { + // 未进行过授权操作,弹出权限申请框 + globalThis.requestPermission() + } + + // 检查是否有权限 + globalThis.checkPermission = (async() => { + console.info('AccessPermission[MainAbility] grantPermission') + // 需要校验的权限 + var permissionNameUser = "ohos.permission.DISTRIBUTED_DATASYNC"; + var bundleFlag = 0; + // 要校验的目标应用的身份标识 + var tokenID = undefined; + // userID值,默认100 + var userID = 100; + // 获取应用信息 + var appInfo = await bundle.getApplicationInfo('com.example.helloworld0218', bundleFlag, userID) + tokenID = appInfo.accessTokenId; + console.log("AccessPermission[MainAbility] accessTokenId:" + appInfo.accessTokenId) + // 获取访问控制模块对象 + var atManager = abilityAccessCtrl.createAtManager(); + // 进行权限校验,0有权限,-1无权限 + var result = await atManager.verifyAccessToken(tokenID, permissionNameUser) + console.log("AccessPermission[MainAbility] result:" + result) + return result + }) + ``` + +4. 若已授权,则打开设备列表弹框,流程图如下所示: + + ![](figures/f4.png) + + 设备列表弹框,示例代码如下: + + ``` + @CustomDialog + struct DialogDeviceList { + controller: CustomDialogController + action: () => void; + build() { + Column() { + Text('设备列表').fontSize(20).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + Divider().width('90%').margin({top: 10, bottom: 10}) + Column() { + if(deviceListGlobal.length == 0) { + Text('未查询到设备') + .width('100%') + .height(100) + .fontSize(16) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0xFFFFFF) + } else { + List({ space: 20, initialIndex: 0 }) { + ForEach(deviceListGlobal, (item) => { + ListItem() { + Column() { + // 设备名称 + Row() { + Text('name: ') + .fontSize(20) + .textAlign(TextAlign.Center) + Text('' + item.name) + .fontSize(20) + .textAlign(TextAlign.Center) + }.width('100%') + // 设备id + Row() { + Text('deviceId: ') + .fontSize(20) + .textAlign(TextAlign.Center) + Text('' + item.id) + .fontSize(20) + .textAlign(TextAlign.Center) + .textOverflow({overflow: TextOverflow.Ellipsis}) + }.width('100%') + } + .justifyContent(FlexAlign.Start) + .backgroundColor('#E2E2E2') + .borderRadius(10) + } + }, item => item.id) + } + .listDirection(Axis.Vertical) // 排列方向 + .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 10, endMargin: 10 }) // 每行之间的分界线 + .edgeEffect(EdgeEffect.None) // 滑动到边缘无效果 + .chainAnimation(false) // 联动特效关闭 + .width('90%').margin({bottom: 10}) + } + }.flexGrow(1) + Divider().width('90%').margin({top: 10}) + Row() { + Text('确定') + .fontSize(15) + .width('50%') + .textAlign(TextAlign.Center) + .fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + }.margin({top: 20, bottom: 10}) + } + } + } + ``` + + 创建设备管理器,示例代码如下: + + ``` + deviceManager.createDeviceManager('com.example.helloworld0218', (error, value) => { + ... + // 获取设备管理器并保存 + self.deviceManager = value; + // 注册设备列表 + self.registerDeviceListCallback_(callback); + }); + ``` + + 获取设备集合,示例代码如下: + + ``` + var list = this.deviceManager.getTrustedDeviceListSync(); + console.info('AccessPermission[RemoteDeviceModel] getTrustedDeviceListSync end, deviceList=' + JSON.stringify(list)); + if (typeof (list) != 'undefined' && typeof (list.length) != 'undefined') { + this.deviceList = list; + } + ``` + + 监听设备状态改变,示例代码如下: + + ``` + this.deviceManager.on('deviceFound', (data) => { + console.info('AccessPermission[RemoteDeviceModel] deviceFound data=' + JSON.stringify(data)); + console.info('AccessPermission[RemoteDeviceModel] deviceFound self.deviceList=' + self.deviceList); + console.info('AccessPermission[RemoteDeviceModel] deviceFound self.deviceList.length=' + self.deviceList.length); + for (var i = 0; i < self.discoverList.length; i++) { + if (self.discoverList[i].deviceId === data.device.deviceId) { + console.info('AccessPermission[RemoteDeviceModel] device founded, ignored'); + return; + } + } + self.discoverList[self.discoverList.length] = data.device; + self.callback(); + }); + ``` + +5. 若禁止权限,则打开无权限说明弹框,流程图如下所示: + + ![](figures/f5.png) + + 示例代码如下: + + ``` + // 未申请权限弹框 + @CustomDialog + struct DialogHints { + controller: CustomDialogController; + action: () => void; + build() { + Column(){ + Text('权限未申请,不能进行请求配对操作!').fontSize(20).width('90%').textAlign(TextAlign.Center).margin({top: 10}) + Text('如需重新申请权限,请在“设置 -> 应用 -> 应用管理 -> 应用名 -> 存储 -> 删除数据、清空缓存”').fontSize(20).width('90%').textAlign(TextAlign.Center).margin({top: 10}) + Divider().width('90%').margin({top: 10}) + Row() { + Text('确定').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + }.margin({top: 20, bottom: 10}) + }.width('100%') + } + } + ``` + +# 恭喜您 + +目前你已经成功完成了Codelab并且学到了: + +- 如何配置动态权限。 +- 如何动态申请权限。 +- 如何查询应用是否允许某个权限。 +- 用户权限与系统权限的差异。 +- 如何通过首选项数据库保存、修改、查询数据。 \ No newline at end of file diff --git a/Ability/AccessPermission/build-profile.json5 b/Ability/AccessPermission/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a94fd2e877f856970e3a9b16d914b7292a40ccbd --- /dev/null +++ b/Ability/AccessPermission/build-profile.json5 @@ -0,0 +1,28 @@ +{ + "app": { + "signingConfigs": [ + ], + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default", + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Ability/AccessPermission/entry/build-profile.json5 b/Ability/AccessPermission/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7dc37bb919dada5132609c409200db266559004f --- /dev/null +++ b/Ability/AccessPermission/entry/build-profile.json5 @@ -0,0 +1,13 @@ +{ + "apiType": 'stageMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/Ability/AccessPermission/entry/hvigorfile.js b/Ability/AccessPermission/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..d7720ee6a7aad5c617d1fd2f6fc8c87067bfa32c --- /dev/null +++ b/Ability/AccessPermission/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/Ability/AccessPermission/entry/package.json b/Ability/AccessPermission/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c4e988f30f2ec9e3430a4d0c8f05e89fabbc2659 --- /dev/null +++ b/Ability/AccessPermission/entry/package.json @@ -0,0 +1,13 @@ +{ + "name": "entry", + "version": "1.0.0", + "ohos": { + "org": "huawei", + "buildTool": "hvigor", + "directoryLevel": "module" + }, + "description": "example description", + "repository": {}, + "license": "ISC", + "dependencies": {} +} diff --git a/Ability/AccessPermission/entry/src/main/ets/Application/AbilityStage.ts b/Ability/AccessPermission/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f96918c937982a919a3d818c59b58c0b48839c9 --- /dev/null +++ b/Ability/AccessPermission/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 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 AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/Ability/AccessPermission/entry/src/main/ets/MainAbility/MainAbility.ts b/Ability/AccessPermission/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..0875cd94c0d9741c3c5de69e5af4641a1ca37431 --- /dev/null +++ b/Ability/AccessPermission/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021 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 Ability from '@ohos.application.Ability' +import abilityAccessCtrl from '@ohos.abilityAccessCtrl' +import bundle from '@ohos.bundle' +import data_preferences from '@ohos.data.preferences' + +export default class MainAbility extends Ability { + + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + + windowStage.setUIContent(this.context, "pages/index", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + + // 检查是否有权限 + globalThis.checkPermission = (async() => { + console.info('AccessPermission[MainAbility] grantPermission') + // 需要校验的权限 + var permissionNameUser = "ohos.permission.DISTRIBUTED_DATASYNC"; + var bundleFlag = 0; + // 要校验的目标应用的身份标识 + var tokenID = undefined; + // userID值,默认100 + var userID = 100; + // 获取应用信息 + var appInfo = await bundle.getApplicationInfo('com.example.helloworld0218', bundleFlag, userID) + tokenID = appInfo.accessTokenId; + console.log("AccessPermission[MainAbility] accessTokenId:" + appInfo.accessTokenId) + // 获取访问控制模块对象 + var atManager = abilityAccessCtrl.createAtManager(); + // 进行权限校验,0有权限,-1无权限 + var result = await atManager.verifyAccessToken(tokenID, permissionNameUser) + console.log("AccessPermission[MainAbility] result:" + result) + return result + }) + + // 已授权权限标识 + globalThis.permissionGranted = abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED + + // 申请权限 + globalThis.requestPermission = (() => { + console.log("AccessPermission[MainAbility] request permissions from user") + this.context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'],(result) => { + // 判断是否授权,用于界面展示 + globalThis.judgePermission() + // 设置已进行授权操作 + globalThis.putData(true) + console.log('requestPermissionsFromUserResult:' + JSON.stringify(result)); + }); + }) + + // 首选项,保存数据:key: requestPermissionFlag,value:requestPermissionFlag(boolean值) + globalThis.putData = ((requestPermissionFlag: boolean) => { + let promise = data_preferences.getPreferences(this.context, 'mystore') + promise.then((preferences) => { + let promisePut = preferences.put('requestPermissionFlag', requestPermissionFlag) + promisePut.then(() => { + console.info("Put the value of startup successfully.") + }).catch((err) => { + console.info("Put the value of startup failed, err: " + err) + }) + }).catch((err) => { + console.info("Get the preferences failed, err: " + err) + }) + }) + + // 首选项,获取数据 + globalThis.getData = (() => { + let promise = data_preferences.getPreferences(this.context, 'mystore') + return promise + }) + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/Ability/AccessPermission/entry/src/main/ets/model/RemoteDeviceModel.ets b/Ability/AccessPermission/entry/src/main/ets/model/RemoteDeviceModel.ets new file mode 100644 index 0000000000000000000000000000000000000000..8f18e844f849dd189b54f366524b04648edb1963 --- /dev/null +++ b/Ability/AccessPermission/entry/src/main/ets/model/RemoteDeviceModel.ets @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2021 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 deviceManager from '@ohos.distributedHardware.deviceManager'; + +var SUBSCRIBE_ID = 100; + +// 远程设备模型类 +export default class RemoteDeviceModel { + // 设备集合:deviceManager.getTrustedDeviceListSync + deviceList = []; + // 设备集合:deviceManager.on + discoverList = []; + // 回调index.ets中的callback方法 + callback; + // 设备管理器 + deviceManager; + // 构造函数 + constructor() { + } + + // 发起请求配对时调用此方法(index.ets调用) + registerDeviceListCallback(callback) { + if (typeof (this.deviceManager) === 'undefined') { + console.log('AccessPermission[RemoteDeviceModel] deviceManager.createDeviceManager begin'); + let self = this; + // 创建设备管理器 + deviceManager.createDeviceManager('com.example.helloworld0218', (error, value) => { + if (error) { + console.error('createDeviceManager failed.'); + return; + } + // 获取设备管理器并保存 + self.deviceManager = value; + // 注册设备列表 + self.registerDeviceListCallback_(callback); + console.log('AccessPermission[RemoteDeviceModel] createDeviceManager callback returned, error=' + error + ' value=' + value); + }); + console.log('AccessPermission[RemoteDeviceModel] deviceManager.createDeviceManager end'); + } else { + this.registerDeviceListCallback_(callback); + } + } + + // 注册设备列表 + registerDeviceListCallback_(callback) { + console.info('AccessPermission[RemoteDeviceModel] registerDeviceListCallback'); + this.callback = callback; + if (this.deviceManager == undefined) { + console.error('AccessPermission[RemoteDeviceModel] deviceManager has not initialized'); + this.callback(); + return; + } + + console.info('AccessPermission[RemoteDeviceModel] getTrustedDeviceListSync begin'); + // 获取设备集合 + var list = this.deviceManager.getTrustedDeviceListSync(); + console.info('AccessPermission[RemoteDeviceModel] getTrustedDeviceListSync end, deviceList=' + JSON.stringify(list)); + if (typeof (list) != 'undefined' && typeof (list.length) != 'undefined') { + this.deviceList = list; + } + + this.callback(); + console.info('AccessPermission[RemoteDeviceModel] callback finished'); + + let self = this; + // 监听设备状态 + this.deviceManager.on('deviceStateChange', (data) => { + console.info('AccessPermission[RemoteDeviceModel] deviceStateChange data=' + JSON.stringify(data)); + switch (data.action) { + case 0: + self.deviceList[self.deviceList.length] = data.device; + console.info('AccessPermission[RemoteDeviceModel] online, updated device list=' + JSON.stringify(self.deviceList)); + break; + case 2: + if (self.deviceList.length > 0) { + for (var i = 0; i < self.deviceList.length; i++) { + if (self.deviceList[i].deviceId === data.device.deviceId) { + self.deviceList[i] = data.device; + break; + } + } + } + console.info('AccessPermission[RemoteDeviceModel] change, updated device list=' + JSON.stringify(self.deviceList)); + self.callback(); + break; + case 1: + if (self.deviceList.length > 0) { + var list = []; + for (var i = 0; i < self.deviceList.length; i++) { + if (self.deviceList[i].deviceId != data.device.deviceId) { + list[i] = data.device; + } + } + self.deviceList = list; + } + console.info('AccessPermission[RemoteDeviceModel] offline, updated device list=' + JSON.stringify(data.device)); + self.callback(); + break; + default: + break; + } + }); + this.deviceManager.on('deviceFound', (data) => { + console.info('AccessPermission[RemoteDeviceModel] deviceFound data=' + JSON.stringify(data)); + console.info('AccessPermission[RemoteDeviceModel] deviceFound self.deviceList=' + self.deviceList); + console.info('AccessPermission[RemoteDeviceModel] deviceFound self.deviceList.length=' + self.deviceList.length); + for (var i = 0; i < self.discoverList.length; i++) { + if (self.discoverList[i].deviceId === data.device.deviceId) { + console.info('AccessPermission[RemoteDeviceModel] device founded, ignored'); + return; + } + } + self.discoverList[self.discoverList.length] = data.device; + self.callback(); + }); + this.deviceManager.on('discoverFail', (data) => { + console.info('AccessPermission[RemoteDeviceModel] discoverFail data=' + JSON.stringify(data)); + }); + this.deviceManager.on('serviceDie', () => { + console.error('AccessPermission[RemoteDeviceModel] serviceDie'); + }); + + SUBSCRIBE_ID = Math.floor(65536 * Math.random()); + var info = { + subscribeId: SUBSCRIBE_ID, + mode: 0xAA, + medium: 2, + freq: 2, + isSameAccount: false, + isWakeRemote: true, + capability: 0 + }; + console.info('AccessPermission[RemoteDeviceModel] startDeviceDiscovery ' + SUBSCRIBE_ID); + this.deviceManager.startDeviceDiscovery(info); + } + + // 取消设备注册 + unregisterDeviceListCallback() { + console.info('AccessPermission[RemoteDeviceModel] stopDeviceDiscovery ' + SUBSCRIBE_ID); + this.deviceManager.stopDeviceDiscovery(SUBSCRIBE_ID); + this.deviceManager.off('deviceStateChange'); + this.deviceManager.off('deviceFound'); + this.deviceManager.off('discoverFail'); + this.deviceManager.off('serviceDie'); + this.deviceList = []; + } +} \ No newline at end of file diff --git a/Ability/AccessPermission/entry/src/main/ets/pages/index.ets b/Ability/AccessPermission/entry/src/main/ets/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..a03dd9ec72a9e5422b886171495eb03c78cecb16 --- /dev/null +++ b/Ability/AccessPermission/entry/src/main/ets/pages/index.ets @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2021 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 RemoteDeviceModel from '../model/RemoteDeviceModel' + +// 实例化RemoteDeviceModel +let remoteDeviceModel = new RemoteDeviceModel(); +// 设备列表集合 +let deviceListGlobal = []; + +@Entry +@Component +struct Index { + + @State permissionDescribe: string = '未授权' + + // 未设置权限提示弹框 + dialogHints : CustomDialogController = new CustomDialogController({ + builder: DialogHints({action: this.onAccept}), + autoCancel: true + }); + + // 设备列表弹框 + dialogController: CustomDialogController = new CustomDialogController({ + builder: DialogDeviceList({action: this.onAccept}), + autoCancel: true + }) + + onAccept() { + } + + build() { + Row() { + Column() { + Text('授权状态:' + this.permissionDescribe) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Button('查询内网设备', { type: ButtonType.Capsule, stateEffect: true }) + .backgroundColor(0x317aff) + .fontSize(40) + .height(50) + .onClick(() => { + // 判断是否进行过授权操作 + globalThis.getData().then((preferences) => { + // 获取key:requestPermissionFlag的值,false未进行过操作、true进行过操作 + let promiseGet = preferences.get('requestPermissionFlag', false) + promiseGet.then((value) => { + if(value) { + // 进行过授权操作,判断是否授权 + globalThis.checkPermission().then(res => { + if (res == globalThis.permissionGranted) { + // 有权限,查询内网设备 + remoteDeviceModel.registerDeviceListCallback(() => { + this.callBack() + }) + this.dialogController.open(); + } else { + // 无权限,给出提示 + this.dialogHints.open() + } + }) + } else { + // 未进行过授权操作,弹出权限申请框 + globalThis.requestPermission() + } + }).catch((err) => { + console.info("Get the value of startup failed, err: " + err) + }) + }) + }) + .margin({top: 50}) + } + .width('100%') + } + .height('100%') + } + + // 查询到设备后回调此函数,放到列表数据中 + callBack() { + console.info('AccessPermission[IndexPage] registerDeviceListCallback, callback entered'); + var list = []; + var deviceList; + if (remoteDeviceModel.discoverList.length > 0) { + deviceList = remoteDeviceModel.discoverList; + } else { + deviceList = remoteDeviceModel.deviceList; + } + console.info('AccessPermission[IndexPage] on remote device updated, count=' + deviceList.length); + for (var i = 0; i < deviceList.length; i++) { + console.info('AccessPermission[IndexPage] device ' + i + '/' + deviceList.length + ' deviceId=' + + deviceList[i].deviceId + ' deviceName=' + deviceList[i].deviceName ); + list.push({ + name: deviceList[i].deviceName, + id: deviceList[i].deviceId + }); + } + deviceListGlobal = list; + console.info('AccessPermission[IndexPage] list deviceId' + JSON.stringify(deviceListGlobal)); + } + + aboutToAppear(){ + // 进入应用,查询是否进行过授权操作(包括:禁止操作、允许操作) + globalThis.getData().then((preferences) => { + // 获取key:requestPermissionFlag的值,false未进行过操作、true进行过操作 + let promiseGet = preferences.get('requestPermissionFlag', false) + promiseGet.then((value) => { + if(value) { + // 进行过授权操作,判断是否有权限 + globalThis.checkPermission().then(res => { + if(res != globalThis.permissionGranted) { + // 未授权 + this.permissionDescribe = '未授权' + } else { + // 已授权 + this.permissionDescribe = '已授权' + } + }) + } else { + // 未进行过授权操作,将requestPermissionFlag设置为false + globalThis.putData(false) + } + }).catch((err) => { + console.info("Get the value of startup failed, err: " + err) + }) + }).catch((err) => { + console.info("Get the preferences failed, err: " + err) + }) + + // 授权拒绝、通过时调用,用于判断界面展示是否授权 + globalThis.judgePermission = (() => { + globalThis.checkPermission().then(res => { + if(res != globalThis.permissionGranted) { + this.permissionDescribe = '未授权' + } else { + this.permissionDescribe = '已授权' + } + }) + }) + } +} + +// 未申请权限弹框 +@CustomDialog +struct DialogHints { + controller: CustomDialogController; + action: () => void; + build() { + Column(){ + Text('权限未申请,不能进行请求配对操作!').fontSize(20).width('90%').textAlign(TextAlign.Center).margin({top: 10}) + Text('如需重新申请权限,请在“设置 -> 应用 -> 应用管理 -> 应用名 -> 存储 -> 删除数据、清空缓存”').fontSize(20).width('90%').textAlign(TextAlign.Center).margin({top: 10}) + Divider().width('90%').margin({top: 10}) + Row() { + Text('确定').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + }.margin({top: 20, bottom: 10}) + }.width('100%') + } +} + +// 设备列表弹框 +@CustomDialog +struct DialogDeviceList { + controller: CustomDialogController + action: () => void; + build() { + Column() { + Text('设备列表').fontSize(20).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + Divider().width('90%').margin({top: 10, bottom: 10}) + Column() { + if(deviceListGlobal.length == 0) { + Text('未查询到设备') + .width('100%') + .height(100) + .fontSize(16) + .textAlign(TextAlign.Center) + .borderRadius(10) + .backgroundColor(0xFFFFFF) + } else { + List({ space: 20, initialIndex: 0 }) { + ForEach(deviceListGlobal, (item) => { + ListItem() { + Column() { + // 设备名称 + Row() { + Text('name: ') + .fontSize(20) + .textAlign(TextAlign.Center) + Text('' + item.name) + .fontSize(20) + .textAlign(TextAlign.Center) + }.width('100%') + // 设备id + Row() { + Text('deviceId: ') + .fontSize(20) + .textAlign(TextAlign.Center) + Text('' + item.id) + .fontSize(20) + .textAlign(TextAlign.Center) + .textOverflow({overflow: TextOverflow.Ellipsis}) + }.width('100%') + } + .justifyContent(FlexAlign.Start) + .backgroundColor('#E2E2E2') + .borderRadius(10) + } + }, item => item.id) + } + .listDirection(Axis.Vertical) // 排列方向 + .divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 10, endMargin: 10 }) // 每行之间的分界线 + .edgeEffect(EdgeEffect.None) // 滑动到边缘无效果 + .chainAnimation(false) // 联动特效关闭 + .width('90%').margin({bottom: 10}) + } + }.flexGrow(1) + Divider().width('90%').margin({top: 10}) + Row() { + Text('确定') + .fontSize(15) + .width('50%') + .textAlign(TextAlign.Center) + .fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + }.margin({top: 20, bottom: 10}) + } + } +} diff --git a/Ability/AccessPermission/entry/src/main/module.json5 b/Ability/AccessPermission/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..350d9743127de1d5e9354447232dcbf9b4db2b46 --- /dev/null +++ b/Ability/AccessPermission/entry/src/main/module.json5 @@ -0,0 +1,44 @@ +{ + "module": { + "requestPermissions": [ + { + // 允许不同设备间的数据交换 + "name" : "ohos.permission.DISTRIBUTED_DATASYNC", + } + ], + "name": "entry", + "type": "entry", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "launchType":"singleton", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/Ability/AccessPermission/entry/src/main/resources/base/element/string.json b/Ability/AccessPermission/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..490210a3908f47722dc942d49dacc98b97669a5f --- /dev/null +++ b/Ability/AccessPermission/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/Ability/AccessPermission/entry/src/main/resources/base/media/icon.png b/Ability/AccessPermission/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/Ability/AccessPermission/entry/src/main/resources/base/media/icon.png differ diff --git a/Ability/AccessPermission/entry/src/main/resources/base/profile/main_pages.json b/Ability/AccessPermission/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..feec276e105eeb8d621c20aaf838f318b0a94150 --- /dev/null +++ b/Ability/AccessPermission/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/index" + ] +} diff --git a/Ability/AccessPermission/figures/1-0.png b/Ability/AccessPermission/figures/1-0.png new file mode 100644 index 0000000000000000000000000000000000000000..2fde136655eefa82c071e2e64164686721083e72 Binary files /dev/null and b/Ability/AccessPermission/figures/1-0.png differ diff --git a/Ability/AccessPermission/figures/1-1.png b/Ability/AccessPermission/figures/1-1.png new file mode 100644 index 0000000000000000000000000000000000000000..9dc83cd4eb227bc9d40adad9d368c0b41cfd26dd Binary files /dev/null and b/Ability/AccessPermission/figures/1-1.png differ diff --git a/Ability/AccessPermission/figures/1.png b/Ability/AccessPermission/figures/1.png new file mode 100644 index 0000000000000000000000000000000000000000..4523cb43fbd17617fb6da06c111b5da2bc943180 Binary files /dev/null and b/Ability/AccessPermission/figures/1.png differ diff --git a/Ability/AccessPermission/figures/2.png b/Ability/AccessPermission/figures/2.png new file mode 100644 index 0000000000000000000000000000000000000000..bd1314b656b7fe2352c49334e1d93ff9efdf69f6 Binary files /dev/null and b/Ability/AccessPermission/figures/2.png differ diff --git a/Ability/AccessPermission/figures/3.png b/Ability/AccessPermission/figures/3.png new file mode 100644 index 0000000000000000000000000000000000000000..ba398670364dbff5a17991a3323ed92a9c0a0c27 Binary files /dev/null and b/Ability/AccessPermission/figures/3.png differ diff --git a/Ability/AccessPermission/figures/4.png b/Ability/AccessPermission/figures/4.png new file mode 100644 index 0000000000000000000000000000000000000000..bbed0b1b7ef89998f017424907ea9135b605b5dc Binary files /dev/null and b/Ability/AccessPermission/figures/4.png differ diff --git a/Ability/AccessPermission/figures/5.png b/Ability/AccessPermission/figures/5.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f98790ccd8c90618e9e20cb0a7d7c025f5c904 Binary files /dev/null and b/Ability/AccessPermission/figures/5.png differ diff --git a/Ability/AccessPermission/figures/6.png b/Ability/AccessPermission/figures/6.png new file mode 100644 index 0000000000000000000000000000000000000000..1d32a84a7fe03f13e45a87dd71b4ef4bb7a8a262 Binary files /dev/null and b/Ability/AccessPermission/figures/6.png differ diff --git a/Ability/AccessPermission/figures/f1.png b/Ability/AccessPermission/figures/f1.png new file mode 100644 index 0000000000000000000000000000000000000000..428109c78a3bf91e8bf2d8ebeb99c75690a5d9ba Binary files /dev/null and b/Ability/AccessPermission/figures/f1.png differ diff --git a/Ability/AccessPermission/figures/f2.png b/Ability/AccessPermission/figures/f2.png new file mode 100644 index 0000000000000000000000000000000000000000..cab5f19a1a52b3bca18787addf96226f1a03f8c0 Binary files /dev/null and b/Ability/AccessPermission/figures/f2.png differ diff --git a/Ability/AccessPermission/figures/f3.png b/Ability/AccessPermission/figures/f3.png new file mode 100644 index 0000000000000000000000000000000000000000..24b3a7e228d6d04b8367a94af37f73f872ef77af Binary files /dev/null and b/Ability/AccessPermission/figures/f3.png differ diff --git a/Ability/AccessPermission/figures/f4.png b/Ability/AccessPermission/figures/f4.png new file mode 100644 index 0000000000000000000000000000000000000000..ae06ee5a2d80612a400bfebb46d28fb78556d4d7 Binary files /dev/null and b/Ability/AccessPermission/figures/f4.png differ diff --git a/Ability/AccessPermission/figures/f5.png b/Ability/AccessPermission/figures/f5.png new file mode 100644 index 0000000000000000000000000000000000000000..58f26c50ae4388707dfad2ed94824b15c30bc3a2 Binary files /dev/null and b/Ability/AccessPermission/figures/f5.png differ diff --git a/Ability/AccessPermission/figures/video1.gif b/Ability/AccessPermission/figures/video1.gif new file mode 100644 index 0000000000000000000000000000000000000000..93880af4e7fb8dce31c3db7b404da54eb8a54ac2 Binary files /dev/null and b/Ability/AccessPermission/figures/video1.gif differ diff --git a/Ability/AccessPermission/figures/video2.gif b/Ability/AccessPermission/figures/video2.gif new file mode 100644 index 0000000000000000000000000000000000000000..3bf5a99feccdde7ab885be520324362b4a413412 Binary files /dev/null and b/Ability/AccessPermission/figures/video2.gif differ diff --git a/Ability/AccessPermission/figures/zh-cn_image_0000001214154402.png b/Ability/AccessPermission/figures/zh-cn_image_0000001214154402.png new file mode 100644 index 0000000000000000000000000000000000000000..9d752ff5311af2816bf898cb2c18ef33bf085726 Binary files /dev/null and b/Ability/AccessPermission/figures/zh-cn_image_0000001214154402.png differ diff --git a/Ability/AccessPermission/hvigorfile.js b/Ability/AccessPermission/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..5f2735e3deeaf655828407544bbed9365c258278 --- /dev/null +++ b/Ability/AccessPermission/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/Ability/AccessPermission/package.json b/Ability/AccessPermission/package.json new file mode 100644 index 0000000000000000000000000000000000000000..11fd7548d7aec24aed12bbb335306b287b4c9788 --- /dev/null +++ b/Ability/AccessPermission/package.json @@ -0,0 +1,17 @@ +{ + "name": "accesspermission", + "version": "1.0.0", + "ohos": { + "org": "huawei", + "buildTool": "hvigor", + "directoryLevel": "project" + }, + "description": "example description", + "repository": {}, + "license": "ISC", + "dependencies": { + "hypium": "^1.0.0", + "@ohos/hvigor": "1.0.6", + "@ohos/hvigor-ohos-plugin": "1.0.6" + } +} diff --git a/Ability/AccessPermission/public_sys-resources/icon-caution.gif b/Ability/AccessPermission/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/Ability/AccessPermission/public_sys-resources/icon-caution.gif differ diff --git a/Ability/AccessPermission/public_sys-resources/icon-danger.gif b/Ability/AccessPermission/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/Ability/AccessPermission/public_sys-resources/icon-danger.gif differ diff --git a/Ability/AccessPermission/public_sys-resources/icon-note.gif b/Ability/AccessPermission/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/Ability/AccessPermission/public_sys-resources/icon-note.gif differ diff --git a/Ability/AccessPermission/public_sys-resources/icon-notice.gif b/Ability/AccessPermission/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/Ability/AccessPermission/public_sys-resources/icon-notice.gif differ diff --git a/Ability/AccessPermission/public_sys-resources/icon-tip.gif b/Ability/AccessPermission/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/Ability/AccessPermission/public_sys-resources/icon-tip.gif differ diff --git a/Ability/AccessPermission/public_sys-resources/icon-warning.gif b/Ability/AccessPermission/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/Ability/AccessPermission/public_sys-resources/icon-warning.gif differ diff --git a/Ability/PageAbility/entry/.gitignore b/Ability/PageAbility/entry/.gitignore deleted file mode 100644 index 7d5b7a94f4dcf381f03ff21f28f8a2494b58023f..0000000000000000000000000000000000000000 --- a/Ability/PageAbility/entry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/build -/node_modules diff --git a/Ability/PageAbility/entry/build.gradle b/Ability/PageAbility/entry/build.gradle deleted file mode 100644 index 1587dd1948941f3eaaf092ae6cae7969cb6895ff..0000000000000000000000000000000000000000 --- a/Ability/PageAbility/entry/build.gradle +++ /dev/null @@ -1,21 +0,0 @@ -apply plugin: 'com.huawei.ohos.hap' -//For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510 -ohos { - compileSdkVersion 7 - defaultConfig { - compatibleSdkVersion 7 - } - buildTypes { - release { - proguardOpt { - proguardEnabled false - rulesFiles 'proguard-rules.pro' - } - } - } -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar', '*.har']) - testImplementation 'junit:junit:4.13.1' -} diff --git a/Ability/PageAbility/entry/proguard-rules.pro b/Ability/PageAbility/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/Ability/PageAbility/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/AppScope/app.json5 b/CommonEventAndNotification/AlarmClock/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5bb3dd05a4bb9b30d8dbad1876998a92604f4df8 --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/AppScope/app.json5 @@ -0,0 +1,13 @@ +{ + "app": { + "bundleName": "com.example.helloworld0218", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true, + "minAPIVersion": 9, + "targetAPIVersion": 9 + } +} diff --git a/CommonEventAndNotification/AlarmClock/AppScope/resources/base/element/string.json b/CommonEventAndNotification/AlarmClock/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..0135ac818a531d0adc91a4f9f9d765deed56c748 --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "AlarmClock" + } + ] +} diff --git a/CommonEventAndNotification/AlarmClock/AppScope/resources/base/media/app_icon.png b/CommonEventAndNotification/AlarmClock/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/CommonEventAndNotification/AlarmClock/AppScope/resources/base/media/app_icon.png differ diff --git a/CommonEventAndNotification/AlarmClock/README.md b/CommonEventAndNotification/AlarmClock/README.md new file mode 100644 index 0000000000000000000000000000000000000000..041102cb4fb7bbb7141c53a333f1d3725f6381bd --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/README.md @@ -0,0 +1,857 @@ +# 介绍 + +本篇Codelab是基于TS扩展的声明式开发范式及OpenHarmony的后台代理提醒能力实现的一个简单闹钟的示例。 + +本篇Codelab实现如下功能: + +- 展示指针表盘和数字时间。 +- 添加、修改和删除闹钟。 +- 展示闹钟列表,并可打开和关闭单个闹钟。 +- 闹钟到设定的时间后进行后台代理提醒。 +- 闹钟定时数据保存到首选项数据库中。 + +最终效果图如下: + +![](figures/1.png) ![](figures/2.png) ![](figures/3.png) ![](figures/4.png) + +# 相关概念 + +- [Canvas](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-canvas-canvas.md):提供画布组件,用于自定义绘制图形。 +- [后台代理提醒](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-reminderAgent.md):发布一个后台代理提醒。 +- [TextPicker](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-textpicker.md):文本类滑动选择器组件。 +- [CustomDialog](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ts-component-based-customdialog-0000001192355895):@CustomDialog装饰器用于装饰自定义弹窗。 +- [首选项](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-data-preferences.md#flush):为应用提供key-value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。 + +# 搭建OpenHarmony环境 + +完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: + +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。 + + 以3.1版本为例: + + ![](figures/zh-cn_image_0000001214154402.png) + +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-standard-env-setup.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-standard-running-rk3568-burning.md) + +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E5%88%9B%E5%BB%BAets%E5%B7%A5%E7%A8%8B)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E4%BD%BF%E7%94%A8%E7%9C%9F%E6%9C%BA%E8%BF%90%E8%A1%8C%E5%BA%94%E7%94%A8)。 + +# 代码结构解读 + +![](figures/目录.png) + +- AppScope:App作用域目录。 +- entry/src/main/ets:程序目录。 + - Application:stage模型目录。 + - AbilityStage.ts:stage模型文件。 + + - images:本篇Codelab对应demo中用到的图标。 + - MainAbility:程序入口目录。 + - MainAbility.ts:程序入口类。 + + - pages:界面目录。 + - detail.ets:详情界面。 + - index.ets:主界面。 + + +- entry/src/main/resources:资源文件目录。 +- entry/src/main/module.json5:应用配置文件。 +- entry/src/build-profile.json5:应用构建配置文件。 +- build-profile.json5:版本信息配置文件。 + +# 相关权限 + +本篇Codelab需要在module.json5中配置如下权限: + +``` +"requestPermissions" :[ + { + // 后台代理提醒权限 + "name": "ohos.permission.PUBLISH_AGENT_REMINDER" + } +] +``` + +# 闹钟主界面 + +闹钟界面包括当前时间、闹钟列表、添加闹钟子组件,具体包括以下模块: + +1. Canvas组件,默认展示指针表盘,指针表盘与数字时钟可通过点击屏幕来回切换。如下图所示: + + ![](figures/video1.gif) + + 在index.ets中获取屏幕宽高,根据屏幕宽高设置Canvas画布尺寸,并将原点移到画布中间,示例代码如下: + + ``` + aboutToAppear(){ + // 从首选项数据库获取数据 + this.getDate() + // 获取屏幕宽高 + display.getDefaultDisplay((err, data) => { + if(err.code === 0) { + console.info('Failed to obtain the default display object. Code: ' + JSON.stringify(err)) + } + this.screenWidth = data.width + this.screenHeight = data.height + // 设置canvas尺寸,竖屏取值为宽高最小值的1/3,横屏取值为宽高最小值的1/4 + this.canvasOnScreenRatio = (this.screenWidth < this.screenHeight ? 3 : 4) + this.size = (this.screenWidth < this.screenHeight ? this.screenWidth : this.screenHeight) / this.canvasOnScreenRatio + // 重置原点到canvas画布中间 + this.context.translate(this.size, this.size / 2) + }); + } + ``` + + 在index.ets中初始化Canvas画布,并绑定指针表盘和数字时钟切换事件,示例代码如下: + + ``` + Canvas(this.context) + .height(this.size) + .aspectRatio(2.0) + .onReady(() =>{ + // 获取半径 + this.radius = this.size / 2 - 2.5 + var that = this + // 避免时钟闪现,先画一遍 + that.draw() + // 定时器 + this.interval = setInterval(function() { + that.draw() + }, 1000) + }) + .onClick(() => { + // 切换指针表盘和数字时钟 + this.showClock = !this.showClock + }) + ``` + + 在index.ets中利用Canvas画布组件绘制指针表盘和数字时钟,示例代码如下: + + ``` + // 开始绘制 + private draw(): void{ + // 清空绘制 + this.context.clearRect(-this.size, this.size / -2, this.size * 2, this.size) + // 获取当前时间 + let date = new Date() + if(this.showClock) { + // 画表盘 + this.drawDials() + // 画秒针 + this.drawSecond(date.getSeconds()) + // 画分针 + this.drawMinute(date.getMinutes(), date.getSeconds()) + // 画时针 + this.drawHour(date.getHours(), date.getMinutes()) + } else { + this.drawTime(date.getHours().toString(), date.getMinutes().toString(), date.getSeconds().toString()) + } + } + + // 画时间 + private drawTime(hour: string, minute: string, second: string): void{ + let time = this.fillZero(hour) + ':' + this.fillZero(minute) + ':' + this.fillZero(second) + this.context.save() + this.context.font = '100px' + this.context.beginPath() + this.context.textAlign = 'center' + this.context.fillText(time, 0, 0) + this.context.restore() + } + + // 补零:HH:mm:ss + private fillZero(val): string{ + var len = val.length; + while(len < 2) { + val = "0" + val; + len++; + } + return val; + } + + // 画表盘 + private drawDials(): void{ + // 画原点 + this.context.save() + this.context.beginPath() + this.context.arc(0, 0, 5, 0, Math.PI * 2) + this.context.fill() + this.context.stroke() + this.context.restore() + // 字体大小 + this.context.font = '20px' + // 画圆 + this.context.save() + this.context.lineWidth = 5 + this.context.beginPath() + this.context.arc(0, 0, this.radius, 0, 2 * Math.PI) + this.context.stroke() + this.context.restore() + + // 画刻度 + for (let n = 1; n <= 60; n++) { + // 从三点钟方向开始获取60个刻度的角度 + var theta = (n - 3) * (Math.PI * 2) / 60; + this.context.save() + // 刻度宽度为2 + this.context.lineWidth = 2 + this.context.beginPath() + // 刻度起始位置 + var x_move = this.radius * Math.cos(theta); + var y_move = this.radius * Math.sin(theta); + // 非整点刻度结束位置 + var x_to = (this.radius - 5) * Math.cos(theta); + var y_to = (this.radius - 5) * Math.sin(theta); + // 整点刻度 + if((n-3) % 5 == 0) { + //整点刻度宽度 + this.context.lineWidth = 3 + // 整点刻度结束位置 + x_to = (this.radius - 10) * Math.cos(theta); + y_to = (this.radius - 10) * Math.sin(theta); + // 整点时间位置 + var x_time = (this.radius - 25) * Math.cos(theta); + var y_time = (this.radius - 25) * Math.sin(theta); + // 绘制整点时间 + this.context.fillText(this.times[(n - 3) / 5] + '', x_time - 5, y_time + 3) + } + // 绘制刻度线 + this.context.moveTo(x_move, y_move) + this.context.lineTo(x_to, y_to) + this.context.stroke() + this.context.restore() + } + } + + // 画秒针 + private drawSecond(second: number): void{ + this.context.save() + this.context.fillStyle = 'red' + var theta = (second - 15) * 2 * Math.PI / 60; + this.context.rotate(theta) + this.context.beginPath() + this.context.moveTo(-15, -3); + this.context.lineTo(-15, 3); + this.context.lineTo(this.radius * 0.9, 1); + this.context.lineTo(this.radius * 0.9, -1); + this.context.fill(); + this.context.restore(); + } + + // 画分针 + private drawMinute(minute: number, second: number): void{ + this.context.save() + var theta = ((minute + second / 60 - 15) * 2 * Math.PI / 60) + this.context.rotate(theta) + this.context.beginPath() + this.context.moveTo(-15, -4); + this.context.lineTo(-15, 4); + this.context.lineTo(this.radius * 0.8, 1); + this.context.lineTo(this.radius * 0.8, -1); + this.context.fill(); + this.context.restore(); + } + + // 画时针 + private drawHour(hour:number, minute: number): void{ + this.context.save() + var theta = ((hour + minute / 60 - 3) * 2 * Math.PI / 12) + this.context.rotate(theta) + this.context.beginPath() + this.context.moveTo(-15, -5); + this.context.lineTo(-15, 5); + this.context.lineTo(this.radius * 0.5, 1); + this.context.lineTo(this.radius * 0.5, -1); + this.context.fill(); + this.context.restore(); + } + ``` + +2. 闹钟列表,展示已添加的闹钟信息,可对闹钟进行启停操作,点击闹钟可跳转到闹钟操作界面(修改和删除闹钟)。如下图所示: + + ![](figures/video2.gif) ![](figures/video3.gif) + + 在index.ets中添加闹钟列表子组件,并绑定启停、跳转事件,示例代码如下: + + ``` + List({ space: 10, initialIndex: 0 }) { + ForEach(this.clockItems.map((item, index) => { + return { i: index, data: item } + }), + (item, index) => { + ListItem() { + Stack({alignContent: Alignment.End}) { + Column() { + Row() { + Text(item.data.partition).fontSize(15) + Text(item.data.hour+ ':' + item.data.minute).fontSize(25).margin({left: 10}) + } + Row() { + Text(item.data.name).fontSize(15) + Text('不重复').fontSize(15).margin({left: 10}) + }.margin({top: 5}) + } + .width('100%') + .margin({left: 10}) + .alignItems(HorizontalAlign.Start) + Toggle({ type: ToggleType.Switch, isOn: item.data.open }) + .selectedColor(0x39a2db) + .switchPointColor(0xe5ffffff) + .onChange((isOn: boolean) => { + item.data.open = isOn + console.info('Component status:' + isOn) + // 关闭、打开闹钟 + this.modifyMsg = [isOn ? 0 : 2, index, item.data.reminderId] + this.resetAlarm() + }) + .width(30) + .aspectRatio(1.0) + } + .width('90%') + .height(60) + .backgroundColor('#E2E2E2') + .borderRadius(10) + }.width('100%') + .onClick(() => { + // 下标 + this.nowIndex = index + // 展示修改界面 + this.showIndex = false + }) + }, + item => item.data.name.toString()) + } + .listDirection(Axis.Vertical) // 排列方向 + .flexGrow(1) + .margin({top: 10}) + ``` + +3. 添加闹钟,点击界面底部闹钟添加按钮,跳转到闹钟操作界面(新增闹钟)。如下图所示: + + ![](figures/video1-0.gif) + + 在index.ets中为添加按钮绑定跳转事件,示例代码如下: + + ``` + Image('images/add.png') + .width(100) + .aspectRatio(1.0) + .margin({bottom: 10}) + .onClick(() => { + // 新增闹钟,值为-1 + this.nowIndex = -1 + // 展示新增闹钟界面 + this.showIndex = false + }).visibility(this.showIndex ? Visibility.Visible : Visibility.Hidden) + ``` + +4. 后台代理提醒,根据闹钟列表中的数据来设置(启停)闹钟实例。 + + 观测闹钟数据变化(新增、修改、删除、启停),示例代码如下: + + ``` + @State @Watch("resetAlarm") clockItems: Array = [] // 闹钟-定时 + + // 观测闹钟数据变化 + private resetAlarm(): void{ + let opeNum = this.modifyMsg[0] + let index = this.modifyMsg[1] + let reminderId = this.modifyMsg[2] + if(opeNum == 0) { + // 新增 + reminderAgent.publishReminder(this.addAlarm(this.clockItems[index], index), (err, reminderId) =>{ + if(err.code == 0) { + // 设置reminderId + this.clockItems[index].reminderId = reminderId + }else { + console.info("publishReminder" + index + "error: " + err.message) + } + }); + } else if(opeNum == 1) { + // 修改,先停止原先的闹钟再开启修改后的 + reminderAgent.cancelReminder(reminderId) + reminderAgent.publishReminder(this.addAlarm(this.clockItems[index], index), (err, reminderId) =>{ + if(err.code == 0) { + // 设置reminderId + this.clockItems[index].reminderId = reminderId + }else { + console.info("publishReminder" + index + "error: " + err.message) + } + }); + } else { + // 删除 + reminderAgent.cancelReminder(reminderId) + } + } + ``` + + 新增闹钟,示例代码如下: + + ``` + private addAlarm(item: ClockItem, index: number): reminderAgent.ReminderRequestAlarm{ + return { + reminderType: reminderAgent.ReminderType.REMINDER_TYPE_ALARM, + // 小时 + hour: item.partition == '上午' ? parseInt(item.hour) : ((parseInt(item.hour) + 12) == 24 ? 0 : parseInt(item.hour) + 12), + // 分钟 + minute: parseInt(item.minute), + // 星期几 + daysOfWeek: [1, 2, 3, 4, 5, 6, 7], + actionButton: [ + { + title: "close", + type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE + }, + { + title: "snooze", + type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE + }, + ], + wantAgent: { + pkgName: "com.example.helloworld0218", + abilityName: "com.example.helloworld0218.MainAbility" + }, + maxScreenWantAgent: { + pkgName: "com.example.helloworld0218", + abilityName: "com.example.helloworld0218.MainAbility" + }, + // 响铃时长 + ringDuration: item.duration * 60, + // 延迟提醒次数 + snoozeTimes: item.intervalTimes, + // 延迟提醒间隔 最小五分钟 + timeInterval: item.intervalMinute, + title: item.name, + content: item.partition + item.hour + ':' + item.minute, + expiredContent: "this reminder has expired", + snoozeContent: "remind later", + notificationId: index, + slotType: notification.SlotType.SOCIAL_COMMUNICATION + } + } + ``` + +5. 首选项数据库,保存闹钟定时数据。 + + 保存闹钟定时数据,示例代码如下: + + ``` + private saveData() { + let promise = data_preferences.getPreferences(globalThis.context, 'mystore') + promise.then((preferences) => { + let promisePut = preferences.put('data', JSON.stringify(this.objs2array())) + promisePut.then(() => { + preferences.flush() + console.info("Put the value of startup successfully.") + }).catch((err) => { + console.info("Put the value of startup failed, err: " + err) + }) + }).catch((err) => { + console.info("Get the preferences failed, err: " + err) + }) + } + ``` + + 获取闹钟定时数据,示例代码如下: + + ``` + private getDate() { + let promise = data_preferences.getPreferences(globalThis.context, 'mystore') + promise.then((preferences) => { + let promiseGet = preferences.get('data', '') + promiseGet.then(value => { + this.clockItems = JSON.parse(value) + }) + }) + } + ``` + +# 闹钟操作界面 + +闹钟操作界面分为新增和修改界面,其中在修改界面可删除闹钟。具体分为以下模块: + +1. 关闭闹钟操作界面子组件,点击左上角“x”图标关闭操作界面,点击右上角“√”图标,保存当前设置并关闭操作界面。如下图所示: + + ![](figures/video5.gif) ![](figures/video6.gif) + + 在detail.ets中添加取消(“x”)、确定(“√”)子组件,并绑定点击事件,示例代码如下: + + ``` + Stack({alignContent: Alignment.End}) { + Row() { + // 取消 + Image('images/cancel.png') + .width(50) + .aspectRatio(1.0) + .onClick(() => { + this.cancel() + }) + // 描述 + Text(this.nowIndex == -1 ? '新建闹钟' : '修改闹钟') + .fontSize(30) + .margin({left: 20}) + } + .height('100%') + .width('100%') + // 确定 + Image('images/confirm.png') + .width(50) + .aspectRatio(1.0) + .onClick(() => { + this.confirm() + }) + } + .margin({top: 20, bottom: 15}) + .width('90%').height(50) + + // 确定 '√' + private confirm(): void{ + // 新增 + if(this.nowIndex == -1) { + // 判断当前闹钟时间是否存在 + let exist = false + this.clockItems.forEach(item => { + if(item.partition == this.timedArray[0] && item.hour == this.timedArray[1] && item.minute == this.timedArray[2]) { + exist = true + return + } + }) + if(exist) { + AlertDialog.show({ message: '该时间闹钟已添加!' }) + } else { + // 新增信息 + this.modifyMsg = [0, this.clockItems.length, this.clockItems.length] + this.clockItems.push(new ClockItem(this.clockName, this.partitionIndex, this.timedArray[0], this.hourIndex, this.timedArray[1], + this.minuteIndex, this.timedArray[2], this.duration, this.intervalMinute, this.intervalTimes, true)) + this.showIndex = true + } + } else { + // 修改 + // 修改信息 + this.modifyMsg = [1, this.nowIndex,this.clockItems[this.nowIndex].reminderId] + this.clockItems[this.nowIndex] = new ClockItem(this.clockName, this.partitionIndex, this.timedArray[0], this.hourIndex, this.timedArray[1], + this.minuteIndex, this.timedArray[2], this.duration, this.intervalMinute, this.intervalTimes, true) + this.showIndex = true + } + + } + + // 取消 '×' + private cancel(): void{ + this.showIndex = true + } + ``` + +2. 设置闹钟提醒时间,在闹钟操作界面可通过滑动选择器设置闹钟的提醒时间(包括:时段、小时、分钟)。如下图所示: + + ![](figures/video7.gif) + + 在detail.ets中初始化时段、小时、分钟数据,示例代码如下: + + ``` + // 时段 + private partitions: string[] = ['上午', '下午'] + // 小时 + private hours: string[] = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] + // 分钟 + private minutes: string[] = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', + '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', + '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', + '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '00', + ] + ``` + + 在detail.ets中添加闹钟时间选择器子组件,示例代码如下: + + ``` + Row() { + // 上午下午 + TextPicker({range: this.partitions, selected: this.partitionIndex}) + .width('33%') + .onChange((value: string, index: number) => { + this.timedArray[0] = value + this.partitionIndex = index + console.info('Picker item changed, value: ' + value + ', index: ' + index) + }) + // 小时 + TextPicker({range: this.hours, selected: this.hourIndex}) + .width('33%') + .onChange((value: string, index: number) => { + this.timedArray[1] = value + this.hourIndex = index + console.info('Picker item changed, value: ' + value + ', index: ' + index) + }) + // 分钟 + TextPicker({range: this.minutes, selected: this.minuteIndex}) + .width('33%') + .onChange((value: string, index: number) => { + this.timedArray[2] = value + this.minuteIndex = index + console.info('Picker item changed, value: ' + value + ', index: ' + index) + }) + } + .backgroundColor('#E2E2E2') + .borderRadius(10) + ``` + +3. 闹钟名子组件。如下图所示: + + ![](figures/video8.gif) + + 在detail.ets中添加闹钟名子组件,点击闹钟名打设置开闹钟名弹框,示例代码如下: + + ``` + Stack({alignContent: Alignment.End}) { + Row() { + Text('闹钟名') + .fontSize(20) + } + .height('100%') + .width('100%') + Text(this.clockName + ' >') + .fontSize(15) + .fontColor('#E2E2E2') + } + .width('100%') + .height(30) + .margin({top: 20, bottom: 10}) + .onClick(() => { + this.dialogControllerName.open() + }) + + // 闹钟名弹框 + dialogControllerName : CustomDialogController = new CustomDialogController({ + builder: DialogName({action: this.onAccept}), + autoCancel: true + }); + + // 闹钟名弹框 + @CustomDialog + struct DialogName { + @Consume clockName: string + name: string + controller: CustomDialogController; + action: () => void; + + build() { + Column(){ + Text('闹钟名').fontSize(20).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + TextArea({text: this.clockName}) + .width('90%').margin({top: 20}) + .onChange((value: string) => { + this.name = value + }) + Divider().width('90%').margin({top: 10}) + Row() { + Text('取消').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + Text('确定').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.clockName = this.name + this.controller.close(); + }) + }.margin({top: 10, bottom: 20}) + }.width('100%') + } + } + ``` + +4. 响铃时长子组件。如下图所示: + + ![](figures/video9.gif) + + 在detail.ets中添加响铃时长文本框子组件,点击后打开响铃时长选择框,示例代码如下: + + ``` + Stack({alignContent: Alignment.End}) { + Row() { + Text('响铃时长') + .fontSize(20) + } + .height('100%') + .width('100%') + Text(this.duration.toFixed(0) + ' 分钟 >') + .fontSize(15) + .fontColor('#E2E2E2') + } + .width('100%') + .height(30) + .margin({bottom: 10}) + .onClick(() => { + this.dialogControllerDuration.open() + }) + + // 响铃时长弹框 + dialogControllerDuration : CustomDialogController = new CustomDialogController({ + builder: DialogDuration({action: this.onAccept}), + autoCancel: true + }); + + // 响铃时长弹框 + @CustomDialog + struct DialogDuration { + @Consume duration: number + //响铃时长,分钟 + private durations: Array = [1, 5, 10, 15, 20, 30] + controller: CustomDialogController; + action: () => void; + + build() { + Column(){ + Text('响铃时长').fontSize(20).width('90%').textAlign(TextAlign.Start).margin({top: 10, bottom: 10}) + ForEach(this.durations, item => { + Stack({alignContent: Alignment.End}) { + Row() { + Text(item + ' 分钟') + }.width('100%') + Radio({ value: item, group: 'radioGroup' }).checked(item == this.duration ? true: false) + .height(20) + .width(20) + .onChange((value: boolean) => { + this.controller.close(); + this.duration = item + }) + }.width('90%') + Divider().width('90%') + }) + Row() { + Text('取消').fontSize(15).width('100%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + }.margin({top: 10, bottom: 20}) + }.width('100%') + } + } + ``` + +5. 再响间隔子组件,包括响铃间隔时间(最少5分钟)和重复响铃次数。如下图所示: + + ![](figures/video10.gif) + + 在detail.ets中添加再响间隔文本框子组件,点击后打开再响间隔弹框,示例代码如下: + + ``` + Stack({alignContent: Alignment.End}) { + Row() { + Text('再响间隔') + .fontSize(20) + } + .height('100%') + .width('100%') + Text(this.intervalMinute.toFixed(0) + ' 分钟,' + this.intervalTimes.toFixed(0) + ' 次 >') + .fontSize(15) + .fontColor('#E2E2E2') + } + .width('100%') + .height(30) + .onClick(() => { + this.dialogControllerInterval.open() + }) + + //再响间隔弹框 + dialogControllerInterval : CustomDialogController = new CustomDialogController({ + builder: DialogInterval({action: this.onAccept}), + autoCancel: true + }); + + // 再响间隔弹框 + @CustomDialog + struct DialogInterval { + // 再响间隔分钟,默认10分钟 + @Consume intervalMinute: number + // 再响间隔次数,默认3次 + @Consume intervalTimes: number + // 再响间隔分钟,界面选择值 + @State intervalMinuteSelect: number = 0 + // 再响间隔次数,界面选择值 + @State intervalTimesSelect: number = 0 + controller: CustomDialogController; + action: () => void; + + build() { + Column(){ + Text('再响间隔').fontSize(20).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + Text('响铃间隔时间(分钟)').fontSize(10).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + Row() { + Slider({ + value: this.intervalMinuteSelect, + min: 5, + max: 30, + step: 5, + style: SliderStyle.OutSet + }) + .blockColor(Color.Blue) + .trackColor(Color.Gray) + .selectedColor(Color.Blue) + .showSteps(true) + .showTips(true) + .onChange((value: number, mode: SliderChangeMode) => { + this.intervalMinuteSelect = value + }) + Text(this.intervalMinuteSelect.toFixed(0)).fontSize(16) + } + .padding({ top: 30 }) + .width('90%') + Divider().width('90%').margin({top: 10}) + Text('重复响铃次数').fontSize(10).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + Row() { + Slider({ + value: this.intervalTimesSelect, + min: 0, + max: 10, + step: 2, + style: SliderStyle.OutSet + }) + .blockColor(Color.Blue) + .trackColor(Color.Gray) + .selectedColor(Color.Blue) + .showSteps(true) + .showTips(true) + .onChange((value: number, mode: SliderChangeMode) => { + this.intervalTimesSelect = value + }) + Text(this.intervalTimesSelect.toFixed(0)).fontSize(16) + } + .padding({ top: 50 }) + .width('90%') + Row() { + Text('取消').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + Text('确定').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.intervalMinute = this.intervalMinuteSelect + this.intervalTimes = this.intervalTimesSelect + this.controller.close(); + }) + }.margin({top: 10, bottom: 20}) + }.width('100%') + } + aboutToAppear(): void{ + // 再响间隔分钟,界面选择值 + this.intervalMinuteSelect = this.intervalMinute + // 再响间隔次数,界面选择值 + this.intervalTimesSelect = this.intervalTimes + } + } + ``` + +# 恭喜您 + +目前你已经成功完成了Codelab并且学到了: + +- 如何使用Canvas画布组件绘制图形。 +- 如何使用后台代理提醒。 +- 如何使用TextPicker。 +- 如何使用CustomDialog组件进行自定义弹框。 +- 如何使用首选项数据库。 \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/build-profile.json5 b/CommonEventAndNotification/AlarmClock/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a94f9962fabcc697fc1a89d01ff9f0c6320010ce --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/build-profile.json5 @@ -0,0 +1,28 @@ +{ + "app": { + "signingConfigs": [ + ], + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "debug", + }, + ], + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default", + ], + }, + ], + }, + ], +} \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/build-profile.json5 b/CommonEventAndNotification/AlarmClock/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7dc37bb919dada5132609c409200db266559004f --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/entry/build-profile.json5 @@ -0,0 +1,13 @@ +{ + "apiType": 'stageMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/hvigorfile.js b/CommonEventAndNotification/AlarmClock/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..d7720ee6a7aad5c617d1fd2f6fc8c87067bfa32c --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/CommonEventAndNotification/AlarmClock/entry/package.json b/CommonEventAndNotification/AlarmClock/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c4e988f30f2ec9e3430a4d0c8f05e89fabbc2659 --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/entry/package.json @@ -0,0 +1,13 @@ +{ + "name": "entry", + "version": "1.0.0", + "ohos": { + "org": "huawei", + "buildTool": "hvigor", + "directoryLevel": "module" + }, + "description": "example description", + "repository": {}, + "license": "ISC", + "dependencies": {} +} diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/Application/AbilityStage.ts b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c9fcaafa50d6605b274c4a54a4b6225bc9bc1d0 --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 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 AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/MainAbility/MainAbility.ts b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..3097d0a082069d7d0135f2e8eb61c5048bc224a6 --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 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 Ability from '@ohos.application.Ability' +import notification from '@ohos.notification'; + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + globalThis.context = this.context + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + let context = this.context + // 通知权限弹框 + notification.requestEnableNotification() + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + + windowStage.setUIContent(this.context, "pages/index", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/add.png b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/add.png new file mode 100644 index 0000000000000000000000000000000000000000..34252da2cb7c751f8baf24488010a03d21f3176b Binary files /dev/null and b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/add.png differ diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/cancel.png b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..e57c208b981f448316a49278088c2fc9c0d1c6d8 Binary files /dev/null and b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/cancel.png differ diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/confirm.png b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/confirm.png new file mode 100644 index 0000000000000000000000000000000000000000..82c1e234962af3a9e75d2fae8468dfa95d759480 Binary files /dev/null and b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/images/confirm.png differ diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/detail.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/detail.ets new file mode 100644 index 0000000000000000000000000000000000000000..4f7997a770c839990e8b7d6dadc0cf2f6e43b1b1 --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/detail.ets @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2021 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. + */ +@Component +export struct Detail { + @Link showIndex: boolean //true主界面 false详情界面 + @Link nowIndex: number // 新增时值为-1,修改时值为当前数组索引 + @State partitionIndex: number = 1 + private partitions: string[] = ['上午', '下午'] // 时段 + @State hourIndex: number = 1 + private hours: string[] = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] // 小时 + @State minuteIndex: number = 1 + private minutes: string[] = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', + '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', + '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', + '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '00', + ] // 分钟 + @State timedArray: Array = ['下午', '02', '02'] //闹钟时间,三个值分别为:上下午、小时、分钟 + @Link clockItems: Array // 闹钟-定时数组 + @Link modifyMsg: Array // 记录clockItems变化数据,三个数值,第一个:0新增、1修改、2删除;第二个:修改闹钟的index值;第三个:闹钟reminderId + @Provide clockName: string = '闹钟' // 闹钟名,默认闹钟 + @Provide duration: number = 5 // 响铃时长, 默认5分钟 + @Provide intervalMinute: number = 10 // 再响间隔分钟,默认10分钟 + @Provide intervalTimes: number = 3 // 再响间隔次数,默认3次 + + // 闹钟名弹框 + dialogControllerName : CustomDialogController = new CustomDialogController({ + builder: DialogName({action: this.onAccept}), + autoCancel: true + }); + // 响铃时长弹框 + dialogControllerDuration : CustomDialogController = new CustomDialogController({ + builder: DialogDuration({action: this.onAccept}), + autoCancel: true + }); + //再响时长弹框 + dialogControllerInterval : CustomDialogController = new CustomDialogController({ + builder: DialogInterval({action: this.onAccept}), + autoCancel: true + }); + + onAccept() { + } + + build() { + Stack({alignContent: Alignment.Bottom}) { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center}) { + Stack({alignContent: Alignment.End}) { + Row() { + // 取消 + Image('images/cancel.png') + .width(50) + .aspectRatio(1.0) + .onClick(() => { + this.cancel() + }) + // 描述 + Text(this.nowIndex == -1 ? '新建闹钟' : '修改闹钟') + .fontSize(30) + .margin({left: 20}) + } + .height('100%') + .width('100%') + // 确定 + Image('images/confirm.png') + .width(50) + .aspectRatio(1.0) + .onClick(() => { + this.confirm() + }) + } + .margin({top: 20, bottom: 15}) + .width('90%').height(50) + + Scroll() { + Column() { + // 时间选择 + Row() { + // 上午下午 + TextPicker({range: this.partitions, selected: this.partitionIndex}) + .width('33%') + .onChange((value: string, index: number) => { + this.timedArray[0] = value + this.partitionIndex = index + console.info('Picker item changed, value: ' + value + ', index: ' + index) + }) + // 小时 + TextPicker({range: this.hours, selected: this.hourIndex}) + .width('33%') + .onChange((value: string, index: number) => { + this.timedArray[1] = value + this.hourIndex = index + console.info('Picker item changed, value: ' + value + ', index: ' + index) + }) + // 分钟 + TextPicker({range: this.minutes, selected: this.minuteIndex}) + .width('33%') + .onChange((value: string, index: number) => { + this.timedArray[2] = value + this.minuteIndex = index + console.info('Picker item changed, value: ' + value + ', index: ' + index) + }) + } + .backgroundColor('#E2E2E2') + .borderRadius(10) + + // 信息 + Stack({alignContent: Alignment.End}) { + Row() { + Text('闹钟名') + .fontSize(20) + } + .height('100%') + .width('100%') + Text(this.clockName + ' >') + .fontSize(15) + .fontColor('#E2E2E2') + } + .width('100%') + .height(30) + .margin({top: 20, bottom: 10}) + .onClick(() => { + this.dialogControllerName.open() + }) + + Divider().margin({bottom: 10}) + + Stack({alignContent: Alignment.End}) { + Row() { + Text('响铃时长') + .fontSize(20) + } + .height('100%') + .width('100%') + Text(this.duration.toFixed(0) + ' 分钟 >') + .fontSize(15) + .fontColor('#E2E2E2') + } + .width('100%') + .height(30) + .margin({bottom: 10}) + .onClick(() => { + this.dialogControllerDuration.open() + }) + + Divider().margin({bottom: 10}) + + Stack({alignContent: Alignment.End}) { + Row() { + Text('再响间隔') + .fontSize(20) + } + .height('100%') + .width('100%') + Text(this.intervalMinute.toFixed(0) + ' 分钟,' + this.intervalTimes.toFixed(0) + ' 次 >') + .fontSize(15) + .fontColor('#E2E2E2') + } + .width('100%') + .height(30) + .onClick(() => { + this.dialogControllerInterval.open() + }) + } + } + .flexGrow(1) + .width('90%') + } + .width('100%') + .height('100%') + + // 删除按钮 + Text('删除') + .width('50%') + .height(45) + .textAlign(TextAlign.Center) + .fontSize(25) + .fontColor('#DE1A33') + .backgroundColor('#E2E2E2') + .borderRadius(20) + .margin({bottom: 10}) + .onClick(() => { + this.delete() + }) + .visibility(this.nowIndex == -1 ? Visibility.None : Visibility.Visible) + } + .width('100%') + .height('100%') + } + + // 确定 '√' + private confirm(): void{ + // 新增 + if(this.nowIndex == -1) { + // 判断当前闹钟时间是否存在 + let exist = false + this.clockItems.forEach(item => { + if(item.partition == this.timedArray[0] && item.hour == this.timedArray[1] && item.minute == this.timedArray[2]) { + exist = true + return + } + }) + if(exist) { + AlertDialog.show({ message: '该时间闹钟已添加!' }) + } else { + this.modifyMsg = [0, this.clockItems.length, this.clockItems.length] // 新增信息 + this.clockItems.push(new ClockItem(this.clockName, this.partitionIndex, this.timedArray[0], this.hourIndex, this.timedArray[1], + this.minuteIndex, this.timedArray[2], this.duration, this.intervalMinute, this.intervalTimes, true)) + this.showIndex = true + } + } else { + // 修改 + this.modifyMsg = [1, this.nowIndex,this.clockItems[this.nowIndex].reminderId] // 修改信息 + this.clockItems[this.nowIndex] = new ClockItem(this.clockName, this.partitionIndex, this.timedArray[0], this.hourIndex, this.timedArray[1], + this.minuteIndex, this.timedArray[2], this.duration, this.intervalMinute, this.intervalTimes, true) + this.showIndex = true + } + + } + + // 取消 '×' + private cancel(): void{ + this.showIndex = true + } + + // 删除 + private delete(): void{ + this.modifyMsg = [2, this.nowIndex, this.clockItems[this.nowIndex].reminderId] // 删除信息 + this.clockItems.splice(this.nowIndex, 1) + this.timedArray = ['下午', '02', '02'] + this.partitionIndex = 1 + this.hourIndex = 1 + this.minuteIndex = 1 + this.clockName = '闹钟' + this.duration = 5 + this.intervalMinute = 10 + this.intervalTimes = 3 + this.showIndex = true + } + + // 页面显示触发 + aboutToAppear(): void{ + // 修改 + if (this.nowIndex != -1){ + // 设置值 ClockItem + let item = this.clockItems[this.nowIndex] + this.timedArray = [item.partition, item.hour, item.minute] + this.partitionIndex = item.partitionIndex + this.hourIndex = item.hourIndex + this.minuteIndex = item.minuteIndex + this.clockName = item.name + this.duration = item.duration + this.intervalMinute = item.intervalMinute + this.intervalTimes = item.intervalTimes + } + } +} + +/** + * 闹钟-定时类 + * @param name 闹钟名 + * @param partitionIndex 上午、下午下标 + * @param partition 上午、下午 + * @param hourIndex 时下标 + * @param hour 时 + * @param minuteIndex 分下标 + * @param minute 分 + * @param duration 响铃时长 + * @param intervalMinute 再响间隔时间(分钟) + * @param intervalTimes 再响间隔次数 + * @param open 是否开启 true false + * @param reminderId 闹钟的reminderId + */ +@Observed export class ClockItem { + name: string + partitionIndex: number + partition: string + hourIndex: number + hour: string + minuteIndex: number + minute: string + duration: number + intervalMinute: number + intervalTimes: number + open: boolean + reminderId: number + + constructor(name: string, partitionIndex: number, partition: string, + hourIndex: number, hour: string, minuteIndex: number, minute: string, + duration: number, intervalMinute: number, intervalTimes: number, open: boolean) { + this.name = name + this.partitionIndex = partitionIndex + this.partition = partition + this.hourIndex = hourIndex + this.hour = hour + this.minuteIndex = minuteIndex + this.minute = minute + this.duration = duration + this.intervalMinute = intervalMinute + this.intervalTimes = intervalTimes + this.open = open + } +} + +// 闹钟名弹框 +@CustomDialog +struct DialogName { + @Consume clockName: string + name: string + controller: CustomDialogController; + action: () => void; + + build() { + Column(){ + Text('闹钟名').fontSize(20).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + TextArea({text: this.clockName}) + .width('90%').margin({top: 20}) + .onChange((value: string) => { + this.name = value + }) + Divider().width('90%').margin({top: 10}) + Row() { + Text('取消').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + Text('确定').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.clockName = this.name + this.controller.close(); + }) + }.margin({top: 10, bottom: 20}) + }.width('100%') + } +} + +// 响铃时长弹框 +@CustomDialog +struct DialogDuration { + @Consume duration: number + private durations: Array = [1, 5, 10, 15, 20, 30] //响铃时长,分钟 + controller: CustomDialogController; + action: () => void; + + build() { + Column(){ + Text('响铃时长').fontSize(20).width('90%').textAlign(TextAlign.Start).margin({top: 10, bottom: 10}) + ForEach(this.durations, item => { + Stack({alignContent: Alignment.End}) { + Row() { + Text(item + ' 分钟') + }.width('100%') + Radio({ value: item, group: 'radioGroup' }).checked(item == this.duration ? true: false) + .height(20) + .width(20) + .onChange((value: boolean) => { + this.controller.close(); + this.duration = item + }) + }.width('90%') + Divider().width('90%') + }) + Row() { + Text('取消').fontSize(15).width('100%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + }.margin({top: 10, bottom: 20}) + }.width('100%') + } +} + +// 再响间隔弹框 +@CustomDialog +struct DialogInterval { + @Consume intervalMinute: number // 再响间隔分钟,默认10分钟 + @Consume intervalTimes: number // 再响间隔次数,默认3次 + @State intervalMinuteSelect: number = 0 // 再响间隔分钟,界面选择值 + @State intervalTimesSelect: number = 0 // 再响间隔次数,界面选择值 + controller: CustomDialogController; + action: () => void; + + build() { + Column(){ + Text('再响间隔').fontSize(20).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + Text('响铃间隔时间(分钟)').fontSize(10).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + Row() { + Slider({ + value: this.intervalMinuteSelect, + min: 5, + max: 30, + step: 5, + style: SliderStyle.OutSet + }) + .blockColor(Color.Blue) + .trackColor(Color.Gray) + .selectedColor(Color.Blue) + .showSteps(true) + .showTips(true) + .onChange((value: number, mode: SliderChangeMode) => { + this.intervalMinuteSelect = value + }) + Text(this.intervalMinuteSelect.toFixed(0)).fontSize(16) + } + .padding({ top: 30 }) + .width('90%') + Divider().width('90%').margin({top: 10}) + Text('重复响铃次数').fontSize(10).width('90%').textAlign(TextAlign.Start).margin({top: 10}) + Row() { + Slider({ + value: this.intervalTimesSelect, + min: 0, + max: 10, + step: 2, + style: SliderStyle.OutSet + }) + .blockColor(Color.Blue) + .trackColor(Color.Gray) + .selectedColor(Color.Blue) + .showSteps(true) + .showTips(true) + .onChange((value: number, mode: SliderChangeMode) => { + this.intervalTimesSelect = value + }) + Text(this.intervalTimesSelect.toFixed(0)).fontSize(16) + } + .padding({ top: 50 }) + .width('90%') + Row() { + Text('取消').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.controller.close(); + }) + Text('确定').fontSize(15).width('50%').textAlign(TextAlign.Center).fontColor('#17A98E') + .onClick(() => { + this.intervalMinute = this.intervalMinuteSelect + this.intervalTimes = this.intervalTimesSelect + this.controller.close(); + }) + }.margin({top: 10, bottom: 20}) + }.width('100%') + } + aboutToAppear(): void{ + this.intervalMinuteSelect = this.intervalMinute // 再响间隔分钟,界面选择值 + this.intervalTimesSelect = this.intervalTimes // 再响间隔次数,界面选择值 + } +} \ No newline at end of file diff --git a/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/index.ets b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..a3bee232994e52747480cd3b919fd944967c4795 --- /dev/null +++ b/CommonEventAndNotification/AlarmClock/entry/src/main/ets/pages/index.ets @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2021 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 reminderAgent from'@ohos.reminderAgent'; +import notification from '@ohos.notification' +import display from '@ohos.display'; +import {Detail, ClockItem} from './detail' +import data_preferences from '@ohos.data.preferences'; + +@Entry +@Component +struct Index { + private times: Array = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2] //时间刻度值 + private settings: RenderingContextSettings = new RenderingContextSettings(true) + private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) + @State size: number = 0 // canvas宽高 + @State canvasOnScreenRatio: number = 3 // 时钟画布是屏幕的几分之一,竖屏:宽度的1/3,此值为3。横屏:高度的1/4,此值为4 + private radius: number = 0 // 半径 + private sixtyParts = Math.PI * 2 / 60 // 60等分 + private twelveParts = Math.PI * 2 / 12 // 12等分 + @State screenWidth: number = 0 // 屏幕宽度 + @State screenHeight: number = 0 // 屏幕高度 + @State interval: any = -1 // 定时器 + @State showClock: boolean = true // true显示时钟 false显示时间 + @State showIndex: boolean = true // true主界面 false详情界面 + @State nowIndex: number = -1 // 新增时值为-1,修改时值为当前数组索引 + @State @Watch("resetAlarm") clockItems: Array = [] // 闹钟-定时 + @State modifyMsg: Array = [-1, -1, -1] // 记录clockItems变化数据,三个数值,第一个:0新增、1修改、2删除;第二个:修改闹钟的index值;第三个:闹钟reminderId + + aboutToAppear(){ + // 从首选项数据库获取数据 + this.getDate() + // 获取屏幕宽高 + display.getDefaultDisplay((err, data) => { + if(err.code === 0) { + console.info('Failed to obtain the default display object. Code: ' + JSON.stringify(err)) + } + this.screenWidth = data.width + this.screenHeight = data.height + // 设置canvas尺寸,竖屏取值为宽高最小值的1/3,横屏取值为宽高最小值的1/4 + this.canvasOnScreenRatio = (this.screenWidth < this.screenHeight ? 3 : 4) + this.size = (this.screenWidth < this.screenHeight ? this.screenWidth : this.screenHeight) / this.canvasOnScreenRatio + // 重置原点到canvas画布中间 + this.context.translate(this.size, this.size / 2) + }); + } + + build() { + Stack({alignContent: Alignment.Bottom}) { + Column() { + Column(){ + Text('闹钟') + .fontSize(30) + .margin({left: 20}) + }.height(80).width('100%').alignItems(HorizontalAlign.Start) + Canvas(this.context) + .height(this.size) + .aspectRatio(2.0) + .onReady(() =>{ + // 获取半径 + this.radius = this.size / 2 - 2.5 + var that = this + // 避免时钟闪现,先画一遍 + that.draw() + // 定时器 + this.interval = setInterval(function() { + that.draw() + }, 1000) + }) + .onClick(() => { + // 切换指针表盘和数字时钟 + this.showClock = !this.showClock + }) + + // 闹钟列表 + List({ space: 10, initialIndex: 0 }) { + ForEach(this.clockItems.map((item, index) => { + return { i: index, data: item } + }), + (item, index) => { + ListItem() { + Stack({alignContent: Alignment.End}) { + Column() { + Row() { + Text(item.data.partition).fontSize(15) + Text(item.data.hour+ ':' + item.data.minute).fontSize(25).margin({left: 10}) + } + Row() { + Text(item.data.name).fontSize(15) + Text('不重复').fontSize(15).margin({left: 10}) + }.margin({top: 5}) + } + .width('100%') + .margin({left: 10}) + .alignItems(HorizontalAlign.Start) + Toggle({ type: ToggleType.Switch, isOn: item.data.open }) + .selectedColor(0x39a2db) + .switchPointColor(0xe5ffffff) + .onChange((isOn: boolean) => { + item.data.open = !item.data.open + console.info('Component status:' + isOn) + // 关闭、打开闹钟 + this.modifyMsg = [item.data.open ? 0 : 2, index, item.data.reminderId] + this.resetAlarm() + }) + .width(30) + .aspectRatio(1.0) + } + .width('90%') + .height(60) + .backgroundColor('#E2E2E2') + .borderRadius(10) + }.width('100%') + .onClick(() => { + this.nowIndex = index // 下标 + this.showIndex = false // 展示修改界面 + }) + }, + item => item.data.name.toString()) + } + .listDirection(Axis.Vertical) // 排列方向 + .flexGrow(1) + .margin({top: 10}) + } + .width('100%') + .height('100%') + .visibility(this.showIndex ? Visibility.Visible : Visibility.Hidden) + + Column(){ + Detail({showIndex: $showIndex, clockItems: $clockItems, nowIndex: $nowIndex, modifyMsg: $modifyMsg}) + }.width('100%').height('100%').visibility(this.showIndex ? Visibility.Hidden : Visibility.Visible) + + Image('images/add.png') + .width(100) + .aspectRatio(1.0) + .margin({bottom: 10}) + .onClick(() => { + this.nowIndex = -1 // 新增闹钟,值为-1 + this.showIndex = false // 展示新增闹钟界面 + }).visibility(this.showIndex ? Visibility.Visible : Visibility.Hidden) + } + .width('100%') + .height('100%') + } + + // 开始绘制 + private draw(): void{ + // 清空绘制 + this.context.clearRect(-this.size, this.size / -2, this.size * 2, this.size) + // 获取当前时间 + let date = new Date() + if(this.showClock) { + // 画表盘 + this.drawDials() + // 画秒针 + this.drawSecond(date.getSeconds()) + // 画分针 + this.drawMinute(date.getMinutes(), date.getSeconds()) + // 画时针 + this.drawHour(date.getHours(), date.getMinutes()) + } else { + this.drawTime(date.getHours().toString(), date.getMinutes().toString(), date.getSeconds().toString()) + } + } + + // 画时间 + private drawTime(hour: string, minute: string, second: string): void{ + let time = this.fillZero(hour) + ':' + this.fillZero(minute) + ':' + this.fillZero(second) + this.context.save() + this.context.font = '100px' + this.context.beginPath() + this.context.textAlign = 'center' + this.context.fillText(time, 0, 0) + this.context.restore() + } + + // 补零:HH:mm:ss + private fillZero(val): string{ + var len = val.length; + while(len < 2) { + val = "0" + val; + len++; + } + return val; + } + + // 画表盘 + private drawDials(): void{ + // 画原点 + this.context.save() + this.context.beginPath() + this.context.arc(0, 0, 5, 0, Math.PI * 2) + this.context.fill() + this.context.stroke() + this.context.restore() + // 字体大小 + this.context.font = '20px' + // 画圆 + this.context.save() + this.context.lineWidth = 5 + this.context.beginPath() + this.context.arc(0, 0, this.radius, 0, 2 * Math.PI) + this.context.stroke() + this.context.restore() + + // 画刻度 + for (let n = 1; n <= 60; n++) { + // 从三点钟方向开始获取60个刻度的角度 + var theta = (n - 3) * (Math.PI * 2) / 60; + this.context.save() + // 刻度宽度为2 + this.context.lineWidth = 2 + this.context.beginPath() + // 刻度起始位置 + var x_move = this.radius * Math.cos(theta); + var y_move = this.radius * Math.sin(theta); + // 非整点刻度结束位置 + var x_to = (this.radius - 5) * Math.cos(theta); + var y_to = (this.radius - 5) * Math.sin(theta); + // 整点刻度 + if((n-3) % 5 == 0) { + //整点刻度宽度 + this.context.lineWidth = 3 + // 整点刻度结束位置 + x_to = (this.radius - 10) * Math.cos(theta); + y_to = (this.radius - 10) * Math.sin(theta); + // 整点时间位置 + var x_time = (this.radius - 25) * Math.cos(theta); + var y_time = (this.radius - 25) * Math.sin(theta); + // 绘制整点时间 + this.context.fillText(this.times[(n - 3) / 5] + '', x_time - 5, y_time + 3) + } + // 绘制刻度线 + this.context.moveTo(x_move, y_move) + this.context.lineTo(x_to, y_to) + this.context.stroke() + this.context.restore() + } + } + + // 画秒针 + private drawSecond(second: number): void{ + this.context.save() + this.context.fillStyle = 'red' + var theta = (second - 15) * 2 * Math.PI / 60; + this.context.rotate(theta) + this.context.beginPath() + this.context.moveTo(-15, -3); + this.context.lineTo(-15, 3); + this.context.lineTo(this.radius * 0.9, 1); + this.context.lineTo(this.radius * 0.9, -1); + this.context.fill(); + this.context.restore(); + } + + // 画分针 + private drawMinute(minute: number, second: number): void{ + this.context.save() + var theta = ((minute + second / 60 - 15) * 2 * Math.PI / 60) + this.context.rotate(theta) + this.context.beginPath() + this.context.moveTo(-15, -4); + this.context.lineTo(-15, 4); + this.context.lineTo(this.radius * 0.8, 1); + this.context.lineTo(this.radius * 0.8, -1); + this.context.fill(); + this.context.restore(); + } + + // 画时针 + private drawHour(hour:number, minute: number): void{ + this.context.save() + var theta = ((hour + minute / 60 - 3) * 2 * Math.PI / 12) + this.context.rotate(theta) + this.context.beginPath() + this.context.moveTo(-15, -5); + this.context.lineTo(-15, 5); + this.context.lineTo(this.radius * 0.5, 1); + this.context.lineTo(this.radius * 0.5, -1); + this.context.fill(); + this.context.restore(); + } + + // 监听闹钟数据变化 + private resetAlarm(): void{ + let opeNum = this.modifyMsg[0] + let index = this.modifyMsg[1] + let reminderId = this.modifyMsg[2] + if(opeNum == 0) { + // 新增 + reminderAgent.publishReminder(this.addAlarm(this.clockItems[index], index), (err, reminderId) =>{ + if(err.code == 0) { + this.clockItems[index].reminderId = reminderId // 设置reminderId + this.saveData() // 保存闹钟数据 + }else { + console.info("publishReminder" + index + "error: " + err.message) + } + }); + } else if(opeNum == 1) { + // 修改,先停止原先的闹钟再开启修改后的 + reminderAgent.cancelReminder(reminderId) + reminderAgent.publishReminder(this.addAlarm(this.clockItems[index], index), (err, reminderId) =>{ + if(err.code == 0) { + this.clockItems[index].reminderId = reminderId // 设置reminderId + this.saveData() // 保存闹钟数据 + }else { + console.info("publishReminder" + index + "error: " + err.message) + } + }); + } else { + // 删除 + reminderAgent.cancelReminder(reminderId) + this.saveData() // 保存闹钟数据 + } + } + + // 根据闹钟数据,新增闹钟 + private addAlarm(item: ClockItem, index: number): reminderAgent.ReminderRequestAlarm{ + return { + reminderType: reminderAgent.ReminderType.REMINDER_TYPE_ALARM, + hour: item.partition == '上午' ? parseInt(item.hour) : ((parseInt(item.hour) + 12) == 24 ? 0 : parseInt(item.hour) + 12), // 小时 + minute: parseInt(item.minute), // 分钟 + daysOfWeek: [1, 2, 3, 4, 5, 6, 7], // 星期几 + actionButton: [ + { + title: "close", + type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE + }, + { + title: "snooze", + type: reminderAgent.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE + }, + ], + wantAgent: { + pkgName: "com.example.helloworld0218", + abilityName: "com.example.helloworld0218.MainAbility" + }, + maxScreenWantAgent: { + pkgName: "com.example.helloworld0218", + abilityName: "com.example.helloworld0218.MainAbility" + }, + ringDuration: item.duration * 60, // 响铃时长 + snoozeTimes: item.intervalTimes, // 延迟提醒次数 + timeInterval: item.intervalMinute, // 延迟提醒间隔 最小五分钟 + title: item.name, + content: item.partition + item.hour + ':' + item.minute, + expiredContent: "this reminder has expired", + snoozeContent: "remind later", + notificationId: index, + slotType: notification.SlotType.SOCIAL_COMMUNICATION + } + } + + // 保存闹钟数据到首选项数据库 + private saveData() { + let promise = data_preferences.getPreferences(globalThis.context, 'mystore') + promise.then((preferences) => { + let promisePut = preferences.put('data', JSON.stringify(this.objs2array())) + promisePut.then(() => { + preferences.flush() + console.info("Put the value of startup successfully.") + }).catch((err) => { + console.info("Put the value of startup failed, err: " + err) + }) + }).catch((err) => { + console.info("Get the preferences failed, err: " + err) + }) + } + + // 从首选项数据库中获取闹钟数据 + private getDate() { + let promise = data_preferences.getPreferences(globalThis.context, 'mystore') + promise.then((preferences) => { + let promiseGet = preferences.get('data', '') + promiseGet.then(value => { + this.clockItems = JSON.parse(value) + }) + }) + } + + // 将对象数组转换成数组 + private objs2array() { + let array = [] + for(let i=0;i + +ADC是模拟-数字转换器(Analog to Digital Converter)的缩写。可以将连续变化的模拟信号转换为离散的数字信号,进而使用数字电路进行处理,称之为数字信号处理。I2C\(Inter Integrated Circuit\)总线是一种简单、双向二线制同步串行总线。 + +本篇Codelab将介绍如何使用ADC和I2C API,实现按下Hi3861开发板按键1和按键2,在OLED显示屏上分别显示英文和中文的功能。 + +效果如下: + +![](figures/1_zh-cn_attachment_0000001275840861-00_00_00-00_00_30.gif) + +# 环境准备 + +完成本篇Codelab,我们首先需要完成开发环境搭建、源码编译,可参照如下步骤进行。 + +1. [搭建开发环境](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-steps-hi3861-setting.md)。 +2. 编译源码:建议开发者选择LTS 3.0版本源码进行编译,本篇Codelab是基于此版本开发的。 + + [编译Hi3861V100开发板源码](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-steps-hi3861-building.md) + + +**您需要使用如下设备完成本Codelab:** + +Hi3861V100开发板主板、底板以及OLED显示屏。 + +# API介绍 + +**I2C API** + + + + + + + + + + + + + + + + + + + + + + +

方法

+

说明

+

IoTI2cInit (unsigned int id, unsigned int baudrate)

+

使用指定波特率初始化I2C设备。

+

IoTI2cDeinit (unsigned int id)

+

去初始化I2C设备。

+

IoTI2cWrite (unsigned int id, unsigned short deviceAddr, const unsigned char *data, unsigned int dataLen)

+

向I2C设备写入数据。

+

IoTI2cRead(unsigned int id, unsigned short deviceAddr, unsigned char *data, unsigned int dataLen)

+

从I2C设备读取数据。

+

IoTI2cSetBaudrate(unsigned int id, unsigned int baudrate)

+

设置I2C设备的波特率。

+
+ +**ADC API** + + + + + + + + + + +

方法

+

说明

+

AdcRead(WifiIotAdcChannelIndex channel, unsigned short *data, WifiIotAdcEquModelSel equModel, WifiIotAdcCurBais curBais, unsigned short rstCnt)

+

根据输入参数从指定的ADC通道读取一段采样数据

+
+ +**Hi3861V100开发板说明** + +实现IOT外设控制,首先需要通过查阅原理图明确接线关系。OLED显示屏与主控芯片(Pegasus)引脚的对应关系如下: + + + + + + + + + + + + + +

按键

+

控制管脚

+

S1

+

GPIO13

+

S2

+

GPIO14

+
+ +>![](public_sys-resources/icon-note.gif) **说明:** +>开发板原理图,请开发者联系Hi3861购买渠道客服获取。 + +# 编译烧写&运行 + +1. **确定目录结构**。 + + 开发者编写业务时,务必先在OpenHarmony/applications/sample/wifi-iot/app路径下新建一个目录,用于存放业务源码文件。例如:在app目录下新增目录screen,其中oled\_demo.c为业务代码,BUILD.gn为编译脚本,具体规划目录结构如下: + + ``` + . + └── applications + └── sample + └── wifi-iot + └── app + │── screen + │ │── oled_demo.c + │ │── oled_ssd1306_conf.h + │ │── oled_ssd1306_fonts.c + │ │── oled_ssd1306_fonts.h + │ │── oled_ssd1306.c + │ │── oled_ssd1306.h + │ └── BUILD.gn + └── BUILD.gn + ``` + +2. **设置I2C引脚复用**。 + + 确定I2C引脚,查看原理图,可以看到OLED屏幕使用到的是I2C0,引脚是GPIO13、GPIO14。我们需要修改源码,在OpenHarmony/device/hisilicon/hispark\_pegasus/sdk\_liteos/app/wifiiot\_app/init/app\_io\_init.c文件中,初始化I2C引脚的代码修改成如下: + + ![](figures/1.png) + +3. **开启I2C功能**。 + + 在OpenHarmony/device/hisilicon/hispark\_pegasus/sdk\_liteos/build/config/usr\_config.mk 文件中,增加 CONFIG\_I2C\_SUPPORT=y。 + + ![](figures/2.png) + +4. **编写业务代码**。 + + 在OpenHarmony/applications/sample/wifi-iot/app/screen目录下新建oled\_demo.c文件,在oled\_demo.c中新建业务入口函数OledDemo,并实现业务逻辑。在代码最下方,使用OpenHarmony启动恢复模块接口SYS\_RUN\(\)启动业务。(SYS\_RUN定义在ohos\_init.h文件中) + + ``` + #include + #include + #include "ohos_init.h" + #include "cmsis_os2.h" + #include "hi_io.h" + #include "hi_adc.h" + #include "oled_ssd1306.h" + + #define OLED_I2C_BAUDRATE 400*1000 + + hi_void convert_to_voltage(hi_u32 data_len) + { + ... + // 按键1被按下 + if((vlt_val > 0.4) && (vlt_val < 0.6)) + { + if(key_flg == 0) + { + key_flg = 1; + key_status = KEY_EVENT_S1; + } + } + // 按键2被按下 + if((vlt_val > 0.8) && (vlt_val < 1.1)) + { + if(key_flg == 0) + { + key_flg = 1; + key_status = KEY_EVENT_S2; + } + } + // 没有按键被按下 + if(vlt_val > 3.0) + { + key_flg = 0; + key_status = KEY_EVENT_NONE; + } + } + // 检测电压 + void read_adc(void) + { + ... + for (i = 0; i < ADC_TEST_LENGTH; i++) { + ret = hi_adc_read((hi_adc_channel_index)HI_ADC_CHANNEL_2, &data, HI_ADC_EQU_MODEL_1, HI_ADC_CUR_BAIS_DEFAULT, 0); + if (ret != HI_ERR_SUCCESS) { + printf("ADC Read Fail\n"); + return; + } + g_adc_buf[i] = data; + } + convert_to_voltage(ADC_TEST_LENGTH); + } + + static void OledTask(void *arg) + { + (void)arg; + // 初始化 + IoTI2cInit(0, OLED_I2C_BAUDRATE); // Rate: 100kbps + ... + while(1) + { + // 读取ADC值 + read_adc(); + + switch(get_key_event()) + { + // 没有按键按下,清屏 + case KEY_EVENT_NONE: + { + // Clear screen + ssd1306_Fill(Black); + ssd1306_UpdateScreen(); + } + break; + // 按键1被按下,显示英文字母 + case KEY_EVENT_S1: + { + // Clear screen + ssd1306_Fill(Black); + ssd1306_SetCursor(0,0); + ssd1306_DrawString("**OpenHarmony!**", Font_7x10, White); + ssd1306_UpdateScreen(); + // 显示10s + usleep(10 * 1000 * 1000); + } + break; + // 按键2被按下,显示中文 + case KEY_EVENT_S2: + { + OledDrawChinese(); + // 显示10s + usleep(10 * 1000 * 1000); + } + break; + } + // 轮询时间控制 + usleep(100); + } + } + + static void OledDemo(void) + { + osThreadAttr_t attr; + // 初始化13、14号管脚 + IoTGpioInit(HI_IO_NAME_GPIO_13); + IoTGpioInit(HI_IO_NAME_GPIO_14); + // 将引脚功能设置为I2C引脚 + hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA); + hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL); + attr.attr_bits = 0U; + attr.cb_mem = NULL; + attr.cb_size = 0U; + attr.stack_mem = NULL; + attr.stack_size = 4096; + attr.priority = osPriorityNormal; + + if (osThreadNew(OledTask, NULL, &attr) == NULL) { + printf("[OledDemo] Falied to create OledTask!\n"); + } + } + SYS_RUN(OledDemo); + ``` + +5. **编写用于将业务构建成静态库的BUILD.gn文件**。 + + 在./applications/sample/wifi-iot/app/screen目录下新建BUILD.gn文件,并完成如下配置。 + + ``` + static_library("oled_example") { + sources = [ + "oled_demo.c", + "oled_ssd1306.c", + "oled_ssd1306_fonts.c" + ] + include_dirs = [ + "//utils/native/lite/include", + "//kernel/liteos_m/components/cmsis", + "//base/iot_hardware/peripheral/interfaces/kits", + "//device/hisilicon/hispark_pegasus/sdk_liteos/include" + ] + } + ``` + + - static\_library中指定业务模块的编译结果,开发者根据实际情况完成填写。 + - sources中指定静态库.a所依赖的.c文件及其路径,若路径中包含"//"则表示绝对路径(此处为代码根路径),若不包含"//"则表示相对路径。 + - include\_dirs中指定source所需要依赖的.h文件路径。 + +6. **编写模块BUILD.gn文件,指定需参与构建的特性模块**。 + + 配置./applications/sample/wifi-iot/app/BUILD.gn文件,在features字段中增加索引,使目标模块参与编译。features字段指定业务模块的路径和目标,features字段配置如下。 + + ``` + import("//build/lite/config/component/lite_component.gni") + + lite_component("app") { + features = [ + "screen:oled_example", + ] + } + ``` + +7. **代码编译和烧录**。 + +代码编译和烧录可以参考: + +[源码编译](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-steps-hi3861-building.md) + +[烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-steps-hi3861-burn.md) + +完成烧录后,按下按键1,OLED显示屏上显示英文“\*\*OpenHarmony!\*\*”,按下按键 + +2,OLED显示屏上显示中文“你好世界”。 + +# 恭喜您 + +目前您已经成功完成了本篇Codelab,并且学到了: + +- 如何使用ADC检测电压值,判断Hi3861开发板上哪个按键被按下。 +- 如何使用I2C控制OLED显示屏显示中英文。 + diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/1.png" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/1.png" new file mode 100644 index 0000000000000000000000000000000000000000..6aaf1c1b2d24679783572290074f11b2c62bbdea Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/1.png" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/1_zh-cn_attachment_0000001275840861-00_00_00-00_00_30.gif" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/1_zh-cn_attachment_0000001275840861-00_00_00-00_00_30.gif" new file mode 100644 index 0000000000000000000000000000000000000000..210ef8622a17e385bd961b541bd4a9c0d938d365 Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/1_zh-cn_attachment_0000001275840861-00_00_00-00_00_30.gif" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/2.png" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/2.png" new file mode 100644 index 0000000000000000000000000000000000000000..0b9d20cb4bf23385688784c5c1950cae833bb60a Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/figures/2.png" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-caution.gif" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-caution.gif" new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-caution.gif" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-danger.gif" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-danger.gif" new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-danger.gif" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-note.gif" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-note.gif" new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-note.gif" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-notice.gif" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-notice.gif" new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-notice.gif" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-tip.gif" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-tip.gif" new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-tip.gif" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-warning.gif" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-warning.gif" new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/public_sys-resources/icon-warning.gif" differ diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/BUILD.gn" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/BUILD.gn" new file mode 100644 index 0000000000000000000000000000000000000000..1de119885202883e64d365020d0c9532d7c37451 --- /dev/null +++ "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/BUILD.gn" @@ -0,0 +1,27 @@ +# Copyright (c) 2020 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. + +static_library("oled_example") { + sources = [ + "oled_demo.c", + "oled_ssd1306_fonts.c", + "oled_ssd1306.c", + ] + + include_dirs = [ + "//utils/native/lite/include", + "//kernel/liteos_m/components/cmsis", + "//base/iot_hardware/peripheral/interfaces/kits", + "//device/hisilicon/hispark_pegasus/sdk_liteos/include", + ] +} diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_demo.c" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_demo.c" new file mode 100644 index 0000000000000000000000000000000000000000..5d80c60d2150baf03622e34bb7d420f018203b0b --- /dev/null +++ "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_demo.c" @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include "ohos_init.h" +#include "cmsis_os2.h" +#include "hi_io.h" +#include "hi_adc.h" +#include "oled_ssd1306.h" + +#define LED_I2C_BARRAGE (400 * 1000) +#define TASK_STACK_SIZE 4096 +void IotShowChinese(void) +{ + const int32_t w = 16; + const int32_t h = 16; + int8_t fonts[][32] = { + { + /* -- ID:0,字符:"你",ASCII编码:C4E3,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节 */ + 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x23, 0xFC, 0x22, 0x04, 0x64, 0x08, 0xA8, 0x40, 0x20, 0x40, + 0x21, 0x50, 0x21, 0x48, 0x22, 0x4C, 0x24, 0x44, 0x20, 0x40, 0x20, 0x40, 0x21, 0x40, 0x20, 0x80, + }, + { + /* -- ID:1,字符:"好",ASCII编码:BAC3,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节 */ + 0x10, 0x00, 0x11, 0xFC, 0x10, 0x04, 0x10, 0x08, 0xFC, 0x10, 0x24, 0x20, 0x24, 0x24, 0x27, 0xFE, + 0x24, 0x20, 0x44, 0x20, 0x28, 0x20, 0x10, 0x20, 0x28, 0x20, 0x44, 0x20, 0x84, 0xA0, 0x00, 0x40, + }, + { + /* -- ID:2,字符:"世",ASCII编码:CAC0,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节 */ + 0x01, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x14, 0xFF, 0xFE, 0x11, 0x10, 0x11, 0x10, + 0x11, 0x10, 0x11, 0x10, 0x11, 0xF0, 0x11, 0x10, 0x10, 0x00, 0x10, 0x08, 0x1F, 0xFC, 0x00, 0x00, + }, + { + /* -- ID:3,字符:"界",ASCII编码:BDE7,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节 */ + 0x00, 0x10, 0x1F, 0xF8, 0x11, 0x10, 0x11, 0x10, 0x1F, 0xF0, 0x11, 0x10, 0x11, 0x10, 0x1F, 0xF0, + 0x02, 0x80, 0x04, 0x60, 0x0C, 0x50, 0x34, 0x4E, 0xC4, 0x44, 0x04, 0x40, 0x08, 0x40, 0x10, 0x40, + } + }; + IotFill(BLACK); + for (size_t i = 0; i < sizeof(fonts) / sizeof(fonts[0]); i++) { + IotShowRegion(i * w, 0, w, h, fonts[i], sizeof(fonts[0]), h); + } + IotChangeScreen(); +} + +hi_u16 g_adc_buf[ADC_TEST_LENGTH] = { 0 }; +int g_keyStatus = KEY_EVENT_NONE; +char g_keyFlg = 0; + +int GetKeyEvent(void) +{ + int tmp = g_keyStatus; + g_keyStatus = KEY_EVENT_NONE; + return tmp; +} + +hi_void convert_to_voltage(hi_u32 data_len) +{ + hi_u32 i; + float vltMax = 0; + float vltMin = 100; + float vltVal; + hi_u16 vlt; + for (i = 0; i < data_len; i++) { + vlt = g_adc_buf[i]; + float voltage = (float)vlt * 1.8 * 4 / 4096.0; /* vlt * 1.8 * 4 / 4096.0: Convert code into voltage */ + vltMax = (voltage > vltMax) ? voltage : vltMax; + vltMin = (voltage < vltMin) ? voltage : vltMin; + } + printf("vltMin:%.3f, vltMax:%.3f \n", vltMin, vltMax); + vltVal = (vltMin + vltMax) / TWO; + // 按键1被按下 + if ((vltVal > FOUR) && (vltVal < SIX)) { + if (g_keyFlg == 0) { + g_keyFlg = 1; + g_keyStatus = KEY_EVENT_S1; + } + } + // 按键2被按下 + if ((vltVal > EIGHT) && (vltVal < ONE)) { + if (g_keyFlg == 0) { + g_keyFlg = 1; + g_keyStatus = KEY_EVENT_S2; + } + } + // 没有按键按下 + if (vltVal > THREE) { + g_keyFlg = 0; + g_keyStatus = KEY_EVENT_NONE; + } +} + +void ReadAdc(void) +{ + hi_u32 ret, i; + hi_u16 data; /* 10 */ + printf("ADC Start\n"); + + memset_s(g_adc_buf, sizeof(g_adc_buf), 0x0, sizeof(g_adc_buf)); + + for (i = 0; i < ADC_TEST_LENGTH; i++) { + ret = hi_adc_read((hi_adc_channel_index)HI_ADC_CHANNEL_2, + &data, HI_ADC_EQU_MODEL_1, HI_ADC_CUR_BAIS_DEFAULT, 0); + if (ret != HI_ERR_SUCCESS) { + printf("ADC Read Fail\n"); + return; + } + g_adc_buf[i] = data; + } + convert_to_voltage(ADC_TEST_LENGTH); +} + +static void OLEDTask(void const *arg) +{ + (void)arg; + + // 指定波特率初始化I2C设备 + IoTI2cInit(0, LED_I2C_BARRAGE); + // 初始化 + IotInit(); + + while (1) { + // 读取ADC值 + ReadAdc(); + switch (GetKeyEvent()) { + case KEY_EVENT_NONE: + { + // Clear screen + IotFill(BLACK); + IotChangeScreen(); + } + break; + + case KEY_EVENT_S1: + { + // 清屏 + IotFill(BLACK); + // 设置光标位置 + IotSetCursor(0, 0); + // 显示内容 + IotShowString("**OpenHarmony!**", g_font710, WHITE); + IotChangeScreen(); + usleep(SLEEP_TIME); + } + break; + + case KEY_EVENT_S2: + { + // 显示中文内容 + IotShowChinese(); + usleep(SLEEP_TIME); + } + break; + + default: + { + } + break; + } + // 轮询时间控制 + usleep(CONTROL_TIME); + } +} + +static void OLEDDemo(void) +{ + osThreadAttr_t attr; + + IoTGpioInit(HI_IO_NAME_GPIO_13); + IoTGpioInit(HI_IO_NAME_GPIO_14); + // 将引脚功能设置为I2C引脚 + hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA); + hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL); + + attr.name = "OLEDTask"; + attr.attr_bits = 0U; + attr.cb_mem = NULL; + attr.cb_size = 0U; + attr.stack_mem = NULL; + attr.stack_size = TASK_STACK_SIZE; + attr.priority = osPriorityNormal; + + if (osThreadNew(OLEDTask, NULL, &attr) == NULL) { + printf("[OLEDDemo] Failed to create OLEDTask!\n"); + } +} +SYS_RUN(OLEDDemo); diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306.c" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306.c" new file mode 100644 index 0000000000000000000000000000000000000000..164a12ce165aaa0aa52dbe9f7726ad387e73a86e --- /dev/null +++ "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306.c" @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2021-2022 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 "oled_ssd1306.h" +#include +#include +#include + +#include +#include + +#include "iot_i2c.h" +#include "iot_errno.h" + +#if defined(IOT_USE_I2C) + +#define IOT_I2C_IDX 0 + +#define IOT_CTRL_CMD 0x00 +#define IOT_CTRL_DATA 0x40 +#define IOT_MASK_CONT (0x1<<7) + +void IotReset(void) { +} + +void HalDelay(int32_t ms) +{ + int32_t msPerTick = 1000 / osKernelGetTickFreq(); + if (ms >= msPerTick) { + osDelay(ms / msPerTick); + } + + int32_t restMs = ms % msPerTick; + if (restMs > 0) { + usleep(restMs * ONE_THOUSAND); + } +} + +static int32_t IotSendData(const int8_t* data, size_t size) +{ + int id = IOT_I2C_IDX; + + return IoTI2cWrite(id, IOT_I2C_ADDER, data, size); +} + +static int32_t IotWriteByte(int8_t regAdder, int8_t byte) +{ + int8_t buffer[] = {regAdder, byte}; + return IotSendData(buffer, sizeof(buffer)); +} + +void IotWriteCmd(int8_t byte) +{ + IotWriteByte(IOT_CTRL_CMD, byte); +} + +void IotWriteData(int8_t* buffer, size_t buffSize) +{ + int8_t data[IOT_WIDTH * TWO] = {0}; + for (size_t i = 0; i < buffSize; i++) { + data[i * TWO] = IOT_CTRL_DATA | IOT_MASK_CONT; + data[i * TWO + 1] = buffer[i]; + } + data[(buffSize - 1) * TWO] = IOT_CTRL_DATA; + IotSendData(data, sizeof(data)); +} +#endif + +static int8_t g_iotBuffer[IOT_BUFFER_SIZE]; + +static IotT g_iot; + +IoTErrorT IotFillBuffer(int8_t* buf, int32_t len) +{ + IoTErrorT ret = IOT_ERR; + if (len <= IOT_BUFFER_SIZE) { + memcpy(g_iotBuffer, buf, len); + ret = IOT_OK; + } + return ret; +} + +void IotInit(void) +{ + // 复位 + IotReset(); + + // 等待屏幕启动 + HalDelay(CONTROL_TIME); + + // 初始化 + IotSetDisplayOn(0); + + IotWriteCmd(MEMORY); + IotWriteCmd(HORIZONTAL); + IotWriteCmd(PAGE); + IotWriteCmd(COM); + IotWriteCmd(HORIZONTAL); + IotWriteCmd(HIGH); + IotWriteCmd(LINE); + + // 设置对比度 + IotSetContrast(CONTRAST); + + IotWriteCmd(SEGMENT); + IotWriteCmd(NORMAL); + IotWriteCmd(MULTIPLEX); + IotWriteCmd(SEEMS); + IotWriteCmd(FOLLOWS); + IotWriteCmd(OFFSET); + IotWriteCmd(HORIZONTAL); + IotWriteCmd(FREQUENCY); + IotWriteCmd(RATIO); + IotWriteCmd(PERIOD); + IotWriteCmd(DEOI); + IotWriteCmd(PINS); + IotWriteCmd(HIS); + IotWriteCmd(VCOMH); + IotWriteCmd(VLSD); + IotWriteCmd(DCDC); + IotWriteCmd(XSDL); + IotSetDisplayOn(1); + + // 清除屏幕显示 + IotFill(BLACK); + + // 将更改后的屏幕缓冲区写入屏幕 + IotChangeScreen(); + + // 设置屏幕 + g_iot.currentX = 0; + g_iot.currentY = 0; + + g_iot.initialized = 1; +} + +// 用给定的颜色填充屏幕 +void IotFill(IOT_COLOR color) +{ + int32_t i; + for (i = 0; i < sizeof(g_iotBuffer); i++) { + g_iotBuffer[i] = (color == BLACK) ? HORIZONTAL : CONTRAST; + } +} + +void IotChangeScreen(void) +{ + const unsigned int two = 2; + int8_t cmd[] = { + 0X21, // 设置列起始和结束地址 + 0X00, // 列起始地址 0 + 0X7F, // 列终止地址 127 + 0X22, // 设置页起始和结束地址 + 0X00, // 页起始地址 0 + 0X07, // 页终止地址 7 + }; + int32_t count = 0; + int8_t data[sizeof(cmd) * TWO + IOT_BUFFER_SIZE + 1] = {}; + + for (int32_t i = 0; i < sizeof(cmd) / sizeof(cmd[0]); i++) { + data[count++] = IOT_CTRL_CMD | IOT_MASK_CONT; + data[count++] = cmd[i]; + } + + data[count++] = IOT_CTRL_DATA; + memcpy(&data[count], g_iotBuffer, sizeof(g_iotBuffer)); + count += sizeof(g_iotBuffer); + + int32_t ret = IotSendData(data, count); + if (ret != IOT_SUCCESS) { + printf("IotChangeScreen send frame data filed: %d!\r\n", ret); + } +} + +void IotShowPixel(int8_t x, int8_t y, IOT_COLOR color) +{ + const unsigned int eight = 8; + if (x >= IOT_WIDTH || y >= IOT_HEIGHT) { + return; + } + + if (g_iot.inverted) { + color = (IOT_COLOR)!color; + } + + if (color == WHITE) { + g_iotBuffer[x + (y / eight) * IOT_WIDTH] |= 1 << (y % eight); + } else { + g_iotBuffer[x + (y / eight) * IOT_WIDTH] &= ~(1 << (y % eight)); + } +} + +char IotShowChar(char ch, FontDef font, IOT_COLOR color) +{ + const unsigned int thirtyTwo = 32; + const unsigned int oHAndTwentySix = 126; + int32_t i, b, j; + + if (ch < thirtyTwo || ch > oHAndTwentySix) { + return 0; + } + + if (IOT_WIDTH < (g_iot.currentX + font.fontWidth) || + IOT_HEIGHT < (g_iot.currentY + font.fontHeight)) { + return 0; + } + + for (i = 0; i < font.fontHeight; i++) { + b = font.data[(ch - thirtyTwo) * font.fontHeight + i]; + for (j = 0; j < font.fontWidth; j++) { + if ((b << j) & QES) { + IotShowPixel(g_iot.currentX + j, (g_iot.currentY + i), (IOT_COLOR) color); + } else { + IotShowPixel(g_iot.currentX + j, (g_iot.currentY + i), (IOT_COLOR)!color); + } + } + } + + g_iot.currentX += font.fontWidth; + + return ch; +} + +char IotShowString(char* str, FontDef font, IOT_COLOR color) +{ + + while (*str) { + if (IotShowChar(*str, font, color) != *str) { + return *str; + } + + str++; + } + + return *str; +} + +void IotSetCursor(int8_t x, int8_t y) +{ + g_iot.currentX = x; + g_iot.currentY = y; +} + +void IotShowRegion(int8_t x, int8_t y, int8_t w, int8_t h, const int8_t* data, int32_t size, int32_t stride) +{ + if (x + w > IOT_WIDTH || y + h > IOT_HEIGHT || w * h == 0) { + printf("%dx%d @ %d,%d out of range or invalid!\r\n", w, h, x, y); + return; + } + + w = (w <= IOT_WIDTH ? w : IOT_WIDTH); + h = (h <= IOT_HEIGHT ? h : IOT_HEIGHT); + stride = (stride == 0 ? w : stride); + + int8_t rows = size * 8 / stride; + for (int8_t i = 0; i < rows; i++) { + int32_t base = i * stride / 8; + for (int8_t j = 0; j < w; j++) { + int32_t idx = base + (j / 8); + int8_t byte = idx < size ? data[idx] : 0; + int8_t bit = byte & (0x80 >> (j % 8)); + IotShowPixel(x + j, y + i, bit ? WHITE : BLACK); + } + } +} + +void IotSetContrast(const int8_t value) +{ + const int8_t kSetContrastControlRegister = 0x81; + IotWriteCmd(kSetContrastControlRegister); + IotWriteCmd(value); +} + +void IotSetDisplayOn(const int8_t on) +{ + int8_t value; + if (on) { + value = FSC; + g_iot.displayOn = 1; + } else { + value = FSD; + g_iot.displayOn = 0; + } + IotWriteCmd(value); +} + +int8_t IotGetDisplayOn() +{ + return g_iot.displayOn; +} diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306.h" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306.h" new file mode 100644 index 0000000000000000000000000000000000000000..b739077a0bf0b417cd3a5aa41bcbf7b55c6616ea --- /dev/null +++ "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306.h" @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021-2022 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 __SSD1306_H__ +#define __SSD1306_H__ + +#include +#include <_ansi.h> + +_BEGIN_STD_C + +#include "oled_ssd1306_conf.h" +#include "oled_ssd1306_fonts.h" + +#define IOT_USE_I2C +#define IOT_I2C_ADDER (0x3C << 1) + +#define ADC_TEST_LENGTH 64 +#define KEY_EVENT_NONE 0 +#define KEY_EVENT_S1 1 +#define KEY_EVENT_S2 2 +#define SLEEP_TIME (3 * 1000 * 1000) +#define CONTROL_TIME 100 +#define ONE_THOUSAND 1000 +#define TWO 2 +#define FOUR 0.4 +#define SIX 0.6 +#define EIGHT 0.8 +#define ONE 1.1 +#define THREE 3.0 +#define SSD1306_I2C_PORT hi2c1 +#define IOT_HEIGHT 64 +#define IOT_WIDTH 128 +#define IOT_BUFFER_SIZE (IOT_WIDTH * IOT_HEIGHT / 8) +#define MEMORY 0x20 +#define HORIZONTAL 0x00 +#define PAGE 0xB0 + +#define COM 0xC8 +#define HIGH 0x10 +#define LINE 0x40 +#define CONTRAST 0xFF + +#define SEGMENT 0xA1 + +#define NORMAL 0xA6 +#define MULTIPLEX 0xA8 +#define SEEMS 0x3F +#define FOLLOWS 0xA4 +#define OFFSET 0xD3 +#define FREQUENCY 0xD5 +#define RATIO 0xF0 +#define PERIOD 0xD9 +#define DEOI 0x11 +#define PINS 0xDA +#define HIS 0x12 +#define VCOMH 0xDB +#define VLSD 0x30 +#define DCDC 0x8D +#define XSDL 0x14 +#define QES 0x8000 +#define FSC 0xAF +#define FSD 0xAE +typedef enum { + BLACK = 0x00, + WHITE = 0x01 +} IOT_COLOR; + +typedef enum { + IOT_OK = 0x00, + IOT_ERR = 0x01 +} IoTErrorT; + +typedef struct { + int16_t currentX; + int16_t currentY; + int8_t inverted; + int8_t initialized; + int8_t displayOn; +} IotT; + +void IotInit(void); +void IotFill(IOT_COLOR color); +void IotSetCursor(int8_t x, int8_t y); +void IotChangeScreen(void); +char IotShowChar(char ch, FontDef font, IOT_COLOR color); +char IotShowString(char* str, FontDef font, IOT_COLOR color); +void IotShowPixel(int8_t x, int8_t y, IOT_COLOR color); +void IotShowRegion(int8_t x, int8_t y, int8_t w, int8_t h, const int8_t* data, int32_t size, int32_t stride); +void IotSetContrast(const int8_t value); +void IotSetDisplayOn(const int8_t on); +int8_t IotGetDisplayOn(void); +void HalDelay(int32_t ms); +void IotReset(void); +void IotWriteCmd(int8_t byte); +void IotWriteData(int8_t* buffer, size_t buffSize); +IoTErrorT IotFillBuffer(int8_t* buf, int32_t len); + +_END_STD_C + +#endif diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_conf.h" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_conf.h" new file mode 100644 index 0000000000000000000000000000000000000000..c05e81de1d4f028ea6c395ba509e5b06a09709ba --- /dev/null +++ "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_conf.h" @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021-2022 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 __SSD1306_CONF_H__ +#define __SSD1306_CONF_H__ + +#define IOT_INCLUDE_FONT_6X8 +#define IOT_INCLUDE_FONT_7X10 +#define IOT_INCLUDE_FONT_11X18 +#define IOT_INCLUDE_FONT_16X26 + +#endif \ No newline at end of file diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_fonts.c" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_fonts.c" new file mode 100644 index 0000000000000000000000000000000000000000..a8573ccff799605d5cbeb7f62c6d36eb9c896b16 --- /dev/null +++ "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_fonts.c" @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2021-2022 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 "oled_ssd1306_fonts.h" +#include "oled_ssd1306_conf.h" + +#ifdef IOT_INCLUDE_FONT_7X10 +static const int16_t g_font7x10 [] = { +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // sp +0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x0000, 0x0000, // ! +0x2800, 0x2800, 0x2800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // " +0x2400, 0x2400, 0x7C00, 0x2400, 0x4800, 0x7C00, 0x4800, 0x4800, 0x0000, 0x0000, // # +0x3800, 0x5400, 0x5000, 0x3800, 0x1400, 0x5400, 0x5400, 0x3800, 0x1000, 0x0000, // $ +0x2000, 0x5400, 0x5800, 0x3000, 0x2800, 0x5400, 0x1400, 0x0800, 0x0000, 0x0000, // % +0x1000, 0x2800, 0x2800, 0x1000, 0x3400, 0x4800, 0x4800, 0x3400, 0x0000, 0x0000, // & +0x1000, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ' +0x0800, 0x1000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x1000, 0x0800, // ( +0x2000, 0x1000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x1000, 0x2000, // ) +0x1000, 0x3800, 0x1000, 0x2800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // * +0x0000, 0x0000, 0x1000, 0x1000, 0x7C00, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, // + +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x1000, 0x1000, // , +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3800, 0x0000, 0x0000, 0x0000, 0x0000, // - +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, // . +0x0800, 0x0800, 0x1000, 0x1000, 0x1000, 0x1000, 0x2000, 0x2000, 0x0000, 0x0000, // / +0x3800, 0x4400, 0x4400, 0x5400, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // 0 +0x1000, 0x3000, 0x5000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // 1 +0x3800, 0x4400, 0x4400, 0x0400, 0x0800, 0x1000, 0x2000, 0x7C00, 0x0000, 0x0000, // 2 +0x3800, 0x4400, 0x0400, 0x1800, 0x0400, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // 3 +0x0800, 0x1800, 0x2800, 0x2800, 0x4800, 0x7C00, 0x0800, 0x0800, 0x0000, 0x0000, // 4 +0x7C00, 0x4000, 0x4000, 0x7800, 0x0400, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // 5 +0x3800, 0x4400, 0x4000, 0x7800, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // 6 +0x7C00, 0x0400, 0x0800, 0x1000, 0x1000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, // 7 +0x3800, 0x4400, 0x4400, 0x3800, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // 8 +0x3800, 0x4400, 0x4400, 0x4400, 0x3C00, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // 9 +0x0000, 0x0000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, // : +0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000, 0x0000, 0x1000, 0x1000, 0x1000, // ; +0x0000, 0x0000, 0x0C00, 0x3000, 0x4000, 0x3000, 0x0C00, 0x0000, 0x0000, 0x0000, // < +0x0000, 0x0000, 0x0000, 0x7C00, 0x0000, 0x7C00, 0x0000, 0x0000, 0x0000, 0x0000, // = +0x0000, 0x0000, 0x6000, 0x1800, 0x0400, 0x1800, 0x6000, 0x0000, 0x0000, 0x0000, // > +0x3800, 0x4400, 0x0400, 0x0800, 0x1000, 0x1000, 0x0000, 0x1000, 0x0000, 0x0000, // ? +0x3800, 0x4400, 0x4C00, 0x5400, 0x5C00, 0x4000, 0x4000, 0x3800, 0x0000, 0x0000, // @ +0x1000, 0x2800, 0x2800, 0x2800, 0x2800, 0x7C00, 0x4400, 0x4400, 0x0000, 0x0000, // A +0x7800, 0x4400, 0x4400, 0x7800, 0x4400, 0x4400, 0x4400, 0x7800, 0x0000, 0x0000, // B +0x3800, 0x4400, 0x4000, 0x4000, 0x4000, 0x4000, 0x4400, 0x3800, 0x0000, 0x0000, // C +0x7000, 0x4800, 0x4400, 0x4400, 0x4400, 0x4400, 0x4800, 0x7000, 0x0000, 0x0000, // D +0x7C00, 0x4000, 0x4000, 0x7C00, 0x4000, 0x4000, 0x4000, 0x7C00, 0x0000, 0x0000, // E +0x7C00, 0x4000, 0x4000, 0x7800, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, // F +0x3800, 0x4400, 0x4000, 0x4000, 0x5C00, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // G +0x4400, 0x4400, 0x4400, 0x7C00, 0x4400, 0x4400, 0x4400, 0x4400, 0x0000, 0x0000, // H +0x3800, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x3800, 0x0000, 0x0000, // I +0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // J +0x4400, 0x4800, 0x5000, 0x6000, 0x5000, 0x4800, 0x4800, 0x4400, 0x0000, 0x0000, // K +0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x7C00, 0x0000, 0x0000, // L +0x4400, 0x6C00, 0x6C00, 0x5400, 0x4400, 0x4400, 0x4400, 0x4400, 0x0000, 0x0000, // M +0x4400, 0x6400, 0x6400, 0x5400, 0x5400, 0x4C00, 0x4C00, 0x4400, 0x0000, 0x0000, // N +0x3800, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // O +0x7800, 0x4400, 0x4400, 0x4400, 0x7800, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, // P +0x3800, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x5400, 0x3800, 0x0400, 0x0000, // Q +0x7800, 0x4400, 0x4400, 0x4400, 0x7800, 0x4800, 0x4800, 0x4400, 0x0000, 0x0000, // R +0x3800, 0x4400, 0x4000, 0x3000, 0x0800, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, // S +0x7C00, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // T +0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // U +0x4400, 0x4400, 0x4400, 0x2800, 0x2800, 0x2800, 0x1000, 0x1000, 0x0000, 0x0000, // V +0x4400, 0x4400, 0x5400, 0x5400, 0x5400, 0x6C00, 0x2800, 0x2800, 0x0000, 0x0000, // W +0x4400, 0x2800, 0x2800, 0x1000, 0x1000, 0x2800, 0x2800, 0x4400, 0x0000, 0x0000, // X +0x4400, 0x4400, 0x2800, 0x2800, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // Y +0x7C00, 0x0400, 0x0800, 0x1000, 0x1000, 0x2000, 0x4000, 0x7C00, 0x0000, 0x0000, // Z +0x1800, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1800, // [ +0x2000, 0x2000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0000, 0x0000, /* \ */ +0x3000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x3000, // ] +0x1000, 0x2800, 0x2800, 0x4400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ^ +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFE00, // _ +0x2000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ` +0x0000, 0x0000, 0x3800, 0x4400, 0x3C00, 0x4400, 0x4C00, 0x3400, 0x0000, 0x0000, // a +0x4000, 0x4000, 0x5800, 0x6400, 0x4400, 0x4400, 0x6400, 0x5800, 0x0000, 0x0000, // b +0x0000, 0x0000, 0x3800, 0x4400, 0x4000, 0x4000, 0x4400, 0x3800, 0x0000, 0x0000, // c +0x0400, 0x0400, 0x3400, 0x4C00, 0x4400, 0x4400, 0x4C00, 0x3400, 0x0000, 0x0000, // d +0x0000, 0x0000, 0x3800, 0x4400, 0x7C00, 0x4000, 0x4400, 0x3800, 0x0000, 0x0000, // e +0x0C00, 0x1000, 0x7C00, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // f +0x0000, 0x0000, 0x3400, 0x4C00, 0x4400, 0x4400, 0x4C00, 0x3400, 0x0400, 0x7800, // g +0x4000, 0x4000, 0x5800, 0x6400, 0x4400, 0x4400, 0x4400, 0x4400, 0x0000, 0x0000, // h +0x1000, 0x0000, 0x7000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // i +0x1000, 0x0000, 0x7000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0xE000, // j +0x4000, 0x4000, 0x4800, 0x5000, 0x6000, 0x5000, 0x4800, 0x4400, 0x0000, 0x0000, // k +0x7000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, // l +0x0000, 0x0000, 0x7800, 0x5400, 0x5400, 0x5400, 0x5400, 0x5400, 0x0000, 0x0000, // m +0x0000, 0x0000, 0x5800, 0x6400, 0x4400, 0x4400, 0x4400, 0x4400, 0x0000, 0x0000, // n +0x0000, 0x0000, 0x3800, 0x4400, 0x4400, 0x4400, 0x4400, 0x3800, 0x0000, 0x0000, // o +0x0000, 0x0000, 0x5800, 0x6400, 0x4400, 0x4400, 0x6400, 0x5800, 0x4000, 0x4000, // p +0x0000, 0x0000, 0x3400, 0x4C00, 0x4400, 0x4400, 0x4C00, 0x3400, 0x0400, 0x0400, // q +0x0000, 0x0000, 0x5800, 0x6400, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, // r +0x0000, 0x0000, 0x3800, 0x4400, 0x3000, 0x0800, 0x4400, 0x3800, 0x0000, 0x0000, // s +0x2000, 0x2000, 0x7800, 0x2000, 0x2000, 0x2000, 0x2000, 0x1800, 0x0000, 0x0000, // t +0x0000, 0x0000, 0x4400, 0x4400, 0x4400, 0x4400, 0x4C00, 0x3400, 0x0000, 0x0000, // u +0x0000, 0x0000, 0x4400, 0x4400, 0x2800, 0x2800, 0x2800, 0x1000, 0x0000, 0x0000, // v +0x0000, 0x0000, 0x5400, 0x5400, 0x5400, 0x6C00, 0x2800, 0x2800, 0x0000, 0x0000, // w +0x0000, 0x0000, 0x4400, 0x2800, 0x1000, 0x1000, 0x2800, 0x4400, 0x0000, 0x0000, // x +0x0000, 0x0000, 0x4400, 0x4400, 0x2800, 0x2800, 0x1000, 0x1000, 0x1000, 0x6000, // y +0x0000, 0x0000, 0x7C00, 0x0800, 0x1000, 0x2000, 0x4000, 0x7C00, 0x0000, 0x0000, // z +0x1800, 0x1000, 0x1000, 0x1000, 0x2000, 0x2000, 0x1000, 0x1000, 0x1000, 0x1800, // { +0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, // | +0x3000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x1000, 0x1000, 0x1000, 0x3000, // } +0x0000, 0x0000, 0x0000, 0x7400, 0x4C00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ~ +}; +#endif + +#ifdef IOT_INCLUDE_FONT_11X18 +static const int16_t g_font11x18 [] = { +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // sp +0x0000, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, +0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // ! +0x0000, 0x1B00, 0x1B00, 0x1B00, 0x1B00, 0x1B00, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // " +0x0000, 0x1980, 0x1980, 0x1980, 0x1980, 0x7FC0, 0x7FC0, 0x1980, 0x3300, +0x7FC0, 0x7FC0, 0x3300, 0x3300, 0x3300, 0x3300, 0x0000, 0x0000, 0x0000, // # +0x0000, 0x1E00, 0x3F00, 0x7580, 0x6580, 0x7400, 0x3C00, 0x1E00, 0x0700, +0x0580, 0x6580, 0x6580, 0x7580, 0x3F00, 0x1E00, 0x0400, 0x0400, 0x0000, // $ +0x0000, 0x7000, 0xD800, 0xD840, 0xD8C0, 0xD980, 0x7300, 0x0600, 0x0C00, +0x1B80, 0x36C0, 0x66C0, 0x46C0, 0x06C0, 0x0380, 0x0000, 0x0000, 0x0000, // % +0x0000, 0x1E00, 0x3F00, 0x3300, 0x3300, 0x3300, 0x1E00, 0x0C00, 0x3CC0, +0x66C0, 0x6380, 0x6180, 0x6380, 0x3EC0, 0x1C80, 0x0000, 0x0000, 0x0000, // & +0x0000, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ' +0x0080, 0x0100, 0x0300, 0x0600, 0x0600, 0x0400, 0x0C00, 0x0C00, 0x0C00, +0x0C00, 0x0C00, 0x0C00, 0x0400, 0x0600, 0x0600, 0x0300, 0x0100, 0x0080, // ( +0x2000, 0x1000, 0x1800, 0x0C00, 0x0C00, 0x0400, 0x0600, 0x0600, 0x0600, +0x0600, 0x0600, 0x0600, 0x0400, 0x0C00, 0x0C00, 0x1800, 0x1000, 0x2000, // ) +0x0000, 0x0C00, 0x2D00, 0x3F00, 0x1E00, 0x3300, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // * +0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0xFFC0, 0xFFC0, +0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // + +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0400, 0x0400, 0x0800, // , +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x1E00, 0x1E00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // - +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // . +0x0000, 0x0300, 0x0300, 0x0300, 0x0600, 0x0600, 0x0600, 0x0600, 0x0C00, +0x0C00, 0x0C00, 0x0C00, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, // / +0x0000, 0x1E00, 0x3F00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6D80, 0x6D80, +0x6180, 0x6180, 0x6180, 0x3300, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 0 +0x0000, 0x0600, 0x0E00, 0x1E00, 0x3600, 0x2600, 0x0600, 0x0600, 0x0600, +0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, // 1 +0x0000, 0x1E00, 0x3F00, 0x7380, 0x6180, 0x6180, 0x0180, 0x0300, 0x0600, +0x0C00, 0x1800, 0x3000, 0x6000, 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, // 2 +0x0000, 0x1C00, 0x3E00, 0x6300, 0x6300, 0x0300, 0x0E00, 0x0E00, 0x0300, +0x0180, 0x0180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 3 +0x0000, 0x0600, 0x0E00, 0x0E00, 0x1E00, 0x1E00, 0x1600, 0x3600, 0x3600, +0x6600, 0x7F80, 0x7F80, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, // 4 +0x0000, 0x7F00, 0x7F00, 0x6000, 0x6000, 0x6000, 0x6E00, 0x7F00, 0x6380, +0x0180, 0x0180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 5 +0x0000, 0x1E00, 0x3F00, 0x3380, 0x6180, 0x6000, 0x6E00, 0x7F00, 0x7380, +0x6180, 0x6180, 0x6180, 0x3380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 6 +0x0000, 0x7F80, 0x7F80, 0x0180, 0x0300, 0x0300, 0x0600, 0x0600, 0x0C00, +0x0C00, 0x0C00, 0x0800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, // 7 +0x0000, 0x1E00, 0x3F00, 0x6380, 0x6180, 0x6180, 0x2100, 0x1E00, 0x3F00, +0x6180, 0x6180, 0x6180, 0x6180, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 8 +0x0000, 0x1E00, 0x3F00, 0x7300, 0x6180, 0x6180, 0x6180, 0x7380, 0x3F80, +0x1D80, 0x0180, 0x6180, 0x7300, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // 9 +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // : +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0C00, 0x0C00, 0x0400, 0x0400, 0x0800, // ; +0x0000, 0x0000, 0x0000, 0x0000, 0x0080, 0x0380, 0x0E00, 0x3800, 0x6000, +0x3800, 0x0E00, 0x0380, 0x0080, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // < +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7F80, 0x7F80, 0x0000, 0x0000, +0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // = +0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x7000, 0x1C00, 0x0700, 0x0180, +0x0700, 0x1C00, 0x7000, 0x4000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // > +0x0000, 0x1F00, 0x3F80, 0x71C0, 0x60C0, 0x00C0, 0x01C0, 0x0380, 0x0700, +0x0E00, 0x0C00, 0x0C00, 0x0000, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // ? +0x0000, 0x1E00, 0x3F00, 0x3180, 0x7180, 0x6380, 0x6F80, 0x6D80, 0x6D80, +0x6F80, 0x6780, 0x6000, 0x3200, 0x3E00, 0x1C00, 0x0000, 0x0000, 0x0000, // @ +0x0000, 0x0E00, 0x0E00, 0x1B00, 0x1B00, 0x1B00, 0x1B00, 0x3180, 0x3180, +0x3F80, 0x3F80, 0x3180, 0x60C0, 0x60C0, 0x60C0, 0x0000, 0x0000, 0x0000, // A +0x0000, 0x7C00, 0x7E00, 0x6300, 0x6300, 0x6300, 0x6300, 0x7E00, 0x7E00, +0x6300, 0x6180, 0x6180, 0x6380, 0x7F00, 0x7E00, 0x0000, 0x0000, 0x0000, // B +0x0000, 0x1E00, 0x3F00, 0x3180, 0x6180, 0x6000, 0x6000, 0x6000, 0x6000, +0x6000, 0x6000, 0x6180, 0x3180, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // C +0x0000, 0x7C00, 0x7F00, 0x6300, 0x6380, 0x6180, 0x6180, 0x6180, 0x6180, +0x6180, 0x6180, 0x6300, 0x6300, 0x7E00, 0x7C00, 0x0000, 0x0000, 0x0000, // D +0x0000, 0x7F80, 0x7F80, 0x6000, 0x6000, 0x6000, 0x6000, 0x7F00, 0x7F00, +0x6000, 0x6000, 0x6000, 0x6000, 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, // E +0x0000, 0x7F80, 0x7F80, 0x6000, 0x6000, 0x6000, 0x6000, 0x7F00, 0x7F00, +0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, // F +0x0000, 0x1E00, 0x3F00, 0x3180, 0x6180, 0x6000, 0x6000, 0x6000, 0x6380, +0x6380, 0x6180, 0x6180, 0x3180, 0x3F80, 0x1E00, 0x0000, 0x0000, 0x0000, // G +0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x7F80, 0x7F80, +0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, // H +0x0000, 0x3F00, 0x3F00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, +0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x3F00, 0x3F00, 0x0000, 0x0000, 0x0000, // I +0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, +0x0180, 0x6180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // J +0x0000, 0x60C0, 0x6180, 0x6300, 0x6600, 0x6600, 0x6C00, 0x7800, 0x7C00, +0x6600, 0x6600, 0x6300, 0x6180, 0x6180, 0x60C0, 0x0000, 0x0000, 0x0000, // K +0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, +0x6000, 0x6000, 0x6000, 0x6000, 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, // L +0x0000, 0x71C0, 0x71C0, 0x7BC0, 0x7AC0, 0x6AC0, 0x6AC0, 0x6EC0, 0x64C0, +0x60C0, 0x60C0, 0x60C0, 0x60C0, 0x60C0, 0x60C0, 0x0000, 0x0000, 0x0000, // M +0x0000, 0x7180, 0x7180, 0x7980, 0x7980, 0x7980, 0x6D80, 0x6D80, 0x6D80, +0x6580, 0x6780, 0x6780, 0x6780, 0x6380, 0x6380, 0x0000, 0x0000, 0x0000, // N +0x0000, 0x1E00, 0x3F00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, +0x6180, 0x6180, 0x6180, 0x3300, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // O +0x0000, 0x7E00, 0x7F00, 0x6380, 0x6180, 0x6180, 0x6180, 0x6380, 0x7F00, +0x7E00, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, // P +0x0000, 0x1E00, 0x3F00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, +0x6180, 0x6580, 0x6780, 0x3300, 0x3F80, 0x1E40, 0x0000, 0x0000, 0x0000, // Q +0x0000, 0x7E00, 0x7F00, 0x6380, 0x6180, 0x6180, 0x6380, 0x7F00, 0x7E00, +0x6600, 0x6300, 0x6300, 0x6180, 0x6180, 0x60C0, 0x0000, 0x0000, 0x0000, // R +0x0000, 0x0E00, 0x1F00, 0x3180, 0x3180, 0x3000, 0x3800, 0x1E00, 0x0700, +0x0380, 0x6180, 0x6180, 0x3180, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // S +0x0000, 0xFFC0, 0xFFC0, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, +0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // T +0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, +0x6180, 0x6180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // U +0x0000, 0x60C0, 0x60C0, 0x60C0, 0x3180, 0x3180, 0x3180, 0x1B00, 0x1B00, +0x1B00, 0x1B00, 0x0E00, 0x0E00, 0x0E00, 0x0400, 0x0000, 0x0000, 0x0000, // V +0x0000, 0xC0C0, 0xC0C0, 0xC0C0, 0xC0C0, 0xC0C0, 0xCCC0, 0x4C80, 0x4C80, +0x5E80, 0x5280, 0x5280, 0x7380, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, // W +0x0000, 0xC0C0, 0x6080, 0x6180, 0x3300, 0x3B00, 0x1E00, 0x0C00, 0x0C00, +0x1E00, 0x1F00, 0x3B00, 0x7180, 0x6180, 0xC0C0, 0x0000, 0x0000, 0x0000, // X +0x0000, 0xC0C0, 0x6180, 0x6180, 0x3300, 0x3300, 0x1E00, 0x1E00, 0x0C00, +0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // Y +0x0000, 0x3F80, 0x3F80, 0x0180, 0x0300, 0x0300, 0x0600, 0x0C00, 0x0C00, +0x1800, 0x1800, 0x3000, 0x6000, 0x7F80, 0x7F80, 0x0000, 0x0000, 0x0000, // Z +0x0F00, 0x0F00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, +0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0F00, 0x0F00, // [ +0x0000, 0x1800, 0x1800, 0x1800, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0600, +0x0600, 0x0600, 0x0600, 0x0300, 0x0300, 0x0300, 0x0000, 0x0000, 0x0000, /* \ */ +0x1E00, 0x1E00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, +0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x1E00, 0x1E00, // ] +0x0000, 0x0C00, 0x0C00, 0x1E00, 0x1200, 0x3300, 0x3300, 0x6180, 0x6180, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ^ +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFE0, 0x0000, // _ +0x0000, 0x3800, 0x1800, 0x0C00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ` +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1F00, 0x3F80, 0x6180, 0x0180, +0x1F80, 0x3F80, 0x6180, 0x6380, 0x7F80, 0x38C0, 0x0000, 0x0000, 0x0000, // a +0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6E00, 0x7F00, 0x7380, 0x6180, +0x6180, 0x6180, 0x6180, 0x7380, 0x7F00, 0x6E00, 0x0000, 0x0000, 0x0000, // b +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1E00, 0x3F00, 0x7380, 0x6180, +0x6000, 0x6000, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // c +0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x1D80, 0x3F80, 0x7380, 0x6180, +0x6180, 0x6180, 0x6180, 0x7380, 0x3F80, 0x1D80, 0x0000, 0x0000, 0x0000, // d +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1E00, 0x3F00, 0x7300, 0x6180, +0x7F80, 0x7F80, 0x6000, 0x7180, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // e +0x0000, 0x07C0, 0x0FC0, 0x0C00, 0x0C00, 0x7F80, 0x7F80, 0x0C00, 0x0C00, +0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, // f +0x0000, 0x0000, 0x0000, 0x0000, 0x1D80, 0x3F80, 0x7380, 0x6180, 0x6180, +0x6180, 0x6180, 0x7380, 0x3F80, 0x1D80, 0x0180, 0x6380, 0x7F00, 0x3E00, // g +0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6F00, 0x7F80, 0x7180, 0x6180, +0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, // h +0x0000, 0x0600, 0x0600, 0x0000, 0x0000, 0x3E00, 0x3E00, 0x0600, 0x0600, +0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, // i +0x0600, 0x0600, 0x0000, 0x0000, 0x3E00, 0x3E00, 0x0600, 0x0600, 0x0600, +0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x4600, 0x7E00, 0x3C00, // j +0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6180, 0x6300, 0x6600, 0x6C00, +0x7C00, 0x7600, 0x6300, 0x6300, 0x6180, 0x60C0, 0x0000, 0x0000, 0x0000, // k +0x0000, 0x3E00, 0x3E00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, +0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, // l +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDD80, 0xFFC0, 0xCEC0, 0xCCC0, +0xCCC0, 0xCCC0, 0xCCC0, 0xCCC0, 0xCCC0, 0xCCC0, 0x0000, 0x0000, 0x0000, // m +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6F00, 0x7F80, 0x7180, 0x6180, +0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, // n +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1E00, 0x3F00, 0x7380, 0x6180, +0x6180, 0x6180, 0x6180, 0x7380, 0x3F00, 0x1E00, 0x0000, 0x0000, 0x0000, // o +0x0000, 0x0000, 0x0000, 0x0000, 0x6E00, 0x7F00, 0x7380, 0x6180, 0x6180, +0x6180, 0x6180, 0x7380, 0x7F00, 0x6E00, 0x6000, 0x6000, 0x6000, 0x6000, // p +0x0000, 0x0000, 0x0000, 0x0000, 0x1D80, 0x3F80, 0x7380, 0x6180, 0x6180, +0x6180, 0x6180, 0x7380, 0x3F80, 0x1D80, 0x0180, 0x0180, 0x0180, 0x0180, // q +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6700, 0x3F80, 0x3900, 0x3000, +0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x0000, // r +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1E00, 0x3F80, 0x6180, 0x6000, +0x7F00, 0x3F80, 0x0180, 0x6180, 0x7F00, 0x1E00, 0x0000, 0x0000, 0x0000, // s +0x0000, 0x0000, 0x0800, 0x1800, 0x1800, 0x7F00, 0x7F00, 0x1800, 0x1800, +0x1800, 0x1800, 0x1800, 0x1800, 0x1F80, 0x0F80, 0x0000, 0x0000, 0x0000, // t +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, +0x6180, 0x6180, 0x6180, 0x6380, 0x7F80, 0x3D80, 0x0000, 0x0000, 0x0000, // u +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x60C0, 0x3180, 0x3180, 0x3180, +0x1B00, 0x1B00, 0x1B00, 0x0E00, 0x0E00, 0x0600, 0x0000, 0x0000, 0x0000, // v +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xDD80, 0xDD80, 0xDD80, 0x5500, +0x5500, 0x5500, 0x7700, 0x7700, 0x2200, 0x2200, 0x0000, 0x0000, 0x0000, // w +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x3300, 0x3300, 0x1E00, +0x0C00, 0x0C00, 0x1E00, 0x3300, 0x3300, 0x6180, 0x0000, 0x0000, 0x0000, // x +0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x3180, 0x3300, 0x3300, +0x1B00, 0x1B00, 0x1B00, 0x0E00, 0x0E00, 0x0E00, 0x1C00, 0x7C00, 0x7000, // y +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FC0, 0x0180, 0x0300, +0x0600, 0x0C00, 0x1800, 0x3000, 0x7FC0, 0x7FC0, 0x0000, 0x0000, 0x0000, // z +0x0380, 0x0780, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0E00, 0x1C00, +0x1C00, 0x0E00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0780, 0x0380, // { +0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, +0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, // | +0x3800, 0x3C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0E00, 0x0700, +0x0700, 0x0E00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x0C00, 0x3C00, 0x3800, // } +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3880, 0x7F80, +0x4700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ~ +}; +#endif +#ifdef IOT_INCLUDE_FONT_16X26 +static const int16_t g_font16x26 [] = { +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [ ] +0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03C0, +0x03C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x0000, 0x0000, 0x0000, +0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [!] +0x1E3C, 0x1E3C, 0x1E3C, 0x1E3C, 0x1E3C, 0x1E3C, 0x1E3C, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = ["] +0x01CE, 0x03CE, 0x03DE, 0x039E, 0x039C, 0x079C, 0x3FFF, 0x7FFF, 0x0738, +0x0F38, 0x0F78, 0x0F78, 0x0E78, 0xFFFF, 0xFFFF, 0x1EF0, 0x1CF0, 0x1CE0, +0x3CE0, 0x3DE0, 0x39E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [#] +0x03FC, 0x0FFE, 0x1FEE, 0x1EE0, 0x1EE0, 0x1EE0, 0x1EE0, 0x1FE0, 0x0FE0, +0x07E0, 0x03F0, 0x01FC, 0x01FE, 0x01FE, 0x01FE, 0x01FE, 0x01FE, 0x01FE, +0x3DFE, 0x3FFC, 0x0FF0, 0x01E0, 0x01E0, 0x0000, 0x0000, 0x0000, // Ascii = [$] +0x3E03, 0xF707, 0xE78F, 0xE78E, 0xE39E, 0xE3BC, 0xE7B8, 0xE7F8, 0xF7F0, +0x3FE0, 0x01C0, 0x03FF, 0x07FF, 0x07F3, 0x0FF3, 0x1EF3, 0x3CF3, 0x38F3, +0x78F3, 0xF07F, 0xE03F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [%] +0x07E0, 0x0FF8, 0x0F78, 0x1F78, 0x1F78, 0x1F78, 0x0F78, 0x0FF0, 0x0FE0, +0x1F80, 0x7FC3, 0xFBC3, 0xF3E7, 0xF1F7, 0xF0F7, 0xF0FF, 0xF07F, 0xF83E, +0x7C7F, 0x3FFF, 0x1FEF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [&] +0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03C0, 0x01C0, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = ['] +0x003F, 0x007C, 0x01F0, 0x01E0, 0x03C0, 0x07C0, 0x0780, 0x0780, 0x0F80, +0x0F00, 0x0F00, 0x0F00, 0x0F00, 0x0F00, 0x0F00, 0x0F80, 0x0780, 0x0780, +0x07C0, 0x03C0, 0x01E0, 0x01F0, 0x007C, 0x003F, 0x000F, 0x0000, // Ascii = [(] +0x7E00, 0x1F00, 0x07C0, 0x03C0, 0x01E0, 0x01F0, 0x00F0, 0x00F0, 0x00F8, +0x0078, 0x0078, 0x0078, 0x0078, 0x0078, 0x0078, 0x00F8, 0x00F0, 0x00F0, +0x01F0, 0x01E0, 0x03C0, 0x07C0, 0x1F00, 0x7E00, 0x7800, 0x0000, // Ascii = [)] +0x03E0, 0x03C0, 0x01C0, 0x39CE, 0x3FFF, 0x3F7F, 0x0320, 0x0370, 0x07F8, +0x0F78, 0x1F3C, 0x0638, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [*] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01C0, 0x01C0, 0x01C0, +0x01C0, 0x01C0, 0x01C0, 0x01C0, 0xFFFF, 0xFFFF, 0x01C0, 0x01C0, 0x01C0, +0x01C0, 0x01C0, 0x01C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [+] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, +0x03E0, 0x03E0, 0x03E0, 0x01E0, 0x01E0, 0x01E0, 0x01C0, 0x0380, // Ascii = [, ] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3FFE, 0x3FFE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [-] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, +0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [.] +0x000F, 0x000F, 0x001E, 0x001E, 0x003C, 0x003C, 0x0078, 0x0078, 0x00F0, +0x00F0, 0x01E0, 0x01E0, 0x03C0, 0x03C0, 0x0780, 0x0780, 0x0F00, 0x0F00, +0x1E00, 0x1E00, 0x3C00, 0x3C00, 0x7800, 0x7800, 0xF000, 0x0000, // Ascii = [/] +0x07F0, 0x0FF8, 0x1F7C, 0x3E3E, 0x3C1E, 0x7C1F, 0x7C1F, 0x780F, 0x780F, +0x780F, 0x780F, 0x780F, 0x780F, 0x780F, 0x7C1F, 0x7C1F, 0x3C1E, 0x3E3E, +0x1F7C, 0x0FF8, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [0] +0x00F0, 0x07F0, 0x3FF0, 0x3FF0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, +0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, +0x01F0, 0x3FFF, 0x3FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [1] +0x0FE0, 0x3FF8, 0x3C7C, 0x003C, 0x003E, 0x003E, 0x003E, 0x003C, 0x003C, +0x007C, 0x00F8, 0x01F0, 0x03E0, 0x07C0, 0x0780, 0x0F00, 0x1E00, 0x3E00, +0x3C00, 0x3FFE, 0x3FFE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [2] +0x0FF0, 0x1FF8, 0x1C7C, 0x003E, 0x003E, 0x003E, 0x003C, 0x003C, 0x00F8, +0x0FF0, 0x0FF8, 0x007C, 0x003E, 0x001E, 0x001E, 0x001E, 0x001E, 0x003E, +0x1C7C, 0x1FF8, 0x1FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [3] +0x0078, 0x00F8, 0x00F8, 0x01F8, 0x03F8, 0x07F8, 0x07F8, 0x0F78, 0x1E78, +0x1E78, 0x3C78, 0x7878, 0x7878, 0xFFFF, 0xFFFF, 0x0078, 0x0078, 0x0078, +0x0078, 0x0078, 0x0078, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [4] +0x1FFC, 0x1FFC, 0x1FFC, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1FE0, +0x1FF8, 0x00FC, 0x007C, 0x003E, 0x003E, 0x001E, 0x003E, 0x003E, 0x003C, +0x1C7C, 0x1FF8, 0x1FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [5] +0x01FC, 0x07FE, 0x0F8E, 0x1F00, 0x1E00, 0x3E00, 0x3C00, 0x3C00, 0x3DF8, +0x3FFC, 0x7F3E, 0x7E1F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3E0F, 0x1E1F, +0x1F3E, 0x0FFC, 0x03F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [6] +0x3FFF, 0x3FFF, 0x3FFF, 0x000F, 0x001E, 0x001E, 0x003C, 0x0038, 0x0078, +0x00F0, 0x00F0, 0x01E0, 0x01E0, 0x03C0, 0x03C0, 0x0780, 0x0F80, 0x0F80, +0x0F00, 0x1F00, 0x1F00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [7] +0x07F8, 0x0FFC, 0x1F3E, 0x1E1E, 0x3E1E, 0x3E1E, 0x1E1E, 0x1F3C, 0x0FF8, +0x07F0, 0x0FF8, 0x1EFC, 0x3E3E, 0x3C1F, 0x7C1F, 0x7C0F, 0x7C0F, 0x3C1F, +0x3F3E, 0x1FFC, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [8] +0x07F0, 0x0FF8, 0x1E7C, 0x3C3E, 0x3C1E, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, +0x3C1F, 0x3E3F, 0x1FFF, 0x07EF, 0x001F, 0x001E, 0x001E, 0x003E, 0x003C, +0x38F8, 0x3FF0, 0x1FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [9] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, +0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, +0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [:] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x03E0, +0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, +0x03E0, 0x03E0, 0x03E0, 0x01E0, 0x01E0, 0x01E0, 0x03C0, 0x0380, // Ascii = [;] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x000F, 0x003F, +0x00FC, 0x03F0, 0x0FC0, 0x3F00, 0xFE00, 0x3F00, 0x0FC0, 0x03F0, 0x00FC, +0x003F, 0x000F, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [<] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [=] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xE000, 0xF800, 0x7E00, +0x1F80, 0x07E0, 0x01F8, 0x007E, 0x001F, 0x007E, 0x01F8, 0x07E0, 0x1F80, +0x7E00, 0xF800, 0xE000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [>] +0x1FF0, 0x3FFC, 0x383E, 0x381F, 0x381F, 0x001E, 0x001E, 0x003C, 0x0078, +0x00F0, 0x01E0, 0x03C0, 0x03C0, 0x07C0, 0x07C0, 0x0000, 0x0000, 0x0000, +0x07C0, 0x07C0, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [?] +0x03F8, 0x0FFE, 0x1F1E, 0x3E0F, 0x3C7F, 0x78FF, 0x79EF, 0x73C7, 0xF3C7, +0xF38F, 0xF38F, 0xF38F, 0xF39F, 0xF39F, 0x73FF, 0x7BFF, 0x79F7, 0x3C00, +0x1F1C, 0x0FFC, 0x03F8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [@] +0x0000, 0x0000, 0x0000, 0x03E0, 0x03E0, 0x07F0, 0x07F0, 0x07F0, 0x0F78, +0x0F78, 0x0E7C, 0x1E3C, 0x1E3C, 0x3C3E, 0x3FFE, 0x3FFF, 0x781F, 0x780F, +0xF00F, 0xF007, 0xF007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [A] +0x0000, 0x0000, 0x0000, 0x3FF8, 0x3FFC, 0x3C3E, 0x3C1E, 0x3C1E, 0x3C1E, +0x3C3E, 0x3C7C, 0x3FF0, 0x3FF8, 0x3C7E, 0x3C1F, 0x3C1F, 0x3C0F, 0x3C0F, +0x3C1F, 0x3FFE, 0x3FF8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [B] +0x0000, 0x0000, 0x0000, 0x01FF, 0x07FF, 0x1F87, 0x3E00, 0x3C00, 0x7C00, +0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7C00, 0x7C00, 0x3E00, 0x3F00, +0x1F83, 0x07FF, 0x01FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [C] +0x0000, 0x0000, 0x0000, 0x7FF0, 0x7FFC, 0x787E, 0x781F, 0x781F, 0x780F, +0x780F, 0x780F, 0x780F, 0x780F, 0x780F, 0x780F, 0x780F, 0x781F, 0x781E, +0x787E, 0x7FF8, 0x7FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [D] +0x0000, 0x0000, 0x0000, 0x3FFF, 0x3FFF, 0x3E00, 0x3E00, 0x3E00, 0x3E00, +0x3E00, 0x3E00, 0x3FFE, 0x3FFE, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, +0x3E00, 0x3FFF, 0x3FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [E] +0x0000, 0x0000, 0x0000, 0x1FFF, 0x1FFF, 0x1E00, 0x1E00, 0x1E00, 0x1E00, +0x1E00, 0x1E00, 0x1FFF, 0x1FFF, 0x1E00, 0x1E00, 0x1E00, 0x1E00, 0x1E00, +0x1E00, 0x1E00, 0x1E00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [F] +0x0000, 0x0000, 0x0000, 0x03FE, 0x0FFF, 0x1F87, 0x3E00, 0x7C00, 0x7C00, +0x7800, 0xF800, 0xF800, 0xF87F, 0xF87F, 0x780F, 0x7C0F, 0x7C0F, 0x3E0F, +0x1F8F, 0x0FFF, 0x03FE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [G] +0x0000, 0x0000, 0x0000, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, +0x7C1F, 0x7C1F, 0x7FFF, 0x7FFF, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x7C1F, +0x7C1F, 0x7C1F, 0x7C1F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [H] +0x0000, 0x0000, 0x0000, 0x3FFF, 0x3FFF, 0x03E0, 0x03E0, 0x03E0, 0x03E0, +0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, +0x03E0, 0x3FFF, 0x3FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [I] +0x0000, 0x0000, 0x0000, 0x1FFC, 0x1FFC, 0x007C, 0x007C, 0x007C, 0x007C, +0x007C, 0x007C, 0x007C, 0x007C, 0x007C, 0x007C, 0x007C, 0x0078, 0x0078, +0x38F8, 0x3FF0, 0x3FC0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [J] +0x0000, 0x0000, 0x0000, 0x3C1F, 0x3C1E, 0x3C3C, 0x3C78, 0x3CF0, 0x3DE0, +0x3FE0, 0x3FC0, 0x3F80, 0x3FC0, 0x3FE0, 0x3DF0, 0x3CF0, 0x3C78, 0x3C7C, +0x3C3E, 0x3C1F, 0x3C0F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [K] +0x0000, 0x0000, 0x0000, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, +0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, 0x3E00, +0x3E00, 0x3FFF, 0x3FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [L] +0x0000, 0x0000, 0x0000, 0xF81F, 0xFC1F, 0xFC1F, 0xFE3F, 0xFE3F, 0xFE3F, +0xFF7F, 0xFF77, 0xFF77, 0xF7F7, 0xF7E7, 0xF3E7, 0xF3E7, 0xF3C7, 0xF007, +0xF007, 0xF007, 0xF007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [M] +0x0000, 0x0000, 0x0000, 0x7C0F, 0x7C0F, 0x7E0F, 0x7F0F, 0x7F0F, 0x7F8F, +0x7F8F, 0x7FCF, 0x7BEF, 0x79EF, 0x79FF, 0x78FF, 0x78FF, 0x787F, 0x783F, +0x783F, 0x781F, 0x781F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [N] +0x0000, 0x0000, 0x0000, 0x07F0, 0x1FFC, 0x3E3E, 0x7C1F, 0x780F, 0x780F, +0xF80F, 0xF80F, 0xF80F, 0xF80F, 0xF80F, 0xF80F, 0x780F, 0x780F, 0x7C1F, +0x3E3E, 0x1FFC, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [O] +0x0000, 0x0000, 0x0000, 0x3FFC, 0x3FFF, 0x3E1F, 0x3E0F, 0x3E0F, 0x3E0F, +0x3E0F, 0x3E1F, 0x3E3F, 0x3FFC, 0x3FF0, 0x3E00, 0x3E00, 0x3E00, 0x3E00, +0x3E00, 0x3E00, 0x3E00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [P] +0x0000, 0x0000, 0x0000, 0x07F0, 0x1FFC, 0x3E3E, 0x7C1F, 0x780F, 0x780F, +0xF80F, 0xF80F, 0xF80F, 0xF80F, 0xF80F, 0xF80F, 0x780F, 0x780F, 0x7C1F, +0x3E3E, 0x1FFC, 0x07F8, 0x007C, 0x003F, 0x000F, 0x0003, 0x0000, // Ascii = [Q] +0x0000, 0x0000, 0x0000, 0x3FF0, 0x3FFC, 0x3C7E, 0x3C3E, 0x3C1E, 0x3C1E, +0x3C3E, 0x3C3C, 0x3CFC, 0x3FF0, 0x3FE0, 0x3DF0, 0x3CF8, 0x3C7C, 0x3C3E, +0x3C1E, 0x3C1F, 0x3C0F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [R] +0x0000, 0x0000, 0x0000, 0x07FC, 0x1FFE, 0x3E0E, 0x3C00, 0x3C00, 0x3C00, +0x3E00, 0x1FC0, 0x0FF8, 0x03FE, 0x007F, 0x001F, 0x000F, 0x000F, 0x201F, +0x3C3E, 0x3FFC, 0x1FF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [S] +0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x03E0, 0x03E0, 0x03E0, 0x03E0, +0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, +0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [T] +0x0000, 0x0000, 0x0000, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, +0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x7C0F, 0x3C1E, 0x3C1E, +0x3E3E, 0x1FFC, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [U] +0x0000, 0x0000, 0x0000, 0xF007, 0xF007, 0xF807, 0x780F, 0x7C0F, 0x3C1E, +0x3C1E, 0x3E1E, 0x1E3C, 0x1F3C, 0x1F78, 0x0F78, 0x0FF8, 0x07F0, 0x07F0, +0x07F0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [V] +0x0000, 0x0000, 0x0000, 0xE003, 0xF003, 0xF003, 0xF007, 0xF3E7, 0xF3E7, +0xF3E7, 0x73E7, 0x7BF7, 0x7FF7, 0x7FFF, 0x7F7F, 0x7F7F, 0x7F7E, 0x3F7E, +0x3E3E, 0x3E3E, 0x3E3E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [W] +0x0000, 0x0000, 0x0000, 0xF807, 0x7C0F, 0x3E1E, 0x3E3E, 0x1F3C, 0x0FF8, +0x07F0, 0x07E0, 0x03E0, 0x03E0, 0x07F0, 0x0FF8, 0x0F7C, 0x1E7C, 0x3C3E, +0x781F, 0x780F, 0xF00F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [X] +0x0000, 0x0000, 0x0000, 0xF807, 0x7807, 0x7C0F, 0x3C1E, 0x3E1E, 0x1F3C, +0x0F78, 0x0FF8, 0x07F0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, +0x03E0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [Y] +0x0000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x000F, 0x001F, 0x003E, 0x007C, +0x00F8, 0x00F0, 0x01E0, 0x03E0, 0x07C0, 0x0F80, 0x0F00, 0x1E00, 0x3E00, +0x7C00, 0x7FFF, 0x7FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [Z] +0x07FF, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, +0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, +0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x07FF, 0x07FF, 0x0000, // Ascii = [[] +0x7800, 0x7800, 0x3C00, 0x3C00, 0x1E00, 0x1E00, 0x0F00, 0x0F00, 0x0780, +0x0780, 0x03C0, 0x03C0, 0x01E0, 0x01E0, 0x00F0, 0x00F0, 0x0078, 0x0078, +0x003C, 0x003C, 0x001E, 0x001E, 0x000F, 0x000F, 0x0007, 0x0000, // Ascii = [\] +0x7FF0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, +0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, +0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x7FF0, 0x7FF0, 0x0000, // Ascii = []] +0x00C0, 0x01C0, 0x01C0, 0x03E0, 0x03E0, 0x07F0, 0x07F0, 0x0778, 0x0F78, +0x0F38, 0x1E3C, 0x1E3C, 0x3C1E, 0x3C1E, 0x380F, 0x780F, 0x7807, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [^] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, // Ascii = [_] +0x00F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [`] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0FF8, 0x3FFC, 0x3C7C, +0x003E, 0x003E, 0x003E, 0x07FE, 0x1FFE, 0x3E3E, 0x7C3E, 0x783E, 0x7C3E, +0x7C7E, 0x3FFF, 0x1FCF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [a] +0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3DF8, 0x3FFE, 0x3F3E, +0x3E1F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C1F, 0x3C1E, +0x3F3E, 0x3FFC, 0x3BF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [b] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03FE, 0x0FFF, 0x1F87, +0x3E00, 0x3E00, 0x3C00, 0x7C00, 0x7C00, 0x7C00, 0x3C00, 0x3E00, 0x3E00, +0x1F87, 0x0FFF, 0x03FE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [c] +0x001F, 0x001F, 0x001F, 0x001F, 0x001F, 0x001F, 0x07FF, 0x1FFF, 0x3E3F, +0x3C1F, 0x7C1F, 0x7C1F, 0x7C1F, 0x781F, 0x781F, 0x7C1F, 0x7C1F, 0x3C3F, +0x3E7F, 0x1FFF, 0x0FDF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [d] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03F8, 0x0FFC, 0x1F3E, +0x3E1E, 0x3C1F, 0x7C1F, 0x7FFF, 0x7FFF, 0x7C00, 0x7C00, 0x3C00, 0x3E00, +0x1F07, 0x0FFF, 0x03FE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [e] +0x01FF, 0x03E1, 0x03C0, 0x07C0, 0x07C0, 0x07C0, 0x7FFF, 0x7FFF, 0x07C0, +0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +0x07C0, 0x07C0, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [f] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07EF, 0x1FFF, 0x3E7F, +0x3C1F, 0x7C1F, 0x7C1F, 0x781F, 0x781F, 0x781F, 0x7C1F, 0x7C1F, 0x3C3F, +0x3E7F, 0x1FFF, 0x0FDF, 0x001E, 0x001E, 0x001E, 0x387C, 0x3FF8, // Ascii = [g] +0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3DFC, 0x3FFE, 0x3F9E, +0x3F1F, 0x3E1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, +0x3C1F, 0x3C1F, 0x3C1F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [h] +0x01F0, 0x01F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FE0, 0x7FE0, 0x01E0, +0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, +0x01E0, 0x01E0, 0x01E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [i] +0x00F8, 0x00F8, 0x0000, 0x0000, 0x0000, 0x0000, 0x3FF8, 0x3FF8, 0x00F8, +0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, +0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F0, 0x71F0, 0x7FE0, // Ascii = [j] +0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C1F, 0x3C3E, 0x3C7C, +0x3CF8, 0x3DF0, 0x3DE0, 0x3FC0, 0x3FC0, 0x3FE0, 0x3DF0, 0x3CF8, 0x3C7C, +0x3C3E, 0x3C1F, 0x3C1F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [k] +0x7FF0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, +0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, +0x01F0, 0x01F0, 0x01F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [l] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF79E, 0xFFFF, 0xFFFF, +0xFFFF, 0xFBE7, 0xF9E7, 0xF1C7, 0xF1C7, 0xF1C7, 0xF1C7, 0xF1C7, 0xF1C7, +0xF1C7, 0xF1C7, 0xF1C7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [m] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3DFC, 0x3FFE, 0x3F9E, +0x3F1F, 0x3E1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, 0x3C1F, +0x3C1F, 0x3C1F, 0x3C1F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [n] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07F0, 0x1FFC, 0x3E3E, +0x3C1F, 0x7C1F, 0x780F, 0x780F, 0x780F, 0x780F, 0x780F, 0x7C1F, 0x3C1F, +0x3E3E, 0x1FFC, 0x07F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [o] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3DF8, 0x3FFE, 0x3F3E, +0x3E1F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C0F, 0x3C1F, 0x3E1E, +0x3F3E, 0x3FFC, 0x3FF8, 0x3C00, 0x3C00, 0x3C00, 0x3C00, 0x3C00, // Ascii = [p] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07EE, 0x1FFE, 0x3E7E, +0x3C1E, 0x7C1E, 0x781E, 0x781E, 0x781E, 0x781E, 0x781E, 0x7C1E, 0x7C3E, +0x3E7E, 0x1FFE, 0x0FDE, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, // Ascii = [q] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1F7F, 0x1FFF, 0x1FE7, +0x1FC7, 0x1F87, 0x1F00, 0x1F00, 0x1F00, 0x1F00, 0x1F00, 0x1F00, 0x1F00, +0x1F00, 0x1F00, 0x1F00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [r] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07FC, 0x1FFE, 0x1E0E, +0x3E00, 0x3E00, 0x3F00, 0x1FE0, 0x07FC, 0x00FE, 0x003E, 0x001E, 0x001E, +0x3C3E, 0x3FFC, 0x1FF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [s] +0x0000, 0x0000, 0x0000, 0x0780, 0x0780, 0x0780, 0x7FFF, 0x7FFF, 0x0780, +0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, 0x0780, +0x07C0, 0x03FF, 0x01FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [t] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3C1E, 0x3C1E, 0x3C1E, +0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C1E, 0x3C3E, 0x3C7E, +0x3EFE, 0x1FFE, 0x0FDE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [u] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF007, 0x780F, 0x780F, +0x3C1E, 0x3C1E, 0x3E1E, 0x1E3C, 0x1E3C, 0x0F78, 0x0F78, 0x0FF0, 0x07F0, +0x07F0, 0x03E0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [v] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF003, 0xF1E3, 0xF3E3, +0xF3E7, 0xF3F7, 0xF3F7, 0x7FF7, 0x7F77, 0x7F7F, 0x7F7F, 0x7F7F, 0x3E3E, +0x3E3E, 0x3E3E, 0x3E3E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [w] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7C0F, 0x3E1E, 0x3E3C, +0x1F3C, 0x0FF8, 0x07F0, 0x07F0, 0x03E0, 0x07F0, 0x07F8, 0x0FF8, 0x1E7C, +0x3E3E, 0x3C1F, 0x781F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [x] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF807, 0x780F, 0x7C0F, +0x3C1E, 0x3C1E, 0x1E3C, 0x1E3C, 0x1F3C, 0x0F78, 0x0FF8, 0x07F0, 0x07F0, +0x03E0, 0x03E0, 0x03C0, 0x03C0, 0x03C0, 0x0780, 0x0F80, 0x7F00, // Ascii = [y] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3FFF, 0x3FFF, 0x001F, +0x003E, 0x007C, 0x00F8, 0x01F0, 0x03E0, 0x07C0, 0x0F80, 0x1F00, 0x1E00, +0x3C00, 0x7FFF, 0x7FFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [z] +0x01FE, 0x03E0, 0x03C0, 0x03C0, 0x03C0, 0x03C0, 0x01E0, 0x01E0, 0x01E0, +0x01C0, 0x03C0, 0x3F80, 0x3F80, 0x03C0, 0x01C0, 0x01E0, 0x01E0, 0x01E0, +0x03C0, 0x03C0, 0x03C0, 0x03C0, 0x03E0, 0x01FE, 0x007E, 0x0000, // Ascii = [{] +0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, +0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, +0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x0000, // Ascii = [|] +0x3FC0, 0x03E0, 0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x01C0, 0x03C0, 0x03C0, +0x01C0, 0x01E0, 0x00FE, 0x00FE, 0x01E0, 0x01C0, 0x03C0, 0x03C0, 0x01C0, +0x01E0, 0x01E0, 0x01E0, 0x01E0, 0x03E0, 0x3FC0, 0x3F00, 0x0000, // Ascii = [}] +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +0x0000, 0x0000, 0x3F07, 0x7FC7, 0x73E7, 0xF1FF, 0xF07E, 0x0000, 0x0000, +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // Ascii = [~] +}; +#endif +#ifdef IOT_INCLUDE_FONT_6X8 +static const int16_t g_font6x8 [] = { +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // sp +0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x2000, 0x0000, // ! +0x5000, 0x5000, 0x5000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // " +0x5000, 0x5000, 0xf800, 0x5000, 0xf800, 0x5000, 0x5000, 0x0000, // # +0x2000, 0x7800, 0xa000, 0x7000, 0x2800, 0xf000, 0x2000, 0x0000, // $ +0xc000, 0xc800, 0x1000, 0x2000, 0x4000, 0x9800, 0x1800, 0x0000, // % +0x4000, 0xa000, 0xa000, 0x4000, 0xa800, 0x9000, 0x6800, 0x0000, // & +0x3000, 0x3000, 0x2000, 0x4000, 0x0000, 0x0000, 0x0000, 0x0000, // ' +0x1000, 0x2000, 0x4000, 0x4000, 0x4000, 0x2000, 0x1000, 0x0000, // ( +0x4000, 0x2000, 0x1000, 0x1000, 0x1000, 0x2000, 0x4000, 0x0000, // ) +0x2000, 0xa800, 0x7000, 0xf800, 0x7000, 0xa800, 0x2000, 0x0000, // * +0x0000, 0x2000, 0x2000, 0xf800, 0x2000, 0x2000, 0x0000, 0x0000, // + +0x0000, 0x0000, 0x0000, 0x0000, 0x3000, 0x3000, 0x2000, 0x0000, // , +0x0000, 0x0000, 0x0000, 0xf800, 0x0000, 0x0000, 0x0000, 0x0000, // - +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3000, 0x3000, 0x0000, // . +0x0000, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x0000, 0x0000, // / +0x7000, 0x8800, 0x9800, 0xa800, 0xc800, 0x8800, 0x7000, 0x0000, // 0 +0x2000, 0x6000, 0x2000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, // 1 +0x7000, 0x8800, 0x0800, 0x7000, 0x8000, 0x8000, 0xf800, 0x0000, // 2 +0xf800, 0x0800, 0x1000, 0x3000, 0x0800, 0x8800, 0x7000, 0x0000, // 3 +0x1000, 0x3000, 0x5000, 0x9000, 0xf800, 0x1000, 0x1000, 0x0000, // 4 +0xf800, 0x8000, 0xf000, 0x0800, 0x0800, 0x8800, 0x7000, 0x0000, // 5 +0x3800, 0x4000, 0x8000, 0xf000, 0x8800, 0x8800, 0x7000, 0x0000, // 6 +0xf800, 0x0800, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x0000, // 7 +0x7000, 0x8800, 0x8800, 0x7000, 0x8800, 0x8800, 0x7000, 0x0000, // 8 +0x7000, 0x8800, 0x8800, 0x7800, 0x0800, 0x1000, 0xe000, 0x0000, // 9 +0x0000, 0x0000, 0x2000, 0x0000, 0x2000, 0x0000, 0x0000, 0x0000, // : +0x0000, 0x0000, 0x2000, 0x0000, 0x2000, 0x2000, 0x4000, 0x0000, // ; +0x0800, 0x1000, 0x2000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0000, // < +0x0000, 0x0000, 0xf800, 0x0000, 0xf800, 0x0000, 0x0000, 0x0000, // = +0x4000, 0x2000, 0x1000, 0x0800, 0x1000, 0x2000, 0x4000, 0x0000, // > +0x7000, 0x8800, 0x0800, 0x3000, 0x2000, 0x0000, 0x2000, 0x0000, // ? +0x7000, 0x8800, 0xa800, 0xb800, 0xb000, 0x8000, 0x7800, 0x0000, // @ +0x2000, 0x5000, 0x8800, 0x8800, 0xf800, 0x8800, 0x8800, 0x0000, // A +0xf000, 0x8800, 0x8800, 0xf000, 0x8800, 0x8800, 0xf000, 0x0000, // B +0x7000, 0x8800, 0x8000, 0x8000, 0x8000, 0x8800, 0x7000, 0x0000, // C +0xf000, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0xf000, 0x0000, // D +0xf800, 0x8000, 0x8000, 0xf000, 0x8000, 0x8000, 0xf800, 0x0000, // E +0xf800, 0x8000, 0x8000, 0xf000, 0x8000, 0x8000, 0x8000, 0x0000, // F +0x7800, 0x8800, 0x8000, 0x8000, 0x9800, 0x8800, 0x7800, 0x0000, // G +0x8800, 0x8800, 0x8800, 0xf800, 0x8800, 0x8800, 0x8800, 0x0000, // H +0x7000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, // I +0x3800, 0x1000, 0x1000, 0x1000, 0x1000, 0x9000, 0x6000, 0x0000, // J +0x8800, 0x9000, 0xa000, 0xc000, 0xa000, 0x9000, 0x8800, 0x0000, // K +0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0xf800, 0x0000, // L +0x8800, 0xd800, 0xa800, 0xa800, 0xa800, 0x8800, 0x8800, 0x0000, // M +0x8800, 0x8800, 0xc800, 0xa800, 0x9800, 0x8800, 0x8800, 0x0000, // N +0x7000, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, // O +0xf000, 0x8800, 0x8800, 0xf000, 0x8000, 0x8000, 0x8000, 0x0000, // P +0x7000, 0x8800, 0x8800, 0x8800, 0xa800, 0x9000, 0x6800, 0x0000, // Q +0xf000, 0x8800, 0x8800, 0xf000, 0xa000, 0x9000, 0x8800, 0x0000, // R +0x7000, 0x8800, 0x8000, 0x7000, 0x0800, 0x8800, 0x7000, 0x0000, // S +0xf800, 0xa800, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, // T +0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, // U +0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x5000, 0x2000, 0x0000, // V +0x8800, 0x8800, 0x8800, 0xa800, 0xa800, 0xa800, 0x5000, 0x0000, // W +0x8800, 0x8800, 0x5000, 0x2000, 0x5000, 0x8800, 0x8800, 0x0000, // X +0x8800, 0x8800, 0x5000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, // Y +0xf800, 0x0800, 0x1000, 0x7000, 0x4000, 0x8000, 0xf800, 0x0000, // Z +0x7800, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x7800, 0x0000, // [ +0x0000, 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0000, 0x0000, /* \ */ +0x7800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x7800, 0x0000, // ] +0x2000, 0x5000, 0x8800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ^ +0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf800, 0x0000, // _ +0x6000, 0x6000, 0x2000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, // ` +0x0000, 0x0000, 0x6000, 0x1000, 0x7000, 0x9000, 0x7800, 0x0000, // a +0x8000, 0x8000, 0xb000, 0xc800, 0x8800, 0xc800, 0xb000, 0x0000, // b +0x0000, 0x0000, 0x7000, 0x8800, 0x8000, 0x8800, 0x7000, 0x0000, // c +0x0800, 0x0800, 0x6800, 0x9800, 0x8800, 0x9800, 0x6800, 0x0000, // d +0x0000, 0x0000, 0x7000, 0x8800, 0xf800, 0x8000, 0x7000, 0x0000, // e +0x1000, 0x2800, 0x2000, 0x7000, 0x2000, 0x2000, 0x2000, 0x0000, // f +0x0000, 0x0000, 0x7000, 0x9800, 0x9800, 0x6800, 0x0800, 0x0000, // g +0x8000, 0x8000, 0xb000, 0xc800, 0x8800, 0x8800, 0x8800, 0x0000, // h +0x2000, 0x0000, 0x6000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, // i +0x1000, 0x0000, 0x1000, 0x1000, 0x1000, 0x9000, 0x6000, 0x0000, // j +0x8000, 0x8000, 0x9000, 0xa000, 0xc000, 0xa000, 0x9000, 0x0000, // k +0x6000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, // l +0x0000, 0x0000, 0xd000, 0xa800, 0xa800, 0xa800, 0xa800, 0x0000, // m +0x0000, 0x0000, 0xb000, 0xc800, 0x8800, 0x8800, 0x8800, 0x0000, // n +0x0000, 0x0000, 0x7000, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, // o +0x0000, 0x0000, 0xb000, 0xc800, 0xc800, 0xb000, 0x8000, 0x0000, // p +0x0000, 0x0000, 0x6800, 0x9800, 0x9800, 0x6800, 0x0800, 0x0000, // q +0x0000, 0x0000, 0xb000, 0xc800, 0x8000, 0x8000, 0x8000, 0x0000, // r +0x0000, 0x0000, 0x7800, 0x8000, 0x7000, 0x0800, 0xf000, 0x0000, // s +0x2000, 0x2000, 0xf800, 0x2000, 0x2000, 0x2800, 0x1000, 0x0000, // t +0x0000, 0x0000, 0x8800, 0x8800, 0x8800, 0x9800, 0x6800, 0x0000, // u +0x0000, 0x0000, 0x8800, 0x8800, 0x8800, 0x5000, 0x2000, 0x0000, // v +0x0000, 0x0000, 0x8800, 0x8800, 0xa800, 0xa800, 0x5000, 0x0000, // w +0x0000, 0x0000, 0x8800, 0x5000, 0x2000, 0x5000, 0x8800, 0x0000, // x +0x0000, 0x0000, 0x8800, 0x8800, 0x7800, 0x0800, 0x8800, 0x0000, // y +0x0000, 0x0000, 0xf800, 0x1000, 0x2000, 0x4000, 0xf800, 0x0000, // z +0x1000, 0x2000, 0x2000, 0x4000, 0x2000, 0x2000, 0x1000, 0x0000, // { +0x2000, 0x2000, 0x2000, 0x0000, 0x2000, 0x2000, 0x2000, 0x0000, // | +0x4000, 0x2000, 0x2000, 0x1000, 0x2000, 0x2000, 0x4000, 0x0000, // } +0x4000, 0xa800, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // ~ +}; +#endif + +#ifdef IOT_INCLUDE_FONT_6X8 +FontDef g_font68 = {6, 8, g_font6x8}; +#endif +#ifdef IOT_INCLUDE_FONT_7X10 +FontDef g_font710 = {7, 10, g_font7x10}; +#endif +#ifdef IOT_INCLUDE_FONT_11X18 +FontDef g_font1118 = {11, 18, g_font11x18}; +#endif +#ifdef IOT_INCLUDE_FONT_16X26 +FontDef g_font1626 = {16, 26, g_font16x26}; +#endif diff --git "a/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_fonts.h" "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_fonts.h" new file mode 100644 index 0000000000000000000000000000000000000000..e5a4c80fbecadf2d64c2f1efa696f97234cbdd81 --- /dev/null +++ "b/Device/OLED\345\261\217\345\271\225\347\232\204\346\230\276\347\244\272/screen/oled_ssd1306_fonts.h" @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021-2022 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 __SSD1306_FONTS_H__ +#define __SSD1306_FONTS_H__ + +#include +#include "oled_ssd1306_conf.h" + +typedef struct { + const int8_t fontWidth; + int8_t fontHeight; + const int16_t *data; +} FontDef; + +#ifdef IOT_INCLUDE_FONT_6X8 +extern FontDef g_font68; +#endif +#ifdef IOT_INCLUDE_FONT_7X10 +extern FontDef g_font710; +#endif +#ifdef IOT_INCLUDE_FONT_11X18 +extern FontDef g_font1118; +#endif +#ifdef IOT_INCLUDE_FONT_16X26 +extern FontDef g_font1626; +#endif +#endif diff --git a/Device/smart_door_access/LICENSE b/Device/smart_door_access/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..80576ef141485b36eea4aebf25af97020bc2de44 --- /dev/null +++ b/Device/smart_door_access/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved. + + 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. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/Device/smart_door_access/README.md b/Device/smart_door_access/README.md new file mode 100644 index 0000000000000000000000000000000000000000..acd5760d0ca7113df65ab8ed78aff3c4b6fccbe8 --- /dev/null +++ b/Device/smart_door_access/README.md @@ -0,0 +1,469 @@ +# 智能门禁 + +# 介绍 + +本教程主要介绍基于OpenHarmony开发的一款智能门禁的Codelab。 + +本Codelab结合了南向设备侧开发和北向应用侧开发,利用两块开发板模拟日常生活中刷门禁的场景,使用开发板A作为设备侧模拟门禁端,使用开发板B作为控制侧发送命令。 + +设备侧通过播放开关门声音来模拟开锁与关锁的动作,控制侧不仅可通过屏幕上的按钮发送开锁与关锁的命令,同时也能同步显示门锁的状态。 + +可以参考下面的流程图快速的了解基本的流程。 + +![](figures/info.png) + +应用效果展示: + +![](figures/run-small.gif) + +# 相关能力 + +主要能力介绍: + +- [OpenHarmony的WIFI 能力(Native)](https://gitee.com/openharmony/communication_wifi) +- [OpenHarmony的音频能力(Native)](https://gitee.com/openharmony/multimedia_audio_standard) +- [OpenHarmony Socket 通信能力(ets)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-socket.md) +- [OpenHarmony stage模型(API9)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/module-structure.md) + +# 搭建OpenHarmony环境 + +要运行此应用前必须先搭建好OpenHarmony的开发环境,需要准备如下设备和环境: + +- Window 10 环境 +- Ubuntu 18.04+ 环境 +- Hi3516DV300开发板套件(含有开发板、USB线、串口线和电源线) +- RK3568(又称:DAYU200)开发板套件(含有开发板、USB线、电源线) + +本demo分为南向(设备侧)开发和北向(应用侧)开发,南向与北向的环境搭建不一样,下面会分开介绍。 + +## 南向环境搭建 + +南向Window环境用来执行镜像烧录,Ubuntu环境用来执行代码下载与编译。 + +注:如果没有Ubuntu环境可以在window上安装虚拟机。由于后续编译过程对虚拟机性能有要求,这里虚拟机的硬盘容量建议分配60G以上,内存建议8G以上,CPU核心数根据电脑配置尽量调高,虚拟机安装过程这里不再详细说明。 + +1. 下载源码 + + 源码下载与编译都是在ubuntu上操作,[OpenHarmony 3.0.2 LTS 下载参考](https://gitee.com/openharmony/docs/blob/master/zh-cn/release-notes/OpenHarmony-v3.0.2-LTS.md#https://gitee.com/link?target=https%3A%2F%2Frepo.huaweicloud.com%2Fharmonyos%2Fos%2F3.0.2%2Fcode-v3.0.2-LTS.tar.gz)。 + +2. 安装依赖工具 + + ``` + sudo apt-get update && sudo apt-get install binutils git git-lfs gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip m4 bc gnutls-bin python3.8 python3-pip ruby + ``` + +3. 执行prebuilts + + 在源码根目录下执行脚本,安装编译器及二进制工具。 + + ``` + bash build/prebuilts_download.sh + ``` + +## 北向环境搭建 + +北向环境可以参考官网的教程进行安装与配置,点击下列步骤标题的链接进一步操作。 + +1. [下载DevEco Studio 3.0 Beta3](https://developer.harmonyos.com/cn/develop/deveco-studio/) +2. [配置与安装](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-deveco-studio-setup-flow-0000001218600628) + +# 代码结构解读 + +南向使用Hi3516DV300开发板,北向使用RK3568开发板。 + +代码目录分为server与client两个部分,其中server是南向代码,client是北向代码。 + +- 南向代码结构: + + ``` + ├── BUILD.gn # GN文件 + ├── bundle.json # 编译构建 + ├── include # 头文件 + │ ├── audio.h + │ ├── common.h + │ ├── hotspot.h + │ └── tcp.h + ├── ohos.build # 编译构建 + └── wav # 音频资源目录 + └── src + ├── audio.cpp # 音频程序 + ├── hotspot.cpp # WIFI热点程序 + ├── main.cpp # 主程序 + └── tcp.cpp # Tcp程序 + + ``` + +- 北向代码结构: + + ``` + ├─AppScope # app全局目录 + │ └─resources + │ └─base + │ ├─element + │ └─media + └─entry # entry目录 + └─src + └─main + ├─ets # ets代码 + │ ├─Application + │ ├─MainAbility + │ ├─model + │ ├─pages + │ └─view + └─resources # 资源目录 + └─base + ├─element + ├─media + └─profile + ``` + +# 代码合入与运行 + +## 南向代码 + +1. 拷贝代码 + + 首先通过git下载本仓库代码,然后在源代码OpenHarmony目录下创建一个文件夹demo,将本仓库代码server\\smart\_door\_access拷贝到OpenHarmony\\demo中,拷贝后路径为 OpenHarmony\\demo\\smart\_door\_access。 + + **路径中的OpenHarmony为源码根目录。** + + ![](figures/zh-cn_image_0000001240982242.png) + +2. 添加build参数 + + OpenHarmony\\build\\subsystem\_config.json 文件中添加smart\_door\_access路径和名字,此操作是为了将demo的路径加入到编译构建子系统中。 + + **此处注意Json的格式,格式不对会编译错误。** + + ``` + "smart_door_access": { + "project":"demo/smart_door_access", + "path":"demo/smart_door_access", + "name":"smart_door_access", + "dir":"demo/smart_door_access" + } + ``` + + ![](figures/zh-cn_image_0000001285254805.png) + +3. 添加production参数 + + OpenHarmony\\productdefine\\common\\products\\Hi3516DV300.json 中添加如下参数,此操作是为了将demo加入到Hi3516DV300的产品中。 + + **此处注意Json的格式,格式不对会导致编译错误** + + ``` + "demo:smart_door_access":{} + ``` + + ![](figures/zh-cn_image_0000001285375257.png) + +4. 编译 + + 输入编译命令,编译代码。 + + 首次编译时间较长请耐心等待,预计时间1h-4h(编译耗时跟电脑CPU配置有关,如果是虚拟机Ubuntu用户,建议把CPU的核心数调高,提高多线程能力),编译过程中会有编译log持续打印,编译成功会有成功log打印。 + + ``` + ./build.sh --product-name Hi3516DV300 + ``` + + ![](figures/zh-cn_image_0000001284944089.png) + + 输入查找命令,若能找到smart\_door\_access\_server文件,说明代码合入成功。 + + ``` + find ./ -name "smart_door_access_server" + ``` + + ![](figures/zh-cn_image_0000001240663090.png) + +5. 烧录 + + 从Ubuntu环境将路径OpenHarmony\\out\\ohos-arm-release\\packages\\phone\\images下的镜像文件夹拷贝到window环境上。 + + 烧写前请先断开开发板电源,将USB线与电脑连接,type-c端口先不要连接开发板。 + + window环境下打开HiTool工具选择烧写eMMC, 传输方式选择USB口,选择分区表文件(文件路径:OpenHarmony\\out\\ohos-arm-release\\packages\\phone\\images\\Hi3516DV300-emmc.xml),点击烧写按钮开始烧写,然后按下开发板的update按钮不放,将USB线的type-c口插到开发板背后的type-c端口,松开update按钮,此时会自动开始烧写,烧写过程会有日志打印,成功会有提醒。update按钮在开发板上的标注符号是sw3。 + + HiTool工具开发者可以在网上自行下载使用。 + + ![](figures/f28c7d177a793f422ccdf4ae97f65ed6_2103x1128.png) + + ![](figures/zh-cn_image_0000001240784572.png) + + ![](figures/zh-cn_image_0000001241103804.png) + + ![](figures/zh-cn_image_0000001240784568.png) + +6. 连接串口调试工具 + + 取出开发板套装中的串口线,将串口的一端连接至开发板的串口,USB一端连接至PC。串口的位置可以参考上面开发板的接口图。 + + 串口端口查看方法: + + 右键此电脑-管理-设备管理器-端口 + + ![](figures/zh-cn_image_0000001240944488.png) + + 如上图,本地电脑连接是COM4端口,打开串口工具,选择COM4,波特率选择115200,即可正常打开串口。串口工具可以使用网上常见的终端工具,比如MobaXterm等。 + +7. 启动设备侧demo + + 运行 smart\_door\_access\_server 程序命令: + + ``` + smart_door_access_server + ``` + + 开发板A运行demo后,会自动分享wifi热点,等待控制侧连接WIFI。启动成功,会有如下log。 + + ![](figures/server_run_log.png) + +## 北向代码 + +1. 点击打开Openharmony系统下载界面,找到 获取方式三:从镜像站点获取 ,下载RK3568标准系统,3.1Release版本。 + + ![](figures/zh-cn_image_0000001240845646.png) + +2. 烧录镜像 + + 参考[DAYU200烧录指导](https://gitee.com/hihope_iot/docs/tree/master/HiHope_DAYU200/%E7%83%A7%E5%86%99%E5%B7%A5%E5%85%B7%E5%8F%8A%E6%8C%87%E5%8D%97),点击按照教程进行烧录。 + +3. DevEco Studio导入代码 + + 使用DevEco Studio打开client\\SmartDoorAccess的项目。项目是使用API 9构建的,使用前要确保API 9 的SDK已经下载好。 + +4. 开发板安装hap应用 + + 按照官网[使用真机进行调试](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-debugging-and-running-0000001263040487)教程进行操作。 + +5. 开发板B连接WIFI + + 系统主页打开设置,进入WLAN界面,选择WIFI名:SmartDoorAccess ,输入密码:12345678,连接完成后,如下图所示。 + + ![](figures/client_net.png) + +6. 启动控制侧demo + 1. 打开SmartDoorAccess + + ![](figures/client-connect.png) + + 2. 点击**连接tcp**按钮,连接成功后,会出现一个锁的图片和三个新的命令控制按钮。 + 3. 点击**发送开门指令**按钮,设备侧会发出开锁的声音,同时锁的图标变成打开状态。 + + ![](figures/client_open.jpg) + + 4. 点击**发送关门指令**按钮,设备侧会发出关锁的声音,同时锁的图标变成关闭状态。 + + ![](figures/client_close.jpg) + + 5. 点击**断开tcp**按钮,断开连接。 + +# 任务一:开启WIFI热点 + +南向设备侧通过WIFI组件能力打开WIFI热点,具体步骤如下: + +1. 获取 WifiHotspot 对象 + + ``` + std::unique_ptr wifiHotspotPtr = WifiHotspot::GetInstance(WIFI_HOTSPOT_ABILITY_ID); + ``` + +2. 配置HotspotConfig + + ``` + // Wifi热点配置 + const std::string ssid = "SmartDoorAccess"; + const std::string key = "12345678"; + HotspotConfig config; + config.SetSsid(ssid); + config.SetPreSharedKey(key); + config.SetMaxConn(1); + config.SetBand(BandType::BAND_2GHZ); + config.SetSecurityType(KeyMgmt::WPA_PSK); + SAMPLE_INFO("config Ssid=%s, key=%s \r\n", config.GetSsid().c_str(), config.GetPreSharedKey().c_str()); + ret = wifiHotspotPtr->SetHotspotConfig(config); + ``` + +3. 开启热点 + + ``` + wifiHotspotPtr->EnableHotspot(); + ``` + +# 任务二:TCP通信 + +北向控制侧通过Socket API 可以执行tcp通信,具体步骤如下: + +1. 导入socket组件 + + ``` + import net_socket from '@ohos.net.socket'; + ``` + +2. 获取TCP对象 + + ``` + this.tcp = net_socket.constructTCPSocketInstance() + ``` + +3. 绑定本机IP与端口 + + ``` + this.tcp.bind({ address: '0.0.0.0', port: 8554, family: 1 }, err => { + if (err) { + logger.log('bind fail'); + return; + } + logger.log('bind success'); + }) + ``` + +4. 连接服务器 + + ``` + this.promise = this.tcp.connect({ address: { address: '192.168.1.2', port: 8556, family: 1 }, timeout: 6000 }); + this.promise.then(() => { + logger.log('connect success') + this.isConnect = true; + this.AutoFlush(); + }).catch(err => { + logger.log(`connect fail : ${err}`) + this.isConnect = false + }); + ``` + +5. 发送数据 + + ``` + private Send(order: string) { + this.tcp.send({ + data: order + }, err => { + if (err) { + logger.log('send fail'); + return; + } + logger.log('send success'); + }) + } + ``` + +6. 接收数据 + + 网络数据是uint8的字节数据,可以转化为对应的字符串使用更方便。 + + ``` + private SockOnMessage(data) { + let buffer = data.message + let dataView = new DataView(buffer) + let str = "" + for (let i = 0;i < dataView.byteLength; ++i) { + str += String.fromCharCode(dataView.getUint8(i)) + } + logger.log(str) + if (str.includes('open')) { + this.isLock = false; + } else if (str.includes('close')) { + this.isLock = true; + } + } + private Accept() { + this.tcp.on('message', buffer => { + this.SockOnMessage(buffer); + }); + } + ``` + +# 任务三:音频播放 + +南向播放音频文件: + +1. 获取 AudioRenderer 对象 + + ``` + AudioStreamType streamType = STREAM_MUSIC; // 流类型示例 + std::unique_ptr audioRenderer = AudioRenderer::Create(streamType); + ``` + +2. 初始化 AudioRenderer 参数 + + ``` + static int32_t InitializeRenderer(std::unique_ptr &audioRenderer) + { + AudioRendererParams rendererParams; + rendererParams.sampleFormat = SAMPLE_S16LE; + rendererParams.sampleRate = SAMPLE_RATE_44100; + rendererParams.channelCount = STEREO; + rendererParams.encodingType = ENCODING_PCM; + return audioRenderer->SetParams(rendererParams); + } + ``` + +3. 设置音量大小 + + ``` + audioRenderer->SetVolume(1.0); // 1.0 最大音量 + ``` + +4. 启动AudioRenderer + + ``` + audioRenderer->Start(); + ``` + +5. 播放音频文件 + + ``` + static void OpenAudioFile(std::unique_ptr &audioRenderer, std::string path) + { + const int32_t WRITE_BUFFERS_COUNT = 500; + int32_t ret = -1; + size_t bufferLen; + // 获取音频组件支持的buffer长度 + ret = audioRenderer->GetBufferSize(bufferLen); + if (ret != 0) { + SAMPLE_INFO("GetBufferSize error"); + } + // 打开音频文件 + FILE *wavFile = fopen(path.c_str(), "rb"); + uint8_t *buffer = (uint8_t *)malloc(bufferLen); + size_t bytesToWrite = 0; + int32_t bytesWritten = 0; + size_t minBytes = 4; + int32_t numBuffersToRender = WRITE_BUFFERS_COUNT; + while (numBuffersToRender) { + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesWritten = 0; + while ((static_cast(bytesWritten) < bytesToWrite) && + ((static_cast(bytesToWrite) - bytesWritten) > minBytes)) { + // 写入音频流 + bytesWritten += audioRenderer->Write(buffer + static_cast(bytesWritten), + bytesToWrite - static_cast(bytesWritten)); + if (bytesWritten < 0) { + break; + } + } + numBuffersToRender--; + } + free(buffer); + fclose(wavFile); + } + ``` + +6. 关闭AudioRenderer + + ``` + audioRenderer->Drain(); + audioRenderer->Stop(); + audioRenderer->Release(); + ``` + +# 恭喜您 + +目前您已经成功完成了本Codelab,并且学到了: + +1. 通过WIFI Native组件开启WIFI热点。 +2. 使用音频 Native组件播放音频文件。 +3. 使用Socket(ets)接口开发tcp通信程序。 \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/AppScope/app.json5 b/Device/smart_door_access/client/SmartDoorAccess/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a1a96920df692d7773bec42d4d8d2f37af4b3d49 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/AppScope/app.json5 @@ -0,0 +1,11 @@ +{ + "app": { + "bundleName": "com.huawei.smartdooraccess", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true + } +} diff --git a/Device/smart_door_access/client/SmartDoorAccess/AppScope/resources/base/element/string.json b/Device/smart_door_access/client/SmartDoorAccess/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..44e3aca4a539b849bd9e07d1d2721934eb3c80c5 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "SmartDoorAccess" + } + ] +} diff --git a/Device/smart_door_access/client/SmartDoorAccess/AppScope/resources/base/media/app_icon.png b/Device/smart_door_access/client/SmartDoorAccess/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/Device/smart_door_access/client/SmartDoorAccess/AppScope/resources/base/media/app_icon.png differ diff --git a/Device/smart_door_access/client/SmartDoorAccess/build-profile.json5 b/Device/smart_door_access/client/SmartDoorAccess/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7d18441853f8bbde636911803a4b3f3d5668cd97 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/build-profile.json5 @@ -0,0 +1,26 @@ +{ + "app": { + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/build-profile.json5 b/Device/smart_door_access/client/SmartDoorAccess/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7dc37bb919dada5132609c409200db266559004f --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/build-profile.json5 @@ -0,0 +1,13 @@ +{ + "apiType": 'stageMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/hvigorfile.js b/Device/smart_door_access/client/SmartDoorAccess/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..d7720ee6a7aad5c617d1fd2f6fc8c87067bfa32c --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/package.json b/Device/smart_door_access/client/SmartDoorAccess/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c7685ac4e7c0d79df04c96744f0d8f22cb4a9025 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/package.json @@ -0,0 +1,14 @@ +{ + "license": "ISC", + "devDependencies": {}, + "name": "entry", + "ohos": { + "org": "huawei", + "directoryLevel": "module", + "buildTool": "hvigor" + }, + "description": "example description", + "repository": {}, + "version": "1.0.0", + "dependencies": {} +} diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/Application/AbilityStage.ts b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..32dfe93ccff0375201857794de902cec4d239442 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,7 @@ +import AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/MainAbility/MainAbility.ts b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..edb9130731e04190fedab08e6446428203cadc28 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,34 @@ +import Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + + windowStage.setUIContent(this.context, "pages/index", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/model/Logger.ets b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/model/Logger.ets new file mode 100644 index 0000000000000000000000000000000000000000..ba29f55d0f435ee3303681c33f91e94bd1ca8faf --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/model/Logger.ets @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 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. + */ + +class Logger { + private prefix: string + + constructor(prefix: string) { + this.prefix = prefix + } + + log(...args: any[]) { + console.log(`[${this.prefix}].${args.join('')}`) + } + + info(...args: any[]) { + console.log(`[${this.prefix}].${args.join('')}`) + } + + debug(...args: any[]) { + console.log(`[${this.prefix}].${args.join('')}`) + } + + error(...args: any[]) { + console.log(`[${this.prefix}].${args.join('')}`) + } +} + +export default new Logger('SmartDoorAccess') \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/pages/index.ets b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..2b64fabcce67a97754a0663671645b9171ff72b2 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/pages/index.ets @@ -0,0 +1,153 @@ +import TitleBar from '../view/TitleBar' +import net_socket from '@ohos.net.socket'; +import logger from '../model/Logger' + +@Entry +@Component +struct back { + @State isConnect: boolean = false; + @State isLock: boolean = true; + isListen: boolean = false; + connectStr: string = '连接tcp' + disConnectStr: string = '断开tcp' + sendOpenStr: string = '发送开门指令' + sendCloseStr: string = '发送关门指令' + tcp: net_socket.TCPSocket = null; + promise: Promise = null; + + private AutoFlush() { + setInterval(function () { + this.Accept(); + }, 100); + } + + private SockOnMessage(data) { + let buffer = data.message + let dataView = new DataView(buffer) + let str = "" + for (let i = 0;i < dataView.byteLength; ++i) { + str += String.fromCharCode(dataView.getUint8(i)) + } + logger.log(str) + if (str.includes('open')) { + this.isLock = false; + } else if (str.includes('close')) { + this.isLock = true; + } + } + + private Accept() { + this.tcp.on('message', buffer => { + this.SockOnMessage(buffer); + }); + } + + private Connect() { + this.tcp = net_socket.constructTCPSocketInstance() + this.tcp.bind({ address: '0.0.0.0', port: 8554, family: 1 }, err => { + if (err) { + logger.log('bind fail'); + return; + } + logger.log('bind success'); + }) + this.promise = this.tcp.connect({ address: { address: '192.168.1.2', port: 8556, family: 1 }, timeout: 6000 }); + this.promise.then(() => { + logger.log('connect success') + this.isConnect = true; + this.AutoFlush(); + }).catch(err => { + logger.log(`connect fail : ${err}`) + this.isConnect = false + }); + } + + private DisConnect(){ + this.tcp.close(err => { + if (err) { + logger.log('DisConnect fail'); + return; + } + logger.log('DisConnect success'); + this.isConnect = false + }) + } + + private Send(order: string) { + this.tcp.send({ + data: order + }, err => { + if (err) { + logger.log('send fail'); + return; + } + logger.log('send success'); + }) + } + + build() { + Column() { + TitleBar() + Column() { + if (this.isConnect) { + if (this.isLock) { + Image($r('app.media.lock')) + .objectFit(ImageFit.Contain) + .width('80%') + .height('50%') + } else { + Image($r('app.media.unlock')) + .objectFit(ImageFit.Contain) + .width('80%') + .height('50%') + } + Button(this.sendOpenStr, { type: ButtonType.Normal, stateEffect: true }) + .borderRadius(8) + .backgroundColor(0x317aff) + .height('10%') + .width('80%') + .margin('1%') + .onClick(() => { + logger.log("open click"); + this.Send('open'); + }) + Button(this.sendCloseStr, { type: ButtonType.Normal, stateEffect: true }) + .borderRadius(8) + .backgroundColor(0x317aff) + .height('10%') + .width('80%') + .margin('1%') + .onClick(() => { + logger.log("close click"); + this.Send('close'); + }) + Button(this.disConnectStr, { type: ButtonType.Normal, stateEffect: true }) + .borderRadius(8) + .backgroundColor(0x317aff) + .height('10%') + .width('80%') + .margin('1%') + .onClick(() => { + logger.log("disConnectStr click"); + this.DisConnect(); + }) + } else { + Button(this.connectStr, { type: ButtonType.Normal, stateEffect: true }) + .borderRadius(8) + .backgroundColor(0x317aff) + .height('10%') + .width('80%') + .margin('1%') + .onClick(() => { + logger.log("connect click"); + this.Connect(); + this.Accept(); + }) + } + }.width('100%').height('90%').padding({ top: '1%', bottom: '1%' }) + } + .width('100%') + .height('100%') + .backgroundColor(Color.Grey) + } +} \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/view/TitleBar.ets b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/view/TitleBar.ets new file mode 100644 index 0000000000000000000000000000000000000000..2e075846455a4cc8922e49d9f4d9dac218acd380 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/ets/view/TitleBar.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 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 router from '@system.router' + +@Component +export default struct TitleBar { + private title: string | Resource = $r('app.string.MainAbility_label') + private hasBackPress: boolean = false + + aboutToAppear() { + this.hasBackPress = parseInt(router.getLength()) > 0 + } + + build() { + Row() { + if (this.hasBackPress) { + Image($r('app.media.icon')) + .width(40).height('100%') + .objectFit(ImageFit.Contain) + .onClick(() => { + router.back() + }) + } + Text(this.title) + .fontColor(Color.White) + .fontSize(30) + .layoutWeight(1) + } + .width('100%') + .height('8%') + .constraintSize({ minHeight: 70 }) + .padding({ left: 15 }) + .backgroundColor('#0D9FFB') + } +} \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/module.json5 b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d80b1c21e4056b0e5c802c4e2c8ad9be67b01dd5 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/module.json5 @@ -0,0 +1,42 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + } + ] + } +} \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/element/string.json b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..5803817fad90ab0e3fb0bd049a5ab454c68f3461 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "SmartDoorAccess" + } + ] +} \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/icon.png b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/icon.png differ diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/lock.svg b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/lock.svg new file mode 100644 index 0000000000000000000000000000000000000000..66cc5da1e2ab3b9c551474a11a417f4b17b9658a --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/lock.svg @@ -0,0 +1,13 @@ + + + Public/ic_public_lock_filled + + + + + + + + + + \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/unlock.svg b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/unlock.svg new file mode 100644 index 0000000000000000000000000000000000000000..2b301ebcbd29efc45eaa27dbe06160cc8ab7c9b8 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/media/unlock.svg @@ -0,0 +1,13 @@ + + + Public/ic_public_unlock_filled + + + + + + + + + + \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/profile/main_pages.json b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..4f0fe138cfeefd707fa478f44c9965c2aaea85d2 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/index" + ] +} \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/hvigorfile.js b/Device/smart_door_access/client/SmartDoorAccess/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..5f2735e3deeaf655828407544bbed9365c258278 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/Device/smart_door_access/client/SmartDoorAccess/package.json b/Device/smart_door_access/client/SmartDoorAccess/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c79609286547a44a219b6bd0d4d74b7089ee6a83 --- /dev/null +++ b/Device/smart_door_access/client/SmartDoorAccess/package.json @@ -0,0 +1,18 @@ +{ + "license":"ISC", + "devDependencies":{}, + "name":"smartdooraccess", + "ohos":{ + "org":"huawei", + "directoryLevel":"project", + "buildTool":"hvigor" + }, + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{ + "@ohos/hvigor-ohos-plugin":"1.0.6", + "hypium":"^1.0.0", + "@ohos/hvigor":"1.0.6" + } +} \ No newline at end of file diff --git a/Device/smart_door_access/figures/GIF-2022-5-6-17-53-58.gif b/Device/smart_door_access/figures/GIF-2022-5-6-17-53-58.gif new file mode 100644 index 0000000000000000000000000000000000000000..a3f64e532545420169f47478afa072ab4ddb6648 Binary files /dev/null and b/Device/smart_door_access/figures/GIF-2022-5-6-17-53-58.gif differ diff --git a/Device/smart_door_access/figures/client-connect.png b/Device/smart_door_access/figures/client-connect.png new file mode 100644 index 0000000000000000000000000000000000000000..5b9542b75cb74bab69a3a59acd2016639a16ccb7 Binary files /dev/null and b/Device/smart_door_access/figures/client-connect.png differ diff --git a/Device/smart_door_access/figures/client_close.jpg b/Device/smart_door_access/figures/client_close.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5d1bb8b81eb4afb4855e957e14ef5cc35a5abc1b Binary files /dev/null and b/Device/smart_door_access/figures/client_close.jpg differ diff --git a/Device/smart_door_access/figures/client_net.png b/Device/smart_door_access/figures/client_net.png new file mode 100644 index 0000000000000000000000000000000000000000..156f40d7da603cae17a74ab3be8a40086ad46dad Binary files /dev/null and b/Device/smart_door_access/figures/client_net.png differ diff --git a/Device/smart_door_access/figures/client_open.jpg b/Device/smart_door_access/figures/client_open.jpg new file mode 100644 index 0000000000000000000000000000000000000000..44d9518ce7f06bd953fbbe9f6e2aee827a9205b2 Binary files /dev/null and b/Device/smart_door_access/figures/client_open.jpg differ diff --git a/Device/smart_door_access/figures/f28c7d177a793f422ccdf4ae97f65ed6_2103x1128.png b/Device/smart_door_access/figures/f28c7d177a793f422ccdf4ae97f65ed6_2103x1128.png new file mode 100644 index 0000000000000000000000000000000000000000..c8d678403146d6d1402257e4c1db27b35d53263a Binary files /dev/null and b/Device/smart_door_access/figures/f28c7d177a793f422ccdf4ae97f65ed6_2103x1128.png differ diff --git a/Device/smart_door_access/figures/info.png b/Device/smart_door_access/figures/info.png new file mode 100644 index 0000000000000000000000000000000000000000..c0d8a79dea0124d9f7af226780d5a27d02478fb4 Binary files /dev/null and b/Device/smart_door_access/figures/info.png differ diff --git a/Device/smart_door_access/figures/run-small.gif b/Device/smart_door_access/figures/run-small.gif new file mode 100644 index 0000000000000000000000000000000000000000..9da9d21b9f12136f2051a9d3735d51826f2ad595 Binary files /dev/null and b/Device/smart_door_access/figures/run-small.gif differ diff --git a/Device/smart_door_access/figures/server_run_log.png b/Device/smart_door_access/figures/server_run_log.png new file mode 100644 index 0000000000000000000000000000000000000000..0381d1daa04676fcd439eef04bd3a111f521e59e Binary files /dev/null and b/Device/smart_door_access/figures/server_run_log.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001240663090.png b/Device/smart_door_access/figures/zh-cn_image_0000001240663090.png new file mode 100644 index 0000000000000000000000000000000000000000..b1fe5c59671fb4e54bad1c6e50ba4b1d2bef2b44 Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001240663090.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001240784568.png b/Device/smart_door_access/figures/zh-cn_image_0000001240784568.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5dbc92ae947d86c045ffea5ccd522c5160a116 Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001240784568.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001240784572.png b/Device/smart_door_access/figures/zh-cn_image_0000001240784572.png new file mode 100644 index 0000000000000000000000000000000000000000..5445236ea0742ed7365646dce4ea2a9f2a06e537 Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001240784572.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001240845646.png b/Device/smart_door_access/figures/zh-cn_image_0000001240845646.png new file mode 100644 index 0000000000000000000000000000000000000000..42ef6e263d1a3df5b280a1618037f87d23d08c98 Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001240845646.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001240944488.png b/Device/smart_door_access/figures/zh-cn_image_0000001240944488.png new file mode 100644 index 0000000000000000000000000000000000000000..8c54504710ba61bbee0993662a35953d1da08b0e Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001240944488.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001240982242.png b/Device/smart_door_access/figures/zh-cn_image_0000001240982242.png new file mode 100644 index 0000000000000000000000000000000000000000..7ad73dc271ffdc17152684b1fb8b1f129b7c8661 Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001240982242.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001241103804.png b/Device/smart_door_access/figures/zh-cn_image_0000001241103804.png new file mode 100644 index 0000000000000000000000000000000000000000..3417cd7cefacc5465b77baa298e1af6dbc70ca88 Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001241103804.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001284944089.png b/Device/smart_door_access/figures/zh-cn_image_0000001284944089.png new file mode 100644 index 0000000000000000000000000000000000000000..e780af8745e7803933e8289d1b92288c404df38e Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001284944089.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001285254805.png b/Device/smart_door_access/figures/zh-cn_image_0000001285254805.png new file mode 100644 index 0000000000000000000000000000000000000000..d359033c2931b3dcb15c7929001412abb97735e6 Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001285254805.png differ diff --git a/Device/smart_door_access/figures/zh-cn_image_0000001285375257.png b/Device/smart_door_access/figures/zh-cn_image_0000001285375257.png new file mode 100644 index 0000000000000000000000000000000000000000..ae8459d426d5b506c07d4756c100944745fee03e Binary files /dev/null and b/Device/smart_door_access/figures/zh-cn_image_0000001285375257.png differ diff --git a/Device/smart_door_access/server/smart_door_access/BUILD.gn b/Device/smart_door_access/server/smart_door_access/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..895f82bd4d4ea2ecc2225902f5252a6cf4c06d9e --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/BUILD.gn @@ -0,0 +1,79 @@ +# Copyright (C) 2021 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("//build/ohos.gni") + +config("my_config") { + include_dirs = [ + "include", + "//third_party/node/src", + "//native_engine", + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "//foundation/communication/wifi/services/wifi_standard/wifi_framework/common/log", + "//foundation/communication/wifi/interfaces/innerkits/native_cpp/wifi_standard/interfaces", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//foundation/communication/wifi/interfaces/innerkits/native_cpp/wifi_standard/include", + "//foundation/communication/wifi/services/wifi_standard/wifi_framework/common/net_helper", + "//base/notification/ces_standard/frameworks/core/include", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiocommon/include", + "//foundation/multimedia/audio_standard/frameworks/innerkitsimpl/common/include", + ] +} + +ohos_executable("smart_door_access_server") { + install_enable = true + sources = [ + "src/main.cpp", + "src/audio.cpp", + "src/hotspot.cpp", + "src/tcp.cpp", + ] + cflags = [ "-fPIC" ] + cflags += [ "-Wall" ] + cflags_cc = cflags + + configs = [ ":my_config" ] + + deps = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//base/notification/ces_standard/frameworks/core:cesfwk_core", + "//base/notification/ces_standard/frameworks/native:cesfwk_innerkits", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/ace/napi:ace_napi", + "//foundation/communication/wifi/interfaces/innerkits/native_cpp/wifi_standard:wifi_sdk", + "//utils/native/base:utils", + "//foundation/multimedia/audio_standard/interfaces/innerkits/native/audiorenderer:audio_renderer" + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core" + ] + + part_name = "smart_door_access" + subsystem_name = "demo" +} + +ohos_prebuilt_etc("closeLock_wav") { + source = "wav/closeLock.wav" + module_install_dir = "data" + part_name = "smart_door_access" +} + +ohos_prebuilt_etc("openLock_wav") { + source = "wav/openLock.wav" + module_install_dir = "data" + part_name = "smart_door_access" +} + diff --git a/Device/smart_door_access/server/smart_door_access/bundle.json b/Device/smart_door_access/server/smart_door_access/bundle.json new file mode 100644 index 0000000000000000000000000000000000000000..5973094db9ed55482991d29cad457363a4aa6c72 --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/bundle.json @@ -0,0 +1,40 @@ +{ + "name": "@ohos/smart_door_access", + "description": "smart_door_access example.", + "version": "3.0", + "license": "Apache License 2.0", + "publishAs": "code-segment", + "segment": { + "destPath": "demo/smart_door_access" + }, + "dirs": {}, + "scripts": {}, + "component": { + "name": "smart_door_access", + "subsystem": "demo", + "syscap": [], + "features": [], + "adapted_system_type": [ "smart_door_access" ], + "rom": "", + "ram": "", + "deps": { + "components": [ + "libhilog", + "cesfwk_core", + "cesfwk_innerkits", + "want", + "ace_napi", + "wifi_sdk", + "utils" + ], + "third_party": [] + }, + "build": { + "sub_component": [ + "//demo/smart_door_access:smart_door_access_server" + ], + "inner_kits": [], + "test": [] + } + } +} \ No newline at end of file diff --git a/Device/smart_door_access/server/smart_door_access/include/audio.h b/Device/smart_door_access/server/smart_door_access/include/audio.h new file mode 100644 index 0000000000000000000000000000000000000000..d14939fcf42afb745f1e121900a9ece12c1e6d01 --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/include/audio.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 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 DEMO_AUDIO_H +#define DEMO_AUDIO_H + +enum PlayCmd { + CLOSE = 1, + OPEN = 2 +}; + +void PlayAudio(int cmd); + +#endif // DEMO_AUDIO_H diff --git a/Device/smart_door_access/server/smart_door_access/include/common.h b/Device/smart_door_access/server/smart_door_access/include/common.h new file mode 100644 index 0000000000000000000000000000000000000000..cd90f92a41a09f952d25e8c3cb2a9329a5db7342 --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/include/common.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 DEMO_COMMON_H +#define DEMO_COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SAMPLE_INFO(format, args...) \ + do { \ + fprintf(stderr, "\033[1;32m [INFO](%s:%d):\t\033[0m" format, __func__, __LINE__, ##args); \ + printf("\n"); \ + } while (0) + +#define SAMPLE_ERROR(format, args...) \ + do { \ + fprintf(stderr, "\033[1;31m [ERROR]RTSP SERVER(%s:%d):\t\033[0m" format, __func__, __LINE__, ##args); \ + printf("\n"); \ + } while (0) + +#define LISTEN_BACK_LOG 10 +#define CLIENT_IP_MAX 40 +#define SERVER_PORT 8556 +#define BUF_MAX_SIZE (1024 * 1024) + +#endif // DEMO_COMMON_H \ No newline at end of file diff --git a/Device/smart_door_access/server/smart_door_access/include/hotspot.h b/Device/smart_door_access/server/smart_door_access/include/hotspot.h new file mode 100644 index 0000000000000000000000000000000000000000..09d6a6a185448d99cbf64dbc6a357b4f50d62659 --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/include/hotspot.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 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 DEMO_HOTSPOT_H +#define DEMO_HOTSPOT_H + +int StartHotspot(); + +#endif // DEMO_HOTSPOT_H \ No newline at end of file diff --git a/Device/smart_door_access/server/smart_door_access/include/tcp.h b/Device/smart_door_access/server/smart_door_access/include/tcp.h new file mode 100644 index 0000000000000000000000000000000000000000..f123c6c91a68f09d1660db7230bb50928c8b27fc --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/include/tcp.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 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 DEMO_TCP_H +#define DEMO_TCP_H + +int TcpServerThread(); + +#endif // DEMO_TCP_H \ No newline at end of file diff --git a/Device/smart_door_access/server/smart_door_access/ohos.build b/Device/smart_door_access/server/smart_door_access/ohos.build new file mode 100644 index 0000000000000000000000000000000000000000..1f9f81bda6f59714ac6c7b210d6ce694cb22c98d --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/ohos.build @@ -0,0 +1,17 @@ +{ + "subsystem": "demo", + "parts": { + "smart_door_access": { + "variants": [ + "phone" + ], + "module_list": [ + "//demo/smart_door_access:smart_door_access_server", + "//demo/smart_door_access:closeLock_wav", + "//demo/smart_door_access:openLock_wav" + ], + "test_list": [ + ] + } + } +} diff --git a/Device/smart_door_access/server/smart_door_access/src/audio.cpp b/Device/smart_door_access/server/smart_door_access/src/audio.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ede0bbc804329080a6ccfb5b56bea6f9ebcb4f6a --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/src/audio.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021 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 "audio.h" +#include "common.h" +#include "audio_renderer.h" + +using namespace OHOS; +using namespace OHOS::AudioStandard; + +static int32_t InitializeRenderer(std::unique_ptr &audioRenderer) +{ + AudioRendererParams rendererParams; + rendererParams.sampleFormat = SAMPLE_S16LE; + rendererParams.sampleRate = SAMPLE_RATE_44100; + rendererParams.channelCount = STEREO; + rendererParams.encodingType = ENCODING_PCM; + + return audioRenderer->SetParams(rendererParams); +} + +static void OpenAudioFile(std::unique_ptr &audioRenderer, std::string path) +{ + const int32_t WRITE_BUFFERS_COUNT = 500; + int32_t ret = -1; + size_t bufferLen; + ret = audioRenderer->GetBufferSize(bufferLen); + if (ret != 0) { + SAMPLE_INFO("GetBufferSize error"); + } + FILE *wavFile = fopen(path.c_str(), "rb"); + uint8_t *buffer = (uint8_t *)malloc(bufferLen); + size_t bytesToWrite = 0; + int32_t bytesWritten = 0; + size_t minBytes = 4; + int32_t numBuffersToRender = WRITE_BUFFERS_COUNT; + while (numBuffersToRender) { + bytesToWrite = fread(buffer, 1, bufferLen, wavFile); + bytesWritten = 0; + while ((static_cast(bytesWritten) < bytesToWrite) && + ((static_cast(bytesToWrite) - bytesWritten) > minBytes)) { + bytesWritten += audioRenderer->Write(buffer + static_cast(bytesWritten), + bytesToWrite - static_cast(bytesWritten)); + if (bytesWritten < 0) { + break; + } + } + numBuffersToRender--; + } + audioRenderer->Drain(); + audioRenderer->Stop(); + audioRenderer->Release(); + + free(buffer); + fclose(wavFile); +} + +void PlayAudio(int cmd) +{ + int ret; + const std::string OPEN_FILE_PATH = "/system/data/openLock.wav"; + const std::string CLOSE_FILE_PATH = "/system/data/closeLock.wav"; + AudioStreamType streamType = STREAM_MUSIC; // 流类型示例 + std::unique_ptr audioRenderer = AudioRenderer::Create(streamType); + + InitializeRenderer(audioRenderer); + ret = audioRenderer->SetVolume(1.0); + if (ret != 0) { + SAMPLE_INFO("SetVolume error"); + } + audioRenderer->Start(); + + switch (cmd) { + case PlayCmd::CLOSE: + OpenAudioFile(audioRenderer, CLOSE_FILE_PATH); + break; + case PlayCmd::OPEN: + OpenAudioFile(audioRenderer, OPEN_FILE_PATH); + break; + default: + break; + } +} \ No newline at end of file diff --git a/Device/smart_door_access/server/smart_door_access/src/hotspot.cpp b/Device/smart_door_access/server/smart_door_access/src/hotspot.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f826ddba7c08766cc4d17af023b86cce041a4983 --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/src/hotspot.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 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 "hotspot.h" +#include "common.h" +#include "wifi_hotspot.h" +#include "wifi_logger.h" + +using namespace OHOS; +using namespace OHOS::Wifi; + +int StartHotspot() +{ + int ret; + std::unique_ptr wifiHotspotPtr = WifiHotspot::GetInstance(WIFI_HOTSPOT_ABILITY_ID); + // Wifi热点配置 + const std::string ssid = "SmartDoorAccess"; + const std::string key = "12345678"; + HotspotConfig config; + config.SetSsid(ssid); + config.SetPreSharedKey(key); + config.SetMaxConn(1); + config.SetBand(BandType::BAND_2GHZ); + config.SetSecurityType(KeyMgmt::WPA_PSK); + SAMPLE_INFO("config Ssid=%s, key=%s \r\n", config.GetSsid().c_str(), config.GetPreSharedKey().c_str()); + ret = wifiHotspotPtr->SetHotspotConfig(config); + if (ret != WIFI_OPT_SUCCESS) { + SAMPLE_INFO("Set hotspot config error\r\n"); + } + // 启动wifi热点 + ret = wifiHotspotPtr->EnableHotspot(); + if (ret != WIFI_OPT_SUCCESS) { + SAMPLE_INFO("Enable hotspot error\r\n"); + } + return ret; +} \ No newline at end of file diff --git a/Device/smart_door_access/server/smart_door_access/src/main.cpp b/Device/smart_door_access/server/smart_door_access/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95da2e953e83283c94348df6ed4a548a00971341 --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/src/main.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 "common.h" +#include "audio.h" +#include "hotspot.h" +#include "tcp.h" + +static void SetNetConfig() +{ + FILE *fp; + std::string cmd = "ifconfig wlan0 192.168.1.2 netmask 255.255.255.0"; + char *sysCommand = cmd.data(); + if ((fp = popen(sysCommand, "r")) == NULL) { + SAMPLE_INFO("set NetConfig fail\r\n"); + } + fgets(sysCommand, sizeof(sysCommand), fp); + SAMPLE_INFO("Set wlan0 Ip : %s", sysCommand); + pclose(fp); +} + +int main(int argc, char **argv) +{ + int ret; + SetNetConfig(); + ret = StartHotspot(); + if (ret != 0) { + SAMPLE_INFO("Hotspot start fail"); + } + ret = TcpServerThread(); + if (ret != 0) { + SAMPLE_INFO("TcpServer start fail"); + } + return 0; +} diff --git a/Device/smart_door_access/server/smart_door_access/src/tcp.cpp b/Device/smart_door_access/server/smart_door_access/src/tcp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b69336448f7833caf314126dc2c1b994381423a --- /dev/null +++ b/Device/smart_door_access/server/smart_door_access/src/tcp.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2021 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 "tcp.h" +#include "common.h" +#include "audio.h" + +bool g_islock = false; + +static int CreateTcpSocket() +{ + int fd; + int on = 1; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + return -1; + } + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); + + return fd; +} + +static int BindSocket(int fd, const char *ip, int port) +{ + const int on = 1; + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = inet_addr(ip); + // 允许重复绑定 + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { + SAMPLE_INFO("setsockopt error"); + } + if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0) + return -1; + + return 0; +} + +static int AcceptClient(int fd, char *ip, int *port) +{ + int ret; + int clientfd; + socklen_t len; + struct sockaddr_in addr; + + ret = memset_s(&addr, sizeof(addr), 0, sizeof(addr)); + if (ret) { + return -1; + } + len = sizeof(addr); + + clientfd = accept(fd, (struct sockaddr *)&addr, &len); + if (clientfd < 0) { + return -1; + } + + ret = strcpy_s(ip, CLIENT_IP_MAX, inet_ntoa(addr.sin_addr)); + if (ret) { + return -1; + } + *port = ntohs(addr.sin_port); + + return clientfd; +} + +static void Finish(int &clientSockfd, char *recvBuffer, char *sendBuffer) +{ + close(clientSockfd); + free(recvBuffer); + free(sendBuffer); + SAMPLE_INFO("finish\n"); +} + +static void DoClient(int clientSockfd, const char *clientIP, int clientPort) +{ + char *recvBuffer = (char *)malloc(BUF_MAX_SIZE); + char *sendBuffer = (char *)malloc(BUF_MAX_SIZE); + const char sendClose[6] = "close"; + const char sendOpen[5] = "open"; + const char sendError[6] = "error"; + + while (1) { + int recvSize; + + recvSize = recv(clientSockfd, recvBuffer, BUF_MAX_SIZE, 0); + if (recvSize <= 0) { + Finish(clientSockfd, recvBuffer, sendBuffer); + return; + } + recvBuffer[recvSize] = '\0'; + SAMPLE_INFO("---------------C->S--------------\n"); + SAMPLE_INFO("%s", recvBuffer); + if (!strcmp(recvBuffer, "close")) { + if (!g_islock) { + SAMPLE_INFO("---------------S->C--------------\n"); + SAMPLE_INFO("%s", sendClose); + send(clientSockfd, sendClose, strlen(sendClose), 0); + PlayAudio(PlayCmd::CLOSE); + g_islock = true; + } + } else if (!strcmp(recvBuffer, "open")) { + if (g_islock) { + SAMPLE_INFO("---------------S->C--------------\n"); + SAMPLE_INFO("%s", sendOpen); + send(clientSockfd, sendOpen, strlen(sendOpen), 0); + PlayAudio(PlayCmd::OPEN); + g_islock = false; + } + } else { + SAMPLE_INFO("cmd err"); + send(clientSockfd, sendError, strlen(sendError), 0); + } + } +} + +int TcpServerThread() +{ + int fd; + fd = CreateTcpSocket(); + if (fd < 0) { + SAMPLE_INFO("failed to create tcp socket\n"); + return -1; + } + + if (BindSocket(fd, "192.168.1.2", SERVER_PORT) < 0) { + SAMPLE_INFO("failed to bind addr\n"); + return -1; + } + + if (listen(fd, LISTEN_BACK_LOG) < 0) { + SAMPLE_INFO("failed to listen\n"); + return -1; + } + + SAMPLE_INFO("tcp server: 192.168.1.2:%d\n", SERVER_PORT); + + while (1) { + int clientSockfd; + char clientIp[CLIENT_IP_MAX]; + int clientPort; + + clientSockfd = AcceptClient(fd, clientIp, &clientPort); + if (clientSockfd < 0) { + SAMPLE_INFO("failed to accept client\n"); + return -1; + } + + SAMPLE_INFO("accept client;client ip:%s,client port:%d\n", clientIp, clientPort); + + DoClient(clientSockfd, clientIp, clientPort); + } + return 0; +} \ No newline at end of file diff --git a/Device/smart_door_access/server/smart_door_access/wav/closeLock.wav b/Device/smart_door_access/server/smart_door_access/wav/closeLock.wav new file mode 100644 index 0000000000000000000000000000000000000000..a4f0f35019fa80232f0572d7266730293c62cfdb Binary files /dev/null and b/Device/smart_door_access/server/smart_door_access/wav/closeLock.wav differ diff --git a/Device/smart_door_access/server/smart_door_access/wav/openLock.wav b/Device/smart_door_access/server/smart_door_access/wav/openLock.wav new file mode 100644 index 0000000000000000000000000000000000000000..e99b07602cf8945b5c66e201c8434efecccebd0f Binary files /dev/null and b/Device/smart_door_access/server/smart_door_access/wav/openLock.wav differ diff --git a/Distributed/GameAuthOpenH/entry/.gitignore b/Distributed/GameAuthOpenH/entry/.gitignore deleted file mode 100644 index 563ba71918c780f0f945deff80e4f9d913156779..0000000000000000000000000000000000000000 --- a/Distributed/GameAuthOpenH/entry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/node_modules -/build \ No newline at end of file diff --git a/Distributed/NewsDemo/entry/.gitignore b/Distributed/NewsDemo/entry/.gitignore deleted file mode 100644 index 7d5b7a94f4dcf381f03ff21f28f8a2494b58023f..0000000000000000000000000000000000000000 --- a/Distributed/NewsDemo/entry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/build -/node_modules diff --git a/Distributed/NewsDemo/entry/proguard-rules.pro b/Distributed/NewsDemo/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/Distributed/NewsDemo/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/Distributed/OHMailETS/entry/proguard-rules.pro b/Distributed/OHMailETS/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/Distributed/OHMailETS/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/Distributed/RemoteStartFA/entry/proguard-rules.pro b/Distributed/RemoteStartFA/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/Distributed/RemoteStartFA/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/AppScope/app.json5 b/ETSUI/PixelUnitsDemo/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..daef6c25b4693e92265d6434a2a32a2f65a7a18e --- /dev/null +++ b/ETSUI/PixelUnitsDemo/AppScope/app.json5 @@ -0,0 +1,11 @@ +{ + "app": { + "bundleName": "com.example.pixel_units_demo", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true + } +} diff --git a/ETSUI/PixelUnitsDemo/AppScope/resources/base/element/string.json b/ETSUI/PixelUnitsDemo/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..bb73c443db6c2e36ead279f89095fe0eb9fa1943 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "PixelUnitsDemo" + } + ] +} diff --git a/ETSUI/PixelUnitsDemo/AppScope/resources/base/media/app_icon.png b/ETSUI/PixelUnitsDemo/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/ETSUI/PixelUnitsDemo/AppScope/resources/base/media/app_icon.png differ diff --git a/ETSUI/PixelUnitsDemo/LICENSE b/ETSUI/PixelUnitsDemo/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..80576ef141485b36eea4aebf25af97020bc2de44 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved. + + 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. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/README.md b/ETSUI/PixelUnitsDemo/README.md new file mode 100644 index 0000000000000000000000000000000000000000..92573c251cbb1468584e2dc1b4d8504b3debd195 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/README.md @@ -0,0 +1,215 @@ +# 介绍 + +本篇Codelab展示了像素单位与像素转换的使用方式,实现效果如下: + +![](figures/像素转换gif.gif) + +# 相关概念 + +px:屏幕上真实的物理像素单位。 + +vp:屏幕密度相关像素,像素密度为160dpi的设备上1vp=1px。1vp对应的物理屏幕像素=(屏幕像素密度/160)px。 + +像素密度的计算可参考下图: + +![](figures/像素密度计算公式.png) + +fp:字体像素,随系统字体大小变化。 + +lpx:视窗逻辑像素单位,lpx单位为实际屏幕宽度与逻辑宽度的比值,逻辑宽度可通过designWidth来配置。 + +我们为window设置不同的designWidth,可以看到在同一屏幕下展示长度是有差异的,如下图: + +![](figures/designWidth720.png) + +在了解像素的相关概念后,我们接下来开始搭建开发环境,并使用不同的像素单位来设置控件的长度、字体的大小,同时借助像素单位转换API对不同的像素单位进行转换。 + +# 搭建OpenHarmony环境 + +完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: + +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。 + + 以3.1版本为例: + + ![](figures/zh-cn_image_0000001264659110.png) + +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-standard-env-setup.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-standard-running-rk3568-burning.md) + +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E5%88%9B%E5%BB%BAets%E5%B7%A5%E7%A8%8B)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E4%BD%BF%E7%94%A8%E7%9C%9F%E6%9C%BA%E8%BF%90%E8%A1%8C%E5%BA%94%E7%94%A8)。 +# 代码结构解读 + +本篇Codelab只对核心代码进行讲解,接下来我们来讲解整个工程的代码结构: + +![](figures/代码结构导读.png) + +``` +├─AppScope # app全局目录 +│ └─resources +│ └─base +│ ├─element +│ └─media +└─entry # entry目录 + └─src + └─main + ├─ets # ets代码 + │ └─AppConfig # 业务代码配置目录。 + │ └── app_font_config.ets #页面字体配置文件 + │ ├─Application + │ ├─MainAbility + │ └─pages + │ └── index.ets #首页 + │ └── pixelConversionPage.ets #像素转换页面 + │ └── pixelUnitsPage.ets #像素单位介绍页面 + └─resources # 资源目录 + └─base + ├─element + ├─media + └─profile +``` +# 为控件指定不同的像素单位 + +单位介绍页面,介绍了系统像素单位的概念,并在代码中为Text组件设置不同的像素单位: + +1.设置Text组件的宽度为200px: + +``` +Text("200px") + .width(200 + 'px') + .height(25) + .backgroundColor(this.blueTitleColor) +... +``` + +2.设置Text组件的宽度为200vp: + +``` +Text("200vp") + .width(200 + 'vp') + .height(25) + .backgroundColor(this.blueTitleColor) +... +``` + +如果使用vp作为像素单位,在为组件设置具体的宽度或高度时,可以不加vp(系统默认单位为vp)。 + +``` +Text("200vp") + .width(200) + .height(25) + .backgroundColor(this.blueTitleColor) +... +``` + +3.设置Text组件的宽度为24fp: + +``` +Text("这是一段为24fp的文字") + .fontSize(24 + 'fp') + .backgroundColor(this.blueTitleColor) +... +``` + +4.使用lpx像素单位: + +``` +Text("200lpx") + .width(200 + 'lpx') + .height(25) +... +``` + +![](figures/screen_capture.png) + +# 使用像素转换 + +在像素转换页面,通过使用像素转换API,实现不同像素单位之间的转换: + +1.vp与px之间的转换 + +vp转换为px: + +``` +... +private vp_px_width: number= 260 +... +Text() + .width(vp2px(this.vp_px_width)) + .height(25) + .backgroundColor(this.redColor) +... +``` + +px转换为vp: + +``` +Text() + .width(px2vp(this.vp_px_width) + 'vp') + .height(25) +... +``` + +2.fp与px之间的转换 + +fp转换为px: + +``` +... +private fp_px_width: number= 180 +... +Text() + .width(fp2px(this.fp_px_width)) + .height(25) +... +``` + +px转换为fp: + +``` +Text() + .width(px2fp(this.fp_px_width)) + .height(25) +... +``` + +3.lpx与px之间的转换 + +lpx转换为px: + +``` +... +private lpx_px_width: number= 200 +... +Text() + .width(lpx2px(this.lpx_px_width)) + .height(25) +... +``` + +px转换为lpx: + +``` +Text() + .width(px2lpx(this.lpx_px_width)) + .height(25) + .backgroundColor(this.blueColor) +... +``` + +![](figures/conversion.png) + +# 恭喜您 + +本篇Codelab介绍像素单位的基本知识与像素单位转换API的使用,通过像素转换案例,向开发者讲解了如何使用像素单位设置组件的大小、字体像素fp的使用以及不同像素单位之间的转换。 + +通过本Codelab的学习,您已经学会了: + +- 不同像素单位的使用 +- 像素单位转换相关API的使用 + + diff --git a/ETSUI/PixelUnitsDemo/build-profile.json5 b/ETSUI/PixelUnitsDemo/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d7b1117cdb34aab2983ac65026d9e8dcc91332d1 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/build-profile.json5 @@ -0,0 +1,27 @@ +{ + "app": { + "signingConfigs": [], + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default", + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/build-profile.json5 b/ETSUI/PixelUnitsDemo/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7dc37bb919dada5132609c409200db266559004f --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/build-profile.json5 @@ -0,0 +1,13 @@ +{ + "apiType": 'stageMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/hvigorfile.js b/ETSUI/PixelUnitsDemo/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..d7720ee6a7aad5c617d1fd2f6fc8c87067bfa32c --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/ETSUI/PixelUnitsDemo/entry/package.json b/ETSUI/PixelUnitsDemo/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..992c771b9e6be8904ce4204f075df58a9b0902cc --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/package.json @@ -0,0 +1,14 @@ +{ + "license":"ISC", + "devDependencies":{}, + "name":"entry", + "ohos":{ + "org":"huawei", + "directoryLevel":"module", + "buildTool":"hvigor" + }, + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{} +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/ets/AppConfig/app_font_config.ets b/ETSUI/PixelUnitsDemo/entry/src/main/ets/AppConfig/app_font_config.ets new file mode 100644 index 0000000000000000000000000000000000000000..bf4d24c816496961f09f6cace3dd15de6cc143e9 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/ets/AppConfig/app_font_config.ets @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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. + */ +enum FontSize { + SMALLER = 18, + SMALL = 24, + MIDDLE = 28, + LARGE = 32, + LARGER = 35, +} + +export enum AppFontSize { + /** + * Indicates that the fontSize of the app button. + */ + BUTTON = FontSize.SMALL, + BUTTON_LARGE = FontSize.LARGE, + /** + * Indicates that the fontSize of the app title. + */ + TITLE = FontSize.LARGER, + SUBTITLE = FontSize.LARGE, + /** + * Indicates that the fontSize of the app normal text. + */ + TEXT = FontSize.SMALL, + TEXT_BIG = FontSize.MIDDLE, + TEXT_SMALL = FontSize.SMALLER +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/ets/Application/AbilityStage.ts b/ETSUI/PixelUnitsDemo/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c9fcaafa50d6605b274c4a54a4b6225bc9bc1d0 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 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 AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/ets/MainAbility/MainAbility.ts b/ETSUI/PixelUnitsDemo/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..f870382553ec44243fad1ac3a9b36fb22acb9d33 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 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 Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + + windowStage.setUIContent(this.context, "pages/index", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/index.ets b/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..7c99f0ac525a7daf885d48e8fbab6abf28df768e --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/index.ets @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 router from '@ohos.router' +@Entry +@Component +struct Index { + @State message: string = 'Hello World!' + TAG= 'PixelUnitsDemo' + + build() { + + Row() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly }) { + TextButton({ content: '像素介绍' ,onclick: () => { + router.push({url: "pages/pixelUnitsPage",}) + }}) + TextButton({ content: '像素转换', onclick: () => { + router.push({url: "pages/pixelConversionPage"}) + } }) + } + .width('100%') + } + .height('100%') + } +} +@Component +struct TextButton { + @Prop content: string + onclick: (onclick?: ClickEvent) => void + + build() { + Button(this.content, { type: ButtonType.Normal, stateEffect: false }) + .borderRadius(9).fontSize(40).padding(50).onClick(this.onclick) + } +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/pixelConversionPage.ets b/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/pixelConversionPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..ddff4b407be4f956274453f702552383e5a9ed0b --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/pixelConversionPage.ets @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2021 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 router from '@ohos.router' +import { AppFontSize } from '../AppConfig/app_font_config' + +@Entry +@Component +struct PixelConversionPage { + @State message: string = 'Hello World' + private blueItemColor: string= "#f1faff" + private blueColor: string= "#2788d9" + private redColor: string= "#DE1a33" + private yellowColor: number= 0xF9CF93 + private vp_px_width: number= 260 + private fp_px_width: number= 180 + private lpx_px_width: number= 200 + private Tag: string= 'Pixel_conversion_page' + + build() { + Stack({ alignContent: Alignment.Bottom }) { + Scroll() { + Column() { + + Text('像素转换') + .fontSize(AppFontSize.TITLE) + .fontWeight(FontWeight.Bold) + .textAlign(TextAlign.Center) + .align(Alignment.Top) + .width("60%") + .margin({ top: 40, bottom: 20 }) + + + List({ space: 20, initialIndex: 0 }) { + ListItem() { + Column() { + //vp转换为px + Text('vp > px:') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + .margin({ bottom: 5, left: 10 }) + Column() { + Text('vp2px(' + this.vp_px_width + ')') + .height(25) + .fontColor(this.blueColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Center) + + }.margin(10) + + + Column() { + Text() + .width(vp2px(this.vp_px_width)) + .height(25) + .backgroundColor(this.redColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + }.margin(10) + + //px转换为vp + Text('px > vp:') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + .margin({ bottom: 5, left: 10 }) + Column() { + Text('px2vp(' + this.vp_px_width + ')') + .height(25) + .fontColor(this.blueColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Center) + }.margin(10) + + Column() { + Text() + .width(px2vp(this.vp_px_width) + 'vp') + .height(25) + .backgroundColor(this.redColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + }.margin(10) + }.alignItems(HorizontalAlign.Start) + + }.padding({ top: 30, bottom: 30, left: 10 }) + .backgroundColor(this.blueItemColor) + .borderRadius(10) + + ListItem() { + //fp转换为px + Column() { + Text('fp > px:') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + .margin({ bottom: 5, left: 10 }) + Column() { + Text('fp2px(' + this.fp_px_width + ')') + .height(25) + .fontColor(this.blueColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Center) + + }.margin(10) + + Column() { + Text() + .width(fp2px(this.fp_px_width)) + .height(25) + .backgroundColor(this.yellowColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + }.margin(10) + //px转换为fp + Text('px > fp:') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueColor) + .align(Alignment.Start) + .width("100%") + .margin({ bottom: 5, left: 10 }) + .fontWeight(FontWeight.Bold) + Column() { + Text('px2fp(' + this.fp_px_width + ')') + .height(25) + .fontColor(this.blueColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Center) + }.margin(10) + + Column() { + Text() + .width(px2fp(this.fp_px_width)) + .height(25) + .backgroundColor(this.yellowColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + }.margin(10) + }.alignItems(HorizontalAlign.Start) + + }.padding({ top: 30, bottom: 30, left: 10 }) + .backgroundColor(this.blueItemColor) + .borderRadius(10) + + ListItem() { + Column() { + //lpx转换为px + Text('lpx > px:') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + .margin({ bottom: 5, left: 10 }) + Column() { + Text('lpx2px(' + this.lpx_px_width + ')') + .height(25) + .fontColor(this.blueColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Center) + }.margin(10) + + Column() { + Text() + .width(lpx2px(this.lpx_px_width)) + .height(25) + .backgroundColor(this.blueColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + }.margin(10) + //px转换为lpx + Text('px > lpx:') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + .padding({ left: 10, right: 10 }) + Column() { + Text('px2lpx(' + this.lpx_px_width + ')') + .height(25) + .fontColor(this.blueColor) + .fontSize(AppFontSize.TEXT_SMALL) + }.margin(10) + + Column() { + Text() + .width(px2lpx(this.lpx_px_width)) + .height(25) + .backgroundColor(this.blueColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + }.margin(10) + + Text('lpx与px之间的转换,需要根据实际情况设置designWidth') + .width("100%") + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.Red) + .margin({ bottom: 5, left: 10 }) + }.alignItems(HorizontalAlign.Start) + }.padding({ top: 30, bottom: 30, left: 10 }) + .backgroundColor(this.blueItemColor) + .borderRadius(10) + } + .borderRadius(10) + .padding({ top: 20, bottom: 120, left: 15, right: 15 }) + + + }.height("100%") + }.margin({ bottom: 80 }) + + Column() { + Text('< 返回主页') + .fontSize(AppFontSize.BUTTON_LARGE) + .fontWeight(FontWeight.Bold) + .fontColor(Color.White) + .padding({ top: 8, bottom: 8 }) + } + .width('100%') + .height(60) + .backgroundColor(this.blueColor) + .align(Alignment.Center) + .onClick(() => { + console.log(this.Tag + "click the button to back home") + router.back() + }) + } + } +} diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/pixelUnitsPage.ets b/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/pixelUnitsPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..5d8d83f9a854ebb665f272b2af53dd27cb0ab318 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/ets/pages/pixelUnitsPage.ets @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2021 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 router from '@ohos.router'; +import { AppFontSize } from '../AppConfig/app_font_config' + +@Entry +@Component +struct PixelUnitsPage { + @State message: string = 'Hello World' + private blueItemColor: string= "#f1faff" + private blueTitleColor: string= "#2788d9" + private Tag: string= "Ark_pixel_page" + + build() { + Stack({ alignContent: Alignment.Bottom }) { + Scroll() { + Column() { + Text('像素介绍') + .fontSize(AppFontSize.TITLE) + .fontWeight(FontWeight.Bold) + .textAlign(TextAlign.Center) + .align(Alignment.Top) + .width("60%") + .margin({ top: 40, bottom: 0 }) + List({ space: 20, initialIndex: 0 }) { + ListItem() { + Column() { + Text('px') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueTitleColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + Text('屏幕物理像素单位。') + .width('100%') + .lineHeight(35) + .fontSize(AppFontSize.TEXT) + .textAlign(TextAlign.Start) + .borderRadius(10) + Column() { + Text("200px") + .width(200 + 'px') + .height(25) + .backgroundColor(this.blueTitleColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + .borderRadius(4) + .padding({ left: 5 }) + } + .align(Alignment.Start) + .width('100%') + .alignItems(HorizontalAlign.Start) + .margin({ top: 20 }) + + + }.align(Alignment.Start) + + + }.editable(true) + .padding(20) + .backgroundColor(this.blueItemColor) + .borderRadius(10) + + ListItem() { + Column() { + Text('vp') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueTitleColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + Text('屏幕密度相关像素,根据屏幕像素密度转换为屏幕物理像素。') + .width('100%') + .lineHeight(35) + .fontSize(AppFontSize.TEXT) + .textAlign(TextAlign.Start) + .borderRadius(10) + Text('像素密度为160dpi的设备上1vp=1px,1vp对应的物理屏幕像素=(屏幕像素密度/160)px') + .width('100%') + .lineHeight(35) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .borderRadius(10) + .fontColor("#5f5f5f") + Column() { + Text("200vp") + .width(200 + 'vp') + .height(25) + .backgroundColor(this.blueTitleColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + .borderRadius(4) + .padding({ left: 5 }) + } + .align(Alignment.Start) + .width('100%') + .alignItems(HorizontalAlign.Start) + .margin({ top: 20 }) + + }.align(Alignment.Start) + + }.editable(true) + .padding(20) + .backgroundColor(this.blueItemColor) + .borderRadius(10) + + ListItem() { + Column() { + Text('fp') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueTitleColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + Text('字体像素,与vp类似,随系统字体大小设置变化。') + .width('100%') + .lineHeight(35) + .fontSize(AppFontSize.TEXT) + .textAlign(TextAlign.Start) + .borderRadius(10) + Text('默认情况下与vp相同,即1vp=1fp,如果用户手动调整了系统字体,scale为缩放比例,设置后的字体大小(单位fp) = 设置前的字体大小 * scale') + .width('100%') + .lineHeight(35) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .borderRadius(10) + .fontColor("#5f5f5f") + Column() { + Text("这是一段为14fp的文字") + .height(25) + .backgroundColor(this.blueTitleColor) + .fontSize(14 + 'fp') + .textAlign(TextAlign.Start) + .fontColor(Color.White) + .borderRadius(4) + .padding({ left: 5 }) + .borderRadius(4) + .padding({ left: 5, right: 10 }) + } + .align(Alignment.Start) + .width('100%') + .alignItems(HorizontalAlign.Start) + .margin({ top: 20 }) + + Column() { + Text("这是一段为24fp的文字") + .fontSize(24 + 'fp') + .backgroundColor(this.blueTitleColor) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + .borderRadius(4) + .padding({ left: 5, right: 10, top: 5, bottom: 5 }) + } + .align(Alignment.Start) + .width('100%') + .alignItems(HorizontalAlign.Start) + .margin({ top: 20 }) + + }.align(Alignment.Start) + + }.editable(true) + .padding(20) + .backgroundColor(this.blueItemColor) + .borderRadius(10) + + ListItem() { + Column() { + Text('lpx') + .fontSize(AppFontSize.SUBTITLE) + .fontColor(this.blueTitleColor) + .align(Alignment.Start) + .width("100%") + .fontWeight(FontWeight.Bold) + Text('视窗逻辑像素单位,lpx单位为实际屏幕宽度与逻辑宽度(通过designWidth配置)的比值。') + .width('100%') + .lineHeight(35) + .fontSize(AppFontSize.TEXT) + .textAlign(TextAlign.Start) + .borderRadius(10) + + Column() { + Text("200lpx") + .width(200 + 'lpx') + .height(25) + .backgroundColor(this.blueTitleColor) + .fontSize(AppFontSize.TEXT_SMALL) + .textAlign(TextAlign.Start) + .fontColor(Color.White) + .borderRadius(4) + .padding({ left: 5 }) + } + .align(Alignment.Start) + .width('100%') + .alignItems(HorizontalAlign.Start) + .margin({ top: 20 }) + + Image($r('app.media.designWidth720')) + .border({ width: 1 }) + .borderStyle(BorderStyle.Dashed) + .margin({ top: 10 }) + + Image($r('app.media.designWidth1440')) + .border({ width: 1 }) + .borderStyle(BorderStyle.Dashed) + .margin({ top: 10 }) + + }.align(Alignment.Start) + + }.editable(true) + .padding(20) + .backgroundColor(this.blueItemColor) + .borderRadius(10) + } + .padding(15).margin({ top: 20, bottom: 160 }) + + + }.height("100%") + } + + Column() { + Text('< 返回主页') + .fontSize(AppFontSize.BUTTON) + .fontWeight(FontWeight.Bold) + .fontColor(Color.White) + } + .width('100%') + .padding({ right: 10, left: 10, top: 20, bottom: 20 }) + .backgroundColor(this.blueTitleColor) + .align(Alignment.Center) + .onClick(() => { + console.log(this.Tag + "click the button to back home") + router.back() + }) + } + } +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/module.json5 b/ETSUI/PixelUnitsDemo/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..035cdc75464278063f3d80f9fc859ac37d6b8b61 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/module.json5 @@ -0,0 +1,37 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/element/string.json b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..490210a3908f47722dc942d49dacc98b97669a5f --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/designWidth1440.PNG b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/designWidth1440.PNG new file mode 100644 index 0000000000000000000000000000000000000000..c6eb548d54ac0e3be796d09bf95efd1c28d5ae02 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/designWidth1440.PNG differ diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/designWidth720.PNG b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/designWidth720.PNG new file mode 100644 index 0000000000000000000000000000000000000000..1dca77390a23b58371dd09080b29f7389d31bb51 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/designWidth720.PNG differ diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/icon.png b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/media/icon.png differ diff --git a/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/profile/main_pages.json b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..361915433f3d4f19b27a0e206c6742ba7f1ccd34 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,11 @@ +{ + "src": [ + "pages/index", + "pages/pixelConversionPage", + "pages/pixelUnitsPage" + ], + "window": { + "designWidth": 720, + "autoDesignWidth": false + } +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/figures/conversion.png b/ETSUI/PixelUnitsDemo/figures/conversion.png new file mode 100644 index 0000000000000000000000000000000000000000..d0c5135e70e67f539c81f25779bb2873f1366e22 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/figures/conversion.png differ diff --git a/ETSUI/PixelUnitsDemo/figures/designWidth720.png b/ETSUI/PixelUnitsDemo/figures/designWidth720.png new file mode 100644 index 0000000000000000000000000000000000000000..0ed972d1bc561309ff5b8877c0cb6f46d674b427 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/figures/designWidth720.png differ diff --git a/ETSUI/PixelUnitsDemo/figures/screen_capture.png b/ETSUI/PixelUnitsDemo/figures/screen_capture.png new file mode 100644 index 0000000000000000000000000000000000000000..bd6459f877abb16c93501581a4e6026e6cf08b46 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/figures/screen_capture.png differ diff --git a/ETSUI/PixelUnitsDemo/figures/zh-cn_image_0000001264659110.png b/ETSUI/PixelUnitsDemo/figures/zh-cn_image_0000001264659110.png new file mode 100644 index 0000000000000000000000000000000000000000..9d752ff5311af2816bf898cb2c18ef33bf085726 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/figures/zh-cn_image_0000001264659110.png differ diff --git "a/ETSUI/PixelUnitsDemo/figures/\344\273\243\347\240\201\347\273\223\346\236\204\345\257\274\350\257\273.png" "b/ETSUI/PixelUnitsDemo/figures/\344\273\243\347\240\201\347\273\223\346\236\204\345\257\274\350\257\273.png" new file mode 100644 index 0000000000000000000000000000000000000000..296ca63e9e537ef598fad163881b693692aaf4e0 Binary files /dev/null and "b/ETSUI/PixelUnitsDemo/figures/\344\273\243\347\240\201\347\273\223\346\236\204\345\257\274\350\257\273.png" differ diff --git "a/ETSUI/PixelUnitsDemo/figures/\345\203\217\347\264\240\345\257\206\345\272\246\350\256\241\347\256\227\345\205\254\345\274\217.png" "b/ETSUI/PixelUnitsDemo/figures/\345\203\217\347\264\240\345\257\206\345\272\246\350\256\241\347\256\227\345\205\254\345\274\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..a110561e10973e61fe9c32fe3999de0d045a32b5 Binary files /dev/null and "b/ETSUI/PixelUnitsDemo/figures/\345\203\217\347\264\240\345\257\206\345\272\246\350\256\241\347\256\227\345\205\254\345\274\217.png" differ diff --git "a/ETSUI/PixelUnitsDemo/figures/\345\203\217\347\264\240\350\275\254\346\215\242gif.gif" "b/ETSUI/PixelUnitsDemo/figures/\345\203\217\347\264\240\350\275\254\346\215\242gif.gif" new file mode 100644 index 0000000000000000000000000000000000000000..c41aa5f0bf3ec5e4dfe68864c3b3170fb10e5c9d Binary files /dev/null and "b/ETSUI/PixelUnitsDemo/figures/\345\203\217\347\264\240\350\275\254\346\215\242gif.gif" differ diff --git a/ETSUI/PixelUnitsDemo/hvigorfile.js b/ETSUI/PixelUnitsDemo/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..5f2735e3deeaf655828407544bbed9365c258278 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/package.json b/ETSUI/PixelUnitsDemo/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5e0eea375fbe32b5fe6fc9337202a133c2d5a1d3 --- /dev/null +++ b/ETSUI/PixelUnitsDemo/package.json @@ -0,0 +1,18 @@ +{ + "license":"ISC", + "devDependencies":{}, + "name":"pixel_units_demo", + "ohos":{ + "org":"huawei", + "directoryLevel":"project", + "buildTool":"hvigor" + }, + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{ + "@ohos/hvigor-ohos-plugin":"1.0.6", + "hypium":"^1.0.0", + "@ohos/hvigor":"1.0.6" + } +} \ No newline at end of file diff --git a/ETSUI/PixelUnitsDemo/public_sys-resources/icon-caution.gif b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-caution.gif differ diff --git a/ETSUI/PixelUnitsDemo/public_sys-resources/icon-danger.gif b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-danger.gif differ diff --git a/ETSUI/PixelUnitsDemo/public_sys-resources/icon-note.gif b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-note.gif differ diff --git a/ETSUI/PixelUnitsDemo/public_sys-resources/icon-notice.gif b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-notice.gif differ diff --git a/ETSUI/PixelUnitsDemo/public_sys-resources/icon-tip.gif b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-tip.gif differ diff --git a/ETSUI/PixelUnitsDemo/public_sys-resources/icon-warning.gif b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/ETSUI/PixelUnitsDemo/public_sys-resources/icon-warning.gif differ diff --git a/ETSUI/WebComponent/AppScope/app.json5 b/ETSUI/WebComponent/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..af7380afc041d044d48931595adad130c271746b --- /dev/null +++ b/ETSUI/WebComponent/AppScope/app.json5 @@ -0,0 +1,11 @@ +{ + "app": { + "bundleName": "com.huawei.myapplication", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true + } +} diff --git a/ETSUI/WebComponent/AppScope/resources/base/element/string.json b/ETSUI/WebComponent/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..22b5c2d945e392b572dc78f81c3ec302c5a69b7a --- /dev/null +++ b/ETSUI/WebComponent/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "Web组件加载本地H5小程序" + } + ] +} diff --git a/ETSUI/WebComponent/AppScope/resources/base/media/app_icon.png b/ETSUI/WebComponent/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/ETSUI/WebComponent/AppScope/resources/base/media/app_icon.png differ diff --git a/ETSUI/WebComponent/LICENSE b/ETSUI/WebComponent/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..80576ef141485b36eea4aebf25af97020bc2de44 --- /dev/null +++ b/ETSUI/WebComponent/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved. + + 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. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/ETSUI/WebComponent/README.md b/ETSUI/WebComponent/README.md new file mode 100644 index 0000000000000000000000000000000000000000..312d3b0a269a28c0ca1ab71e3a6c9a1cc2e7ed77 --- /dev/null +++ b/ETSUI/WebComponent/README.md @@ -0,0 +1,214 @@ +# Web组件加载本地H5小程序 + +# 介绍 + +本Codelab是一个OpenHarmony应用,使用具有网页显示能力的web组件,加载一个本地H5界面。所加载的界面是一个由HTML+CSS+JavaScript实现的完整小应用。本案例旨在向开发者展示OpenHarmony如何通过web组件加载完成的H5小程序,以及如何通过run JavaScript直接调用H5界面的JavaScript函数,实现eTS和H5的简单交互,简化OpenHarmony集成H5小程序的过程。 + +**运行效果:** + +![](figures/GIF-2022-5-6-17-53-58.gif) + +# 相关概念 + +**[web组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-web.md#loadurl):**提供具有网页显示能力的Web组件。 + +# 开发环境 + +- IDE版本:3.0.0.900 +- 项目类型:eTS语言、API9、stage模型 +- 调试设备:RK3568 + +# 相关权限 + +加载web资源需要在config.json中配置如下权限: + +``` +"requestPermissions": [ + { + name: "ohos.permission.INTERNET" + } +] +``` + +# H5小程序 + +抽奖小程序由HTML+CSS+JS实现,主要的代码展示: + +1. 抽奖盘html + + 利用无序列表元素组合一个九宫格,中间一格为抽奖格,外围八格为奖品格。奖品格的图片src路径后续通过JS动态添加。 + + ``` +
+ + +
    +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • 点击抽奖
  • + +
  • 奖品
  • +
+
+ ``` + +2. 抽奖盘CSS + + 通过绝对定位的方式,可以快速的将一个无序列表变为九宫格效果。 + + ``` + /* 抽奖div */ + .luckyDraw { + width: 480px; + margin: 0 auto; + } + + /* 抽奖列表 */ + .prizes { + width: 480px; + margin: 30px auto; + position: relative; + } + + /* 奖品格子 */ + .prizes li { + width: 160px; + height: 160px; + box-sizing: border-box; + text-align: center; + line-height: 160px; + position: absolute; + border-radius: 25px; + padding: 10px,10px; + } + + /* 奖品格子位置 */ + .prizes li:nth-of-type(1) { + left: 0; + top: 0; + } + .... + ``` + +3. 抽奖盘JS + + 预先随机好结果,通过可变速的旋转动作,旋转指定的圈数后,最后落在指定位置。运行时的旋转效果通过给元素动态添加CSS效果来实现。 + + ``` + let i = 0; //转到哪个位置 + let count = 0; //转圈初始值 + let totalCount = 8; //至少转动的总圈数 + let speed = 500; //转圈速度,值越大越慢 + let index = 3; //转到哪个奖品 + + // 旋转函数,预先随机好结果,通过可变速的旋转动作,到达指定的圈数后,最后落在指定位置 + function roll() { + //速度衰减 + speed -= 50; + if (speed <= 10) { + speed = 10; + } + //每次调用都去掉全部active类名 + for (var j = 0;j < ali.length; j++) { + ali[j].classList.remove('active'); + } + i++; + //计算转圈次数 + if (i >= ali.length - 1) { + i = 0; + count++; + } + prizeText.innerHTML = arr[i]; //显示当前奖品名称 + ali[i].classList.add('active'); //添加激活类名,给奖品加样式 + //满足转圈数和指定位置就停止 + if (count >= totalCount && (i + 1) == index) { + clearTimeout(timer); + isClick = true; + speed = initSpeed; + dialogText.innerHTML = "恭喜获得 " + arr[i] + " 请填写收件地址"; + dialogImg.src = arrImg[i]; + timer = setTimeout(openDialog, 1000); // 等待1s打开弹窗 + } else { + timer = setTimeout(roll, speed); //不满足条件时调用定时器 + //最后一圈减速 + if (count >= totalCount - 1 || speed <= 50) { + speed += 100; + } + } + } + // 抽奖开始函数 + function start() { + finishText.style.display = "none"; + // 防止抽奖多次触发 + if (isClick) { + count = 0; + //随机产生中奖位置 + index = Math.floor(Math.random() * arr.length + 1); + roll(); + isClick = false; + } + } + ``` + +# web组件 + +通过web组件不仅可以在OpenHarmony设备上展示H5小程序的界面,也可以通过runJavaScript\(\)执行小程序的JS函数,来实现eTS与H5小程序的交互功能。 + +web组件代码: + +``` +@Entry +@Component +struct Index { + // web组件控制器可以控制Web组件各种行为 + webController: WebController = new WebController() + + build() { + Row() { + Column() { + Text("Web组件外") + .fontSize(50) + .fontWeight(FontWeight.Bold) + Button("点击抽奖") + .fontSize(40) + .height("8%") + .width("30%") + .onClick(() => { + this.webController.runJavaScript({ script: 'start()' }); // 运行web加载的本地JS函数 + console.log("点击抽奖按钮") + }) + Text("-----------------------------") + .fontSize(50) + Text("Web组件内") + .fontSize(50) + .fontWeight(FontWeight.Bold) + // web组件加载本地H5 + Web({ src: $rawfile('index.html'), controller: this.webController }) + // 设置是否开启通过$rawfile(filepath/filename)访问应用中rawfile路径的文件, 默认启用。 + .fileAccess(true) + // 设置是否允许自动加载图片资源,默认允许。 + .imageAccess(true) + // 设置是否允许执行JavaScript脚本,默认允许执行。 + .javaScriptAccess(true) + .backgroundColor(Color.Pink) + } + .width('100%') + } + .height('100%') + } +} +``` + +# 恭喜您 + +通过本篇Codelab,您可以学到: + +1、Web组件加载本地H5小程序。 + +2、Web组件运行本地H5小程序的JS函数。 \ No newline at end of file diff --git a/ETSUI/WebComponent/build-profile.json5 b/ETSUI/WebComponent/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..fc53829be062f3a883f815802e6039c733ebb352 --- /dev/null +++ b/ETSUI/WebComponent/build-profile.json5 @@ -0,0 +1,26 @@ +{ + "app": { + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default", + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/build-profile.json5 b/ETSUI/WebComponent/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7dc37bb919dada5132609c409200db266559004f --- /dev/null +++ b/ETSUI/WebComponent/entry/build-profile.json5 @@ -0,0 +1,13 @@ +{ + "apiType": 'stageMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/hvigorfile.js b/ETSUI/WebComponent/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..d7720ee6a7aad5c617d1fd2f6fc8c87067bfa32c --- /dev/null +++ b/ETSUI/WebComponent/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/ETSUI/WebComponent/entry/package.json b/ETSUI/WebComponent/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c7685ac4e7c0d79df04c96744f0d8f22cb4a9025 --- /dev/null +++ b/ETSUI/WebComponent/entry/package.json @@ -0,0 +1,14 @@ +{ + "license": "ISC", + "devDependencies": {}, + "name": "entry", + "ohos": { + "org": "huawei", + "directoryLevel": "module", + "buildTool": "hvigor" + }, + "description": "example description", + "repository": {}, + "version": "1.0.0", + "dependencies": {} +} diff --git a/ETSUI/WebComponent/entry/src/main/ets/Application/AbilityStage.ts b/ETSUI/WebComponent/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f96918c937982a919a3d818c59b58c0b48839c9 --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 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 AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/ets/MainAbility/MainAbility.ts b/ETSUI/WebComponent/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..50f32a075d2ce8e0e644fa28f7b0b0eaa8d812ad --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 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 Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + + windowStage.setUIContent(this.context, "pages/index", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/ETSUI/WebComponent/entry/src/main/ets/pages/index.ets b/ETSUI/WebComponent/entry/src/main/ets/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..6300ac2714a108edc90bc5c8c2ce99de91f106d5 --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/ets/pages/index.ets @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 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 { + // web组件控制器可以控制Web组件各种行为 + webController: WebController = new WebController() + + build() { + Row() { + Column() { + Text("Web组件外") + .fontSize(50) + .fontWeight(FontWeight.Bold) + Button("点击抽奖") + .fontSize(40) + .height("8%") + .width("30%") + .onClick(() => { + this.webController.runJavaScript({ script: 'start()' }); + console.log("点击抽奖按钮") + }) + Text("-----------------------------") + .fontSize(50) + Text("Web组件内") + .fontSize(50) + .fontWeight(FontWeight.Bold) + // web组件加载本地H5 + Web({ src: $rawfile('index.html'), controller: this.webController }) + // 设置是否开启通过$rawfile(filepath/filename)访问应用中rawfile路径的文件, 默认启用。 + .fileAccess(true) + // 设置是否允许自动加载图片资源,默认允许。 + .imageAccess(true) + // 设置是否允许执行JavaScript脚本,默认允许执行。 + .javaScriptAccess(true) + .backgroundColor(Color.Pink) + } + .width('100%') + } + .height('100%') + } +} \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/module.json5 b/ETSUI/WebComponent/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..1cc42784a7ca48aced098c4f1444cff29f645b27 --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/module.json5 @@ -0,0 +1,42 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + name: "ohos.permission.INTERNET" + } + ] + } +} \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/resources/base/element/string.json b/ETSUI/WebComponent/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..6631d602a5b72ee29874ec0abab7b93ccf769220 --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "web组件加载本地H5小程序" + } + ] +} \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/resources/base/media/icon.png b/ETSUI/WebComponent/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/base/media/icon.png differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/base/profile/main_pages.json b/ETSUI/WebComponent/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..feec276e105eeb8d621c20aaf838f318b0a94150 --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/index" + ] +} diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/css/index.css b/ETSUI/WebComponent/entry/src/main/resources/rawfile/css/index.css new file mode 100644 index 0000000000000000000000000000000000000000..3a025534918c771ca1c6993fc10a3ff9f728a4bf --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/resources/rawfile/css/index.css @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2021 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. + */ + +/* 重置样式 */ +* { + margin: 0; + padding: 0;/* 去除无序列表的样式 */ + list-style: none;/* 去除文本的样式 */ + text-decoration: none; +} + +/* 图片样式 */ +img { + width: 100%; + height: 100%; + margin: auto; + display: block; +} + +/* 抽奖div */ +.luckyDraw { + width: 480px; + margin: 0 auto; +} + +/* 抽奖列表 */ +.prizes { + width: 480px; + margin: 30px auto; + position: relative; +} + +/* 开始抽奖文本 */ +.trigger { + font-size: 20px; + text-align: center; + display:block; + line-height:140px; +} + +/* 奖品格子 */ +.prizes li { + width: 160px; + height: 160px; + box-sizing: border-box; + text-align: center; + line-height: 160px; + position: absolute; + border-radius: 25px; + padding: 10px,10px; +} + +/* 奖品格子位置 */ +.prizes li:nth-of-type(1) { + left: 0; + top: 0; +} + +.prizes li:nth-of-type(2) { + left: 160px; + top: 0; +} + +.prizes li:nth-of-type(3) { + left: 320px; + top: 0; +} + +.prizes li:nth-of-type(4) { + left: 320px; + top: 160px; +} + +.prizes li:nth-of-type(5) { + left: 320px; + top: 320px; +} + +.prizes li:nth-of-type(6) { + left: 160px; + top: 320px; +} + +.prizes li:nth-of-type(7) { + left: 0; + top: 320px; +} + +.prizes li:nth-of-type(8) { + left: 0; + top: 160px; +} + +.prizes li:nth-of-type(9) { + width: 140px; + height: 140px; + left: 160px; + top: 160px; + background: pink; + margin: 10px; + text-align: center; +} + +/* 抽奖效果 */ +.active:after { + top: 0; + left: 0; + content: ""; + width: 100%; + height: 100%; + position: absolute; + border-radius: 24px; + background: rgba(1, 1, 1, 0.3); +} + +/* 奖品显示区样式 */ +#prizeText { +left: 0px; +top: 500px; +width: 480px; +margin: 0 auto; +font-size: 28px; +text-align: center; +position: absolute; +} + +/* 弹窗样式 */ +.dialog { + top: 0; + left: 0; + z-index: 1; + width: 100%; + height: 100%; + display: none; + overflow: auto; + position: fixed; + background-color: rgba(1, 1, 1, 0.3); +} + +/* 弹窗内容 */ +.dialog-content { + width: 480px; + height: 410px; + padding: 20px; + position: static; + margin: 100px auto; + border-radius: 15px; + background-color: #fefefe; + border: 1px solid #888; +} + +/* 收货信息 */ +.infoBox{ + padding: 24px; + margin-bottom: 10px; + vertical-align: middle; + border-bottom: 1px solid #DDE0E8; +} + +/* 弹窗内容 */ +.infoBox .infoInput { + border: 1px solid #D2D9dC; + border-radius: 2px; + color: #444; + font: 12px; + padding: 8px 14px; + margin-bottom: 8px; + width: 310px; +} + +/* 弹窗图片 */ +.dialogImg { + width: 150px; + margin: 10px,10px,10px,10px +} + +/* 提交按钮 */ +.btn { + border: none; + color: white; + padding: 15px 30px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 18px; + border-radius: 15px; + display: block; + margin: auto; + background-color: #4CAF50; /* 绿色 */ +} + +/* 关闭按钮 */ +.close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} +.close:hover, +.close:focus { + color: black; +} diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/1-band.jpg b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/1-band.jpg new file mode 100644 index 0000000000000000000000000000000000000000..26b8a82d1093d0373569b456c8fe805f8946285f Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/1-band.jpg differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/2-buds.jpg b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/2-buds.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9c954eda456a83e93872e31cbc988ec530b97017 Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/2-buds.jpg differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/3-car.jpg b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/3-car.jpg new file mode 100644 index 0000000000000000000000000000000000000000..337a7735cce62499a3bc88851a446b72f27e01a6 Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/3-car.jpg differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/4-computer.png b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/4-computer.png new file mode 100644 index 0000000000000000000000000000000000000000..37cf717a45d19cb48de9918ba8fde56c18213d63 Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/4-computer.png differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/5-pad.jpg b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/5-pad.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5bf7164d5103d0304ef03d93da42ec664b5960a7 Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/5-pad.jpg differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/6-phone.jpg b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/6-phone.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dd9cdb5de63f18b60bd4356c8fe5f589f5b829f0 Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/6-phone.jpg differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/7-router.jpg b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/7-router.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dea3ad9c1508472084b888c7a3602fe2e2e13380 Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/7-router.jpg differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/8-watch.png b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/8-watch.png new file mode 100644 index 0000000000000000000000000000000000000000..6f718a2878a9f74278204fd425a48c5e0856d4e7 Binary files /dev/null and b/ETSUI/WebComponent/entry/src/main/resources/rawfile/img/8-watch.png differ diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/index.html b/ETSUI/WebComponent/entry/src/main/resources/rawfile/index.html new file mode 100644 index 0000000000000000000000000000000000000000..8b1e70216910bf8b70a922cc108faa7bdfa6ebdf --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/resources/rawfile/index.html @@ -0,0 +1,60 @@ + + + + + + + + 抽奖页面 + + +
+ + +
    +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • 点击抽奖
  • + +
  • 奖品
  • +
+
+ + +
+ +
+ × +
+

恭喜获得如下奖品,请填写收货地址

+ +
+

+

+

+
+ +
+
+
+ + + + \ No newline at end of file diff --git a/ETSUI/WebComponent/entry/src/main/resources/rawfile/js/index.js b/ETSUI/WebComponent/entry/src/main/resources/rawfile/js/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a2091680c78c5a9a4a1dd6c1561b97958f500c27 --- /dev/null +++ b/ETSUI/WebComponent/entry/src/main/resources/rawfile/js/index.js @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2021 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. + */ + +// 奖品名数组 +let arr = ["手环", "耳机", "汽车", "电脑", "平板", "手机", "路由", "手表"]; +// 奖品图片数组 +let arrImg = ["./img/1-band.jpg", "./img/2-buds.jpg", "./img/3-car.jpg", + "./img/4-computer.png", "./img/5-pad.jpg", "./img/6-phone.jpg", + "./img/7-router.jpg", "./img/8-watch.png"]; +// 获取奖品列表 +let prizes = document.querySelector('.prizes'); +// 获取奖品区名称 +let prizeText = document.querySelector('#prizeText'); +// 获取全部奖品单元格 +let ali = document.querySelectorAll('.prizes-li'); +// 获取弹窗 +let dialog = document.querySelector('.dialog'); +// 获取关闭弹窗span +let close = document.querySelector('.close'); +// 获取提交按钮 +let btn = document.querySelector('.btn'); +// 获取弹窗文本 +let dialogText = document.querySelector('.dialogText'); +// 获取弹窗图片 +let dialogImg = document.querySelector('.dialogImg'); +// 获取奖品img +let pic = document.querySelectorAll('.pic'); +// 抽奖结束文字 +let finishText = document.querySelector('.finishText'); +// 信息输入框 +let infoInput = document.querySelectorAll('.infoInput'); + +let i = 0; //转到哪个位置 +let count = 0; //转圈初始值 +let totalCount = 8; //至少转动的总圈数 +let speed = 500; //转圈速度,值越大越慢 +let initSpeed = 500; +let timer; +let isClick = true; +let index = 3; //指定转到哪个奖品 + +// 绑定img +for (let j = 0;j < pic.length; j++) { + pic[j].src = arrImg[j]; +} + +// 旋转函数,预先随机好结果,通过可变速的旋转动作,到达指定的圈数后,最后落在指定位置 +function roll() { + //速度衰减 + speed -= 50; + if (speed <= 10) { + speed = 10; + } + //每次调用都去掉全部active类名 + for (let j = 0; j < ali.length; j++) { + ali[j].classList.remove('active'); + } + i++; + //计算转圈次数 + if (i >= ali.length - 1) { + i = 0; + count++; + } + + prizeText.innerHTML = arr[i]; //显示当前奖品名称 + + ali[i].classList.add('active'); //添加激活类名,给奖品加样式 + //满足转圈数和指定位置就停止 + if (count >= totalCount && (i + 1) == index) { + clearTimeout(timer); + isClick = true; + speed = initSpeed; + dialogText.innerHTML = "恭喜获得 " + arr[i] + " 请填写收件地址"; + dialogImg.src = arrImg[i]; + timer = setTimeout(openDialog, 1000); // 等待1s打开弹窗 + } else { + timer = setTimeout(roll, speed); //不满足条件时调用定时器 + //最后一圈减速 + if (count >= totalCount - 1 || speed <= 50) { + speed += 100; + } + } +} + +// 抽奖开始函数 +function start() { + finishText.style.display = "none"; + // 防止抽奖多次触发 + if (isClick) { + count = 0; + //随机产生中奖位置 + index = Math.floor(Math.random() * arr.length + 1); + roll(); + isClick = false; + } +} + +// 打开弹窗 +function openDialog() { + dialog.style.display = "block"; + // 清楚输入框内容 + for (var i = 0;i < infoInput.length; i++) { + infoInput[i].value = ""; + } +} + +// 关闭弹窗 +function closeDialog() { + dialog.style.display = "none"; +} + +// 点击 (x), 关闭弹窗 +close.onclick = function () { + closeDialog(); +} + +// 在用户点击其他地方时,关闭弹窗 +window.onclick = function (event) { + if (event.target == dialog) { + closeDialog(); + } +} +// 提交按钮 +btn.onclick = function () { + closeDialog(); + finishText.style.display = "block"; +} + +// 结束语 + diff --git a/ETSUI/WebComponent/figures/GIF-2022-5-6-17-53-58.gif b/ETSUI/WebComponent/figures/GIF-2022-5-6-17-53-58.gif new file mode 100644 index 0000000000000000000000000000000000000000..a3f64e532545420169f47478afa072ab4ddb6648 Binary files /dev/null and b/ETSUI/WebComponent/figures/GIF-2022-5-6-17-53-58.gif differ diff --git a/ETSUI/WebComponent/hvigorfile.js b/ETSUI/WebComponent/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..5f2735e3deeaf655828407544bbed9365c258278 --- /dev/null +++ b/ETSUI/WebComponent/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/ETSUI/WebComponent/package.json b/ETSUI/WebComponent/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ec5d226fa60c3ba501a253ad6f521614c3249d28 --- /dev/null +++ b/ETSUI/WebComponent/package.json @@ -0,0 +1,18 @@ +{ + "license":"ISC", + "devDependencies":{}, + "name":"webcomponent", + "ohos":{ + "org":"huawei", + "directoryLevel":"project", + "buildTool":"hvigor" + }, + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{ + "@ohos/hvigor-ohos-plugin":"1.0.6", + "hypium":"^1.0.0", + "@ohos/hvigor":"1.0.6" + } +} \ No newline at end of file diff --git a/JSUI/AnimationDemo/entry/.gitignore b/JSUI/AnimationDemo/entry/.gitignore deleted file mode 100644 index 7d5b7a94f4dcf381f03ff21f28f8a2494b58023f..0000000000000000000000000000000000000000 --- a/JSUI/AnimationDemo/entry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/build -/node_modules diff --git a/JSUI/ClickableJsDemo/entry/.gitignore b/JSUI/ClickableJsDemo/entry/.gitignore deleted file mode 100644 index 796b96d1c402326528b4ba3c12ee9d92d0e212e9..0000000000000000000000000000000000000000 --- a/JSUI/ClickableJsDemo/entry/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/JSUI/DialogDemo/entry/.gitignore b/JSUI/DialogDemo/entry/.gitignore deleted file mode 100644 index 7d5b7a94f4dcf381f03ff21f28f8a2494b58023f..0000000000000000000000000000000000000000 --- a/JSUI/DialogDemo/entry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/build -/node_modules diff --git a/JSUI/InputApplication/entry/.gitignore b/JSUI/InputApplication/entry/.gitignore deleted file mode 100644 index 7d5b7a94f4dcf381f03ff21f28f8a2494b58023f..0000000000000000000000000000000000000000 --- a/JSUI/InputApplication/entry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/build -/node_modules diff --git a/JSUI/RatingApplication/entry/.gitignore b/JSUI/RatingApplication/entry/.gitignore deleted file mode 100644 index 7d5b7a94f4dcf381f03ff21f28f8a2494b58023f..0000000000000000000000000000000000000000 --- a/JSUI/RatingApplication/entry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/build -/node_modules diff --git a/JSUI/ShoppingOpenHarmony/entry/proguard-rules.pro b/JSUI/ShoppingOpenHarmony/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/JSUI/ShoppingOpenHarmony/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/JSUI/SliderApplication/entry/proguard-rules.pro b/JSUI/SliderApplication/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/JSUI/SliderApplication/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/JSUI/SwitchApplication/entry/proguard-rules.pro b/JSUI/SwitchApplication/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/JSUI/SwitchApplication/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/Media/Audio_OH_ETS/entry/.gitignore b/Media/Audio_OH_ETS/entry/.gitignore deleted file mode 100644 index 4f9a973815d0b5e49bc8547681a6b4bc7a178d12..0000000000000000000000000000000000000000 --- a/Media/Audio_OH_ETS/entry/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/node_modules -/.preview -/build \ No newline at end of file diff --git a/Media/Audio_OH_ETS/entry/package-lock.json b/Media/Audio_OH_ETS/entry/package-lock.json deleted file mode 100644 index 15bc7145be1490029883067847743ea7134cf545..0000000000000000000000000000000000000000 --- a/Media/Audio_OH_ETS/entry/package-lock.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "entry", - "version": "1.0.0", - "lockfileVersion": 1 -} diff --git a/Media/ImageEditorTemplate/entry/proguard-rules.pro b/Media/ImageEditorTemplate/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/Media/ImageEditorTemplate/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/Media/VideoOpenHarmony/entry/.gitignore b/Media/VideoOpenHarmony/entry/.gitignore deleted file mode 100644 index 7d5b7a94f4dcf381f03ff21f28f8a2494b58023f..0000000000000000000000000000000000000000 --- a/Media/VideoOpenHarmony/entry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/build -/node_modules diff --git a/Media/VideoOpenHarmony/entry/proguard-rules.pro b/Media/VideoOpenHarmony/entry/proguard-rules.pro deleted file mode 100644 index f7666e47561d514b2a76d5a7dfbb43ede86da92a..0000000000000000000000000000000000000000 --- a/Media/VideoOpenHarmony/entry/proguard-rules.pro +++ /dev/null @@ -1 +0,0 @@ -# config module specific ProGuard rules here. \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/AppScope/app.json5 b/NativeAPI/NativeTemplateDemo/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..f650aad178b54a3ca65f91014808b288609955f9 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 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.example.nativetemplatedemo", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true + } +} diff --git a/NativeAPI/NativeTemplateDemo/AppScope/resources/base/element/string.json b/NativeAPI/NativeTemplateDemo/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..80ff878b2c261f76f4580d9b9838183ac4767842 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "NativeTemplateDemo" + } + ] +} diff --git a/NativeAPI/NativeTemplateDemo/AppScope/resources/base/media/app_icon.png b/NativeAPI/NativeTemplateDemo/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/AppScope/resources/base/media/app_icon.png differ diff --git a/NativeAPI/NativeTemplateDemo/README.md b/NativeAPI/NativeTemplateDemo/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5e1ef89be8ec1b52b320d4c4f07663252ee86287 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/README.md @@ -0,0 +1,533 @@ +# 1.介绍 + +本篇Codelab主要介绍如何使用DevEco Studio for OpenHarmony创建一个Native C++应用。应用采用“Native C++”模板,实现了通过Node-API调用C标准库的功能。本示例通过调用C标准库接口来演示调用过程,具体接口是C标准库的计算两个给定数平方和的平方根(hypot)。Codelab实现效果如下图所示: + +![](figures/zh-cn_image_0000001304821425.png) + + + +# 2.相关概念 + +[Node\_API](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/native-lib/third_party_napi/napi.md) :用于封装JavaScript能力为native插件的API,独立于底层JavaScript,并作为Node.js的一部分。 + +[Native API中支持的标准库](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/native-lib/third_party_libc/musl.md) :目前支持标准C库、C++库、OpenSL ES、zlib。 + +[C常用函数库](https://zh.cppreference.com/w/c/numeric/math) :math.h。 + +[Cmake](https://cmake.org/cmake/help/latest/) :管理源代码构建的工具。 + +# 3.搭建OpenHarmony环境 + +完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: + +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96) :标准系统解决方案(二进制)。 + + 以3.1版本为例: + + ![](figures/zh-cn_image_0000001293014749.png) + +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-standard-env-setup.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-standard-running-rk3568-burning.md) + +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87) ,完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E5%88%9B%E5%BB%BAets%E5%B7%A5%E7%A8%8B) 创建工程(模板选择“Native C++”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E4%BD%BF%E7%94%A8%E7%9C%9F%E6%9C%BA%E8%BF%90%E8%A1%8C%E5%BA%94%E7%94%A8) 。 + +# 4.代码结构解读 + +本篇Codelab只对核心代码进行讲解,整个工程的代码结构如下: + +![](figures/zh-cn_image_0000001247459334.png) + +文件说明如下: + +``` +├── cpp:C++代码区 +│ ├── types: // 接口存放文件夹 +│ │ └── libhello +│ │ ├── index.d.ts // 接口文件 +│ │ └── package.json // 接口注册配置文件 +│ ├── CmakeList.text // Cmake打包配置文件 +│ └── hello.cpp // C++源代码 +└── ets // ets代码区 + └── Application + │ └── AbilityStage.ts // Hap包运行时类 + ├── MainAbility + │ └── MainAbility.ts // Ability,提供对Ability生命周期、上下文环境等调用管理 + └── pages + └── index.ets // 主页面 +``` + +# 5.eTS调用C++方法流程 + +1. 应用架构。 + + 整个应用架构可以分为三部分:C++侧、eTS侧、工具链。 + + - C++侧:包含各种文件的引用、C++或者C代码、Node\_API将C++函数与JavaScript关联的信息等。 + - eTS侧:包含界面UI、自身方法,调用引用包的方法等。 + - 工具链:包含Cmake打包工具在内的系列工具。 + + 在eTS调用C++方法的过程中,需要使用到[Node\_API](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/native-lib/third_party_napi/napi.md) 、[Cmake](https://cmake.org/cmake/help/latest/) 等工具来做中间转换,整个架构及其关联关系如下: + + ![](figures/zh-cn_image_0000001259093508.png) + + >![](public_sys-resources/icon-note.gif) **说明:** + >在上面的示意图中,hello.cpp文件用来编写C++代码,并通过Node\_API将C++函数与JavaScript方法关联。C++代码通过Cmake打包工具打包成动态链接库SO文件,并通过xxx.d.ts文件对外提供接口。eTS端通过引入SO包的方式去调用SO文件中的接口。 + +2. 调用、打包流程。 + + 在eTS调用C++方法的过程中,调用、打包流程如下: + + ![](figures/zh-cn_image_0000001307070421.png) + + >![](public_sys-resources/icon-note.gif) **说明:** + >上图中C++代码通过Cmake打包成SO文件后可以直接被eTS侧引入,最终通过hivgor一起打包成可执行的OpenHarmony hap包。 + + 重点环节说明如下: + + - ①cpp源码编写,Node\_API将C++函数与JavaScript方法关联,index.d.ts接口文档,package.json文件编写。 + + (1)c++编写“hyPotC”方法,用以实现计算两个数平方和的平方根。 + + ``` + #include "napi/native_api.h" + #include "math.h" + static napi_value hyPotC(napi_env env, napi_callback_info info){ + ... + } + ``` + + (2)Node\_API将C++函数与JavaScript方法关联。 + + 将C++的“hyPotC”函数进行注册,注册的对外接口名为“hyPot”。 + + ``` + static napi_value Init(napi_env env, napi_value exports){ + napi_property_descriptor desc[] = { + { "hyPot", nullptr, hyPotC, nullptr, nullptr, nullptr, napi_default, nullptr }, + }; + ... + } + ``` + + (3)index.d.ts接口文档编写。 + + ``` + export const hyPot: (a: number, b: number) => number; + ``` + + (4)package.json文件编写。 + + ``` + { + "name": "libhello.so", + "types": "./index.d.ts" + } + ``` + + - ②Cmake打包配置、CmakeList.txt配置需要添加的hello.cpp文件。 + + ``` + add_library(hello SHARED hello.cpp) + ``` + + - ③index.ets中引入SO包,调用SO包中的hyPot方法。 + + ``` + import libHello from "libhello.so" + ... + Button(this.buttonSubmit) + ... + .onClick(() => { + this.result = libHello.hyPot(this.num1,this.num2) + }) + ``` + +# 6.C++方法实现 + +1. 编写方法。 + 1. 方法说明: + + + + + + + + + +

方法名

+

说明

+

hyPotC

+

求两个数平方和的平方根

+
+ + 2. hyPotC方法传入参数说明: + + + + + + + + + + + + + + + +

参数名

+

类型

+

说明

+

env

+

napi_env

+

用于表示底层 Node-API 实现可以用来保持 VM 特定状态的上下文。

+

info

+

napi_callback_info

+

传递给回调函数的不透明数据类型。它可用于获取有关调用回调的上下文的附加信息。

+
+ + 3. hyPotC返回参数说明: + + + + + + + + + +

类型

+

说明

+

napi_value

+

这是一个不透明的指针,用于表示 JavaScript 值(这里返回的是计算后的结果)。

+
+ + 4. 编写方法。 + + ``` + #include "napi/native_api.h" + #include "math.h" + static napi_value hyPotC(napi_env env, napi_callback_info info) + { + // 参数数量 + size_t argc = 2; + // 声明参数数组 + napi_value args[2] = {nullptr}; + // 获取传入的参数并依次放入参数数组中 + napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); + // 对第一个js参数类型进行判定 + napi_valuetype valueType0; + napi_typeof(env, args[0], &valueType0); + // 对第二个js参数类型进行判定 + napi_valuetype valueType1; + napi_typeof(env, args[1], &valueType1); + // 将第一个传入参数转化为double类型 + double value0; + napi_get_value_double(env, args[0], &value0); + // 将第二个传入参数转化为double类型 + double value1; + napi_get_value_double(env, args[1], &value1); + // 声明返回结果字段,并调用C标准库的hypot方法进行计算 + napi_value sum; + double result = hypot(value0,value1); + napi_create_double(env, result, &sum); + return sum; + } + ``` + + 5. 注册模块。 + + 模块注册是固定写法,在napi\_property\_descriptor desc\[\]中我们需要将编写的“hyPotC”方法(从左至右第三个参数)与对暴露的接口“hyPot”接口(从左至右第一个参数)进行关联,其他参考示例默认填写即可。 + + 示例: + + ``` + { "hyPot", nullptr, hyPotC, nullptr, nullptr, nullptr, napi_default, nullptr } + ``` + + 模块注册代码: + + ``` + EXTERN_C_START + static napi_value Init(napi_env env, napi_value exports) + { + napi_property_descriptor desc[] = { + { "hypot", nullptr, Hypot, nullptr, nullptr, nullptr, napi_default, nullptr }, + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; + } + EXTERN_C_END + ``` + + 6. 其他模块描述。 + + 描述信息可以直接参考如下示例,nm\_modname可以根据实际情况修改。 + + ``` + static napi_module demoModule = { + .nm_version =1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "libhello", + .nm_priv = ((void*)0), + .reserved = { 0 }, + }; + extern "C" __attribute__((constructor)) void RegisterModule(void) + { + napi_module_register(&demoModule); + } + ``` + +2. 编写接口文档。 + + index.d.ts用于对外提供方法、说明文档(名字可以更改,点击方法可以直接链接到index.d.ts)。 + + ``` + export const hyPot: (a: number, b: number) => number; + ``` + +3. 在package.json文件中将index.d.ts与cpp文件关联起来。 + + ``` + { + "name": "libhello.so", + "types": "./index.d.ts" + } + ``` + +4. CMakeLists.txt配置CMake打包参数。 + + CMakeLists.txt是CMake打包的配置文件,里面的大部分内容无需修改,project、add\_library方法中的内容可以根据实际情况修改。 + + ``` + # the minimum version of CMake.指明了对cmake的最低(高)版本的要求 + cmake_minimum_required(VERSION 3.4.1) + #配置项目信息 + project(XComponent) + #指定编程语言 + set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + #设置头文件的搜索目录 + include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include + ) + # 添加名为xxx的库 + add_library(hello SHARED hello.cpp) + #构建此可执行文件需要链接的库 + target_link_libraries(hello PUBLIC libace_napi.z.so libc++.a) + ``` + +# 7.界面设计 + +1. 界面整体规划效果如下图所示: + + ![](figures/zh-cn_image_0000001305065829.png) + +2. 设置所需要用到的参数。 + 1. 参数说明。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

字段

+

类型

+

说明

+

tittle

+

string

+

应用标题

+

message

+

string

+

示例说明

+

tipsNum1

+

number

+

提示输入第一个参数

+

tipsNum2

+

number

+

提示输入第二个参数

+

tipsResult

+

string

+

结果提示

+

buttonSubmit

+

string

+

计算按钮名称

+

result

+

string

+

结果

+

num1

+

number

+

输入的第一数

+

num2

+

number

+

输入的第二个数

+
+ + 2. 代码中设置参数,详情请参考源码。 + + ``` + @Entry + @Component + struct Index { + private textInputController1: TextInputController = new TextInputController() + private textInputController2: TextInputController = new TextInputController() + private tittle: string = '调用C标准库示例' + ... + build() { + ... + } + } + ``` + +3. 界面实现,详情请参考源码。 + + ``` + @Entry + @Component + struct Index { + ... + build() { + Row() { + Column() { + Row(){ + ... + }.height('10%').width('100%').justifyContent(FlexAlign.Center) + Row(){ + ... + }.height('15%').width('100%').justifyContent(FlexAlign.Center) + Row(){ + ... + }.height('5%').width('100%').justifyContent(FlexAlign.Start) + Row(){ + ... + }.height('5%').width('100%').margin({top:20}) + Row(){ + ... + }.height('10%').width('100%').touchable(false) + Row(){ + Button(this.buttonSubmit) + .fontSize(40) + .fontWeight(FontWeight.Bold) + .margin({top:5}) + .height(100) + .width(200) + }.height('30%').width('100%').justifyContent(FlexAlign.Center) + } + .width('100%') + } + .height('100%') + } + } + ``` + +4. 绑定事件、关联参数。 + + 在这一步中,两个TextInput组件分别绑定onChange事件,并分别关联num1,num2来记录输入的参数 + + ``` + @Entry + @Component + struct Index { + ... + build() { + Row() { + Column() { + ... + Row(){ + ... + TextInput({ placeholder: '请输入第一个数字:', controller:this.textInputController1}).type(InputType.Number) + .height('100%').width('60%').margin({left:10,right:30}) + .onChange(value =>{this.num1 = parseFloat(value)}) + }.height('5%').width('100%').justifyContent(FlexAlign.Start) + Row(){ + ... + TextInput({ placeholder: '请输入第二个数字:', controller:this.textInputController2}).type(InputType.Number) + .height('100%').width('60%').margin({left:10,right:30}) + .onChange(value =>{this.num2 = parseFloat(value)}) + }.height('5%').width('100%').margin({top:20}) + ... + } + .height('100%') + } + } + ``` + +# 8.JS调用C++方法 + +1. 在index.ets文件中引入编译好的SO包。 + + ``` + import libHello from "libhello.so" + ``` + +2. Button组件添加点击事件,调用testNapi中的方法。 + + ``` + Button(this.buttonSubmit) + .fontSize(40) + .fontWeight(FontWeight.Bold) + .margin({top:5}) + .height(100) + .width(200) + .onClick(() => { + this.result = libHello.hyPot(this.num1,this.num2) + }) + ``` + +3. hvihgor打包将so文件与eTS代码一起打包成hap包。 +4. 安装hap包运行。 + +# 9.恭喜您 + +通过本篇Codelab我们了解了C++代码如何与JS实现关联,eTS如何调用SO包中的接口等,同时也掌握了C++代码的具体编写与打包流程。 + +知识点: + +- Node\_API +- Native API中支持的标准库 +- C常用函数库 +- Cmake diff --git a/NativeAPI/NativeTemplateDemo/build-profile.json5 b/NativeAPI/NativeTemplateDemo/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..bc139b58f33409f54981a2b31bf556f6f1edd01c --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/build-profile.json5 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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": [], + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default", + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/build-profile.json5 b/NativeAPI/NativeTemplateDemo/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..81c6ae377a05e002f03102b69d2c95076fdcfd66 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/build-profile.json5 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 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": "-v -DOHOS_STL=c++_shared", + "abiFilters": [ + "armeabi-v7a", + ], + "cppFlags": "", + } + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/hvigorfile.js b/NativeAPI/NativeTemplateDemo/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..046440d7e1f1965a8564b6f6db4f4e5b91893525 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/hvigorfile.js @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021 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.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/NativeAPI/NativeTemplateDemo/entry/package.json b/NativeAPI/NativeTemplateDemo/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ae1949123a1094d051aa2bb1ae040e05289fac26 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/package.json @@ -0,0 +1,16 @@ +{ + "license":"ISC", + "devDependencies":{ + "@types/libhello.so":"file:./src/main/cpp/types/libhello" + }, + "name":"entry", + "ohos":{ + "org":"huawei", + "directoryLevel":"module", + "buildTool":"hvigor" + }, + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{} +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/CMakeLists.txt b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb3e8cf5ecf077b801dc770e6d2fb3f370d56654 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright (c) 2021 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. + +# the minimum version of CMake.指明了对cmake的最低(高)版本的要求 +cmake_minimum_required(VERSION 3.4.1) +#配置项目信息 +project(XComponent) +#指定编程语言 +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +#设置头文件的搜索目录 +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include + ) +# 添加名为xxx的库 +add_library(hello SHARED hello.cpp) +#构建此可执行文件需要链接的库 +target_link_libraries(hello PUBLIC libace_napi.z.so libc++.a) \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/hello.cpp b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/hello.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d5c8d337f06fb1c99c807c786aece0c3213268d --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/hello.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 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 "math.h" + +static napi_value hyPotC(napi_env env, napi_callback_info info) +{ + // 参数数量 + size_t argc = 2; + // 声明参数数组 + napi_value args[2] = {nullptr}; + // 获取传入的参数并依次放入参数数组中 + napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); + // 对第一个js参数类型进行判定 + napi_valuetype valueType0; + napi_typeof(env, args[0], &valueType0); + // 对第二个js参数类型进行判定 + napi_valuetype valueType1; + napi_typeof(env, args[1], &valueType1); + // 将第一个传入参数转化为double类型 + double value0; + napi_get_value_double(env, args[0], &value0); + // 将第二个传入参数转化为double类型 + double value1; + napi_get_value_double(env, args[1], &value1); + // 声明返回结果字段,并调用C标准库的hypot方法进行计算 + napi_value sum; + double result = hypot(value0,value1); + napi_create_double(env, result, &sum); + return sum; +} + + + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + { "hyPot", nullptr, hyPotC, 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 = "libhello", +.nm_priv = ((void*)0), +.reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ +napi_module_register(&demoModule); +} diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/types/libhello/index.d.ts b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/types/libhello/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..fce82814254301b9f9b350396851fe1d47f4fd9a --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/types/libhello/index.d.ts @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021 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 hyPot: (a: number, b: number) => number; diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/types/libhello/package.json b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/types/libhello/package.json new file mode 100644 index 0000000000000000000000000000000000000000..06114142df41dd957be4d5cbdb080fab44d567db --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/types/libhello/package.json @@ -0,0 +1,4 @@ +{ + "name": "libhello.so", + "types": "./index.d.ts" +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/ets/Application/AbilityStage.ts b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c9fcaafa50d6605b274c4a54a4b6225bc9bc1d0 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 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 AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/ets/MainAbility/MainAbility.ts b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..f870382553ec44243fad1ac3a9b36fb22acb9d33 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 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 Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + + windowStage.setUIContent(this.context, "pages/index", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/index.ets b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..620f76c1ebd0d08453d3f180cbb0bd738dc2d403 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/index.ets @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 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 libHello from "libhello.so" + +@Entry +@Component +struct Index { + private textInputController1: TextInputController = new TextInputController() + private textInputController2: TextInputController = new TextInputController() + private tittle: string = '调用C标准库示例' + private message: string = '计算两个给定数平方和的平方根√(x²+y²)' + private tipsNum1: string = '请输入第一个数:' + private tipsNum2: string = '请输入第二个数:' + private tipsResult: string = '结果:' + private buttonSubmit: string = '计算' + @State result: number = 0 + @State num1: number = 0.0 + @State num2: number = 0.0 + + build() { + Row() { + Column() { + Row(){ + Text(this.tittle).height('100%').align(Alignment.Center).fontSize(40).fontWeight(800) + }.height('10%').width('100%').justifyContent(FlexAlign.Center) + Row(){ + Text(this.message).height('100%').align(Alignment.Center).fontSize(24).fontWeight(500) + }.height('15%').width('100%').justifyContent(FlexAlign.Center) + Row(){ + Text(this.tipsNum1).fontColor(Color.Black).fontSize(24).width('30%').height('100%').margin({left:30}) + TextInput({ placeholder: '请输入第一个数字:', controller:this.textInputController1}).type(InputType.Number) + .height('100%').width('60%').margin({left:10,right:30}) + .onChange(value =>{this.num1 = parseFloat(value)}) + }.height('5%').width('100%').justifyContent(FlexAlign.Start) + Row(){ + Text(this.tipsNum2).fontColor(Color.Black).fontSize(24).width('30%').height('100%').margin({left:30}) + TextInput({ placeholder: '请输入第二个数字:', controller:this.textInputController2}).type(InputType.Number) + .height('100%').width('60%').margin({left:10,right:30}) + .onChange(value =>{this.num2 = parseFloat(value)}) + }.height('5%').width('100%').margin({top:20}) + Row(){ + Text(this.tipsResult).fontColor(Color.Black).fontSize(24).width('40%').height('100%').margin({left:30}) + Text(''+this.result).fontColor(Color.Black).fontSize(30).width(60).height(200).width('60%').height('100%') + }.height('10%').width('100%').touchable(false) + Row(){ + Button(this.buttonSubmit) + .fontSize(40) + .fontWeight(FontWeight.Bold) + .margin({top:5}) + .height(100) + .width(200) + .onClick(() => { + this.result = libHello.hyPot(this.num1,this.num2) + }) + }.height('30%').width('100%').justifyContent(FlexAlign.Center) + } + .width('100%') + } + .height('100%') + } +} diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/module.json5 b/NativeAPI/NativeTemplateDemo/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e1f8ca34d91534b014326aa1723a38123b086044 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/module.json5 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 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", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/element/string.json b/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..83fab4ae57f503cf1deee58ef1b9b48833da7ef9 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "native_C++" + }, + { + "name": "MainAbility_desc", + "value": "description" + } + ] +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/media/icon.png b/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/media/icon.png differ diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/profile/main_pages.json b/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..feec276e105eeb8d621c20aaf838f318b0a94150 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/index" + ] +} diff --git a/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001247459334.png b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001247459334.png new file mode 100644 index 0000000000000000000000000000000000000000..dea12adf11ab8de0706d199c77bd6b0a9cdbc89c Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001247459334.png differ diff --git a/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001259093508.png b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001259093508.png new file mode 100644 index 0000000000000000000000000000000000000000..c97d914014a74cb150b7bba3807dfea7de2f6921 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001259093508.png differ diff --git a/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001293014749.png b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001293014749.png new file mode 100644 index 0000000000000000000000000000000000000000..9d752ff5311af2816bf898cb2c18ef33bf085726 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001293014749.png differ diff --git a/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001304821425.png b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001304821425.png new file mode 100644 index 0000000000000000000000000000000000000000..645abbc09bffc82be4ee6c5247d977812556b4dd Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001304821425.png differ diff --git a/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001305065829.png b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001305065829.png new file mode 100644 index 0000000000000000000000000000000000000000..e8a44f530cf731cf1fee15243691ae4594697be7 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001305065829.png differ diff --git a/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001307070421.png b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001307070421.png new file mode 100644 index 0000000000000000000000000000000000000000..951836201f37069f9e38cf50ae90ec7ff815a9e4 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/figures/zh-cn_image_0000001307070421.png differ diff --git a/NativeAPI/NativeTemplateDemo/hvigorfile.js b/NativeAPI/NativeTemplateDemo/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..0975e47a7f53d9ef0d5aa09cd557602a7e01f342 --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/hvigorfile.js @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021 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.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/package.json b/NativeAPI/NativeTemplateDemo/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1988277b7496674e51af4b9bdf8b7e239090125c --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/package.json @@ -0,0 +1,18 @@ +{ + "license":"ISC", + "devDependencies":{}, + "name":"nativetemplatedemo", + "ohos":{ + "org":"huawei", + "directoryLevel":"project", + "buildTool":"hvigor" + }, + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{ + "@ohos/hvigor-ohos-plugin":"1.0.6", + "hypium":"^1.0.0", + "@ohos/hvigor":"1.0.6" + } +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-caution.gif b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-caution.gif differ diff --git a/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-danger.gif b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-danger.gif differ diff --git a/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-note.gif b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-note.gif differ diff --git a/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-notice.gif b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-notice.gif differ diff --git a/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-tip.gif b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-tip.gif differ diff --git a/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-warning.gif b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NativeAPI/NativeTemplateDemo/public_sys-resources/icon-warning.gif differ diff --git a/NativeAPI/XComponent/AppScope/app.json5 b/NativeAPI/XComponent/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8b884d0be07d41a71e634ad2ae291bf9fd1de38e --- /dev/null +++ b/NativeAPI/XComponent/AppScope/app.json5 @@ -0,0 +1,11 @@ +{ + "app": { + "bundleName": "ohos.samples.myapplication", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true + } +} diff --git a/NativeAPI/XComponent/AppScope/resources/base/element/string.json b/NativeAPI/XComponent/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..001dc15a006a3fd043a055beb26d3c6c2a021949 --- /dev/null +++ b/NativeAPI/XComponent/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "XComponent" + } + ] +} diff --git a/NativeAPI/XComponent/AppScope/resources/base/media/app_icon.png b/NativeAPI/XComponent/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NativeAPI/XComponent/AppScope/resources/base/media/app_icon.png differ diff --git a/NativeAPI/XComponent/LICENSE b/NativeAPI/XComponent/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..80576ef141485b36eea4aebf25af97020bc2de44 --- /dev/null +++ b/NativeAPI/XComponent/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved. + + 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. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/NativeAPI/XComponent/README.md b/NativeAPI/XComponent/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b880fe080838156df5ca7a87dd0449f3dac769a9 --- /dev/null +++ b/NativeAPI/XComponent/README.md @@ -0,0 +1,521 @@ +# 介绍 + +本篇Codelab主要介绍如何使用XComponent组件调用Native API来创建EGL/GLES环境,从而使用标准OpenGL ES进行图形渲染。本项目使用OpenGL实现了在主页面绘制一个正方形,并可以改变正方形的颜色。如图所示,点击“绘制矩形”按钮,下方的XComponent组件中便渲染出一个正方形,此时点击正方形,可以改变正方形的颜色。 + +![](figures/1.jpg)![](figures/2.jpg)![](figures/3.jpg) + +# 相关概念 + +[XComponent](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-xcomponent.md):OpenHarmony API8开始提供的UI组件,可用于EGL/OpenGLES和媒体数据写入。 + +[Native API](https://gitee.com/openharmony/docs/tree/master/zh-cn/application-dev/reference/native-apis):用于封装C++方法,暴露给eTS侧。 + +# 搭建OpenHarmony环境 + +完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: + +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。 + + 以3.1版本为例: + + ![](figures/zh-cn_image_0000001214154402.png) + +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-standard-env-setup.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-standard-running-rk3568-burning.md) + +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E5%88%9B%E5%BB%BAets%E5%B7%A5%E7%A8%8B)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E4%BD%BF%E7%94%A8%E7%9C%9F%E6%9C%BA%E8%BF%90%E8%A1%8C%E5%BA%94%E7%94%A8)。 + +# 代码结构解读 + +本篇Codelab应用“Native C++”模板,整个工程的代码结构如下图所示: + +![](figures/zh-cn_image_0000001312007181.png) + +各模块和文件说明说下: + +``` +├── cpp // C++代码区 +│ ├── manager // 生命周期管理模块 +│ │ ├── plugin_manager.cpp +│ │ └── plugin_manager.h +│ ├── render // 渲染模块 +│ │ ├── egl_core.cpp // 核心渲染代码 +│ │ ├── egl_core.h +│ │ ├── plugin_render.cpp // Native API封装代码 +│ │ └── plugin_render.h +│ ├── types +│ ├── CMakeLists.txt // Cmake编译工具链 +│ └── napi_init.cpp +└── ets // eTS代码区 + ├── Application + │ └── AbilityStage.ts // Hap包运行时类 + ├── MainAbility + │ └── MainAbility.ts // Ability,提供对Ability生命周期、上下文环境等管理 + └── pages + └── index.ets // 主页面 +``` + +整个项目各模块之间的调用流程可用下图直观表示: + +![](figures/zh-cn_image_0000001318156501.png) + +# C++侧渲染功能实现 + +本节将介绍在C++侧如何实现图形渲染功能。 + +1.首先进行初始化,包括初始化可用的EGLDisplay、确定可用的Surface配置、创建渲染区域Surface、创建并关联上下文等。 + +``` +void EGLCore::eglContextInit(void* window, int w, int h) { + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "EGLCore", "eglContextInit ===> window = %{public}p, w = %{public}d, h = %{public}d", window, w, h); + width_ = w; + height_ = h; + mEglWindow = static_cast(window); + + // 初始化EGLDisplay + EGLint majorVersion; + EGLint minorVersion; + mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (mEglDisplay == EGL_NO_DISPLAY) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglGetDisplay ===> unable to get EGL display"); + return; + } + if (!eglInitialize(mEglDisplay, &majorVersion, &minorVersion)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglInitialize ===> unable to get initialize EGL display"); + return; + } + + // 选择配置 + EGLint attribList[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + + const EGLint maxConfigs = 1; + EGLint numConfigs; + if (!eglChooseConfig(mEglDisplay, attribList, &mEglConfig, maxConfigs, &numConfigs)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglChooseConfig ===> unable to choose configs"); + return; + } + + // 创建surface + EGLint winAttribs[] = { + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, + EGL_NONE + }; + if (mEglWindow) { + mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mEglWindow, winAttribs); + if (mEglSurface == nullptr) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglCreateWindowSurface ===> unable to create surface"); + return; + } + } + + // 创建context + EGLint verList[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, verList); + if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglMakeCurrent ===> error = %{public}d", eglGetError()); + } + + // 创建program + mProgramHandle = createProgram(vertexShader, fragmentShader); + if (!mProgramHandle) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "createProgram ===> unable to create program"); + return; + } +} +``` + +2.使用OpenGL渲染正方形。 + +实现一个渲染函数,通过调用OpenGL相关API进行绘制,有关OpenGL相关介绍请参考对应资料。 + +``` +void EGLCore::draw() { + GLfloat color[] = { + 0.5f, 0.6f, 0.3f, 1.0f + }; + + const GLfloat rectangleVertices[] = { + -0.5f, 0.5f, + 0.5f, 0.5f, + 0.5f, -0.5f, + -0.5f, -0.5f + }; + + glViewport(0, 0, width_, height_); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(mProgramHandle); + GLint positionHandle = glGetAttribLocation(mProgramHandle, "a_position"); + glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, rectangleVertices); + glEnableVertexAttribArray(positionHandle); + glVertexAttrib4fv(1, color); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableVertexAttribArray(positionHandle); + + glFlush(); + glFinish(); + eglSwapBuffers(mEglDisplay, mEglSurface); + flag = true; +} +``` + +3.改变正方形的颜色。 + +重新绘制一个大小相同、颜色不同的正方形,与原正方形地址交换,实现“改变颜色”功能。 + +``` +void EGLCore::changeColor() { + if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "elgMakeCurrent ===> error = %{public}d", eglGetError()); + } + + GLfloat color[] = { + 0.9f, 0.5f, 0.7f, 1.0f + }; + + const GLfloat rectangleVertices[] = { + -0.5f, 0.5f, + 0.5f, 0.5f, + 0.5f, -0.5f, + -0.5f, -0.5f + }; + + glViewport(0, 0, width_, height_); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(mProgramHandle); + GLint positionHandle = glGetAttribLocation(mProgramHandle, "a_position"); + glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, rectangleVertices); + glEnableVertexAttribArray(positionHandle); + glVertexAttrib4fv(1, color); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableVertexAttribArray(positionHandle); + + if (flag) { + eglSwapBuffers(mEglDisplay, mEglSurface); + } +} +``` + +# 使用Native API将C++方法暴露给eTS侧 + +本节将介绍如何使用Native API将C++实现的方法暴露给eTS侧,从而能在eTS侧调用对应方法。 + +1.创建NAPI接口函数,封装对应C++方法。 + +``` +napi_value PluginRender::NapiDrawRectangle(napi_env env, napi_callback_info info) { + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginRender", "NapiDrawRectangle"); + napi_value exportInstance; + napi_value thisArg; + napi_status status; + OH_NativeXComponent *nativeXComponent = nullptr; + + int32_t xID; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + + napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr); + + status = napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); + if (status != napi_ok) { + return nullptr; + }; + + status = napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)); + if (status != napi_ok) { + return nullptr; + } + + xID = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); + if (xID != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "PluginRender", "NapiDrawRectangle: Unable to get XComponent id"); + return nullptr; + } + + std::string id(idStr); + PluginRender* render = PluginRender::getInstance(id); + if (render) { + render->eglCore_->draw(); // 该接口函数封装的是上文实现的渲染函数 + } + return nullptr; +} +``` + +2.注册方法。 + +将接口函数注册为eTS侧接口,如下所示,在eTS侧调用drawRectangle\(\)方法,即可绘制正方形。 + +``` +napi_value PluginRender::Export(napi_env env, napi_value exports) { + napi_property_descriptor desc[] = { + { "drawRectangle", nullptr, PluginRender::NapiDrawRectangle, nullptr, nullptr, nullptr, napi_default, nullptr} + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +``` + +# 使用Native API实现触摸事件回调函数 + +为了在触摸时改变正方形的颜色,需要将上文实现的改变颜色函数changeColor\(\)封装为触摸事件的回调函数,本节介绍如何使用Native API来实现这一功能。 + +1.封装C++对应方法。 + +创建一个新函数,将C++对应方法封装。 + +``` +void DispatchTouchEventCB(OH_NativeXComponent* component, void* window) { + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Callback", "DispatchTouchEventCB"); + + int32_t xID; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + xID = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + + if (xID != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Callback", "DispatchTouchEventCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = PluginRender::getInstance(id); + if (render) { + render->eglCore_->changeColor(); // 封装上文实现的改变颜色函数 + } +} +``` + +2.将新函数绑定为触摸事件的回调函数。 + +``` + auto renderCallback = &PluginRender::callback_; + renderCallback->OnSurfaceCreated = OnSurfaceCreatedCB; + renderCallback->OnSurfaceChanged = OnSurfaceChangedCB; + renderCallback->OnSurfaceDestroyed = OnSurfaceDestroyedCB; + renderCallback->DispatchTouchEvent = DispatchTouchEventCB; // 这一步修改了触摸事件的回调函数,在触摸事件触发时调用NAPI接口函数,从而调用原C++方法 +``` + +# 使用Native API在应用生命周期调用相应C++方法 + +Native API可以将实现的接口函数绑定到eTS侧对应的生命周期函数上,从而在应用切换到不同的生命周期时自动调用封装的C++方法。 + +1.编写对应接口函数。 + +编写想要在对应的生命周期调用的接口函数,如在应用创建时调用的接口函数: + +``` +napi_value PluginManager::NapiOnCreate(napi_env env, napi_callback_info info) { + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "NapiOnCreate"); + // do something + return nullptr; +} +``` + +2.将接口函数注册到JS侧对应的生命周期函数上。 + +``` +napi_value PluginManager::getContext(napi_env env, napi_callback_info info) { + napi_status status; + napi_value exports; + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + if (argc != 1) { + napi_throw_type_error(env, NULL, "Wrong number of arguments"); + return nullptr; + } + + napi_valuetype valuetype; + status = napi_typeof(env, args[0], &valuetype); + + if (status != napi_ok) { + return nullptr; + } + + if (valuetype != napi_number) { + napi_throw_type_error(env, NULL, "Wrong type of arguments"); + return nullptr; + } + + int64_t value; + napi_get_value_int64(env, args[0], &value); + napi_create_object(env, &exports); + + switch (value) { + case APP_LIFECYCLE: + { + /***** 应用 APP 生命周期注册 *****/ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "getContext: APP_LIFECYCLE"); + /***** Register App Lifecycle *****/ + napi_property_descriptor desc[] = { + { "onCreate", nullptr, PluginManager::NapiOnCreate, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "onShow", nullptr, PluginManager::NapiOnShow, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "onHide", nullptr, PluginManager::NapiOnHide, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "onDestroy", nullptr, PluginManager::NapiOnDestroy, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + } + break; + + case JS_PAGE_LIFECYCLE: + { + /***** 声明式开发范式 JS Page 生命周期注册 *****/ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "getContext: JS_PAGE_LIFECYCLE"); + /***** Register JS Page Lifecycle *****/ + napi_property_descriptor desc[] = { + { "onPageShow", nullptr, PluginManager::NapiOnPageShow, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "onPageHide", nullptr, PluginManager::NapiOnPageHide, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + } + break; + + default: + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "PluginManager", "getContext: wrong type of arguments"); + } + return exports; +} +``` + +# 注册与编译 + +本节介绍如何将上文的实现统一打包注册并编译动态链接库文件。 + +1.注册模块。 + +在该函数中注册上文实现的接口函数,从而将封装的C++方法暴露出来,供eTS侧调用。 + +``` +static napi_value Init(napi_env env, napi_value exports) { + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Init", "Init begins"); + napi_property_descriptor desc[] ={ + { "getContext", nullptr, PluginManager::getContext, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + + bool ret = PluginManager::GetInstance()->Export(env, exports); + if (!ret) { + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Init", "Init failed"); + } + return exports; +} +``` + +2.描述信息。 + +编写接口的描述信息,根据实际需要可以修改对应参数。 + +``` +static napi_module nativerenderModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "nativerender", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; +``` + +3.CMake编译。 + +使用CMake工具链将C++源代码编译成动态链接库文件。 + +``` +cmake_minimum_required(VERSION 3.4.1) +project(XComponent) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +add_definitions(-DOHOS_PLATFORM) +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include + ) +add_library(nativerender SHARED + render/egl_core.cpp + render/plugin_render.cpp + manager/plugin_manager.cpp + napi_init.cpp + ) + +find_library( # Sets the name of the path variable. + EGL-lib + EGL ) + +find_library( # Sets the name of the path variable. + GLES-lib + GLESv3 ) + +find_library( # Sets the name of the path variable. + hilog-lib + hilog_ndk.z ) + +find_library( # Sets the name of the path variable. + libace-lib + ace_ndk.z ) + +find_library( # Sets the name of the path variable. + libnapi-lib + ace_napi.z ) + +find_library( # Sets the name of the path variable. + libuv-lib + uv ) + +target_link_libraries(nativerender PUBLIC ${EGL-lib} ${GLES-lib} ${hilog-lib} ${libace-lib} ${libnapi-lib} ${libuv-lib} libc++.a) +``` + +# eTS侧界面设计与方法调用 + +1.导入模块。 + +在eTS侧导入编译生成的动态链接库文件。 + +``` +import nativerender from "libnativerender.so"; +``` + +2.在eTS侧增加XComponent组件,调用.onLoad\(\)方法指定上下文环境。 + +``` +XComponent({ id: 'xcomponentId', type: 'texture', libraryname: 'nativerender'}) + .onLoad((context) => { + this.context = context; + }) + .onDestroy(() => { + }) +``` + +3.新增Button组件,绑定由Native API注册的drawTriangle\(\)方法,实现绘制正方形的功能。 + +``` +Button('绘制矩形') + .margin({ bottom: 10 }) + .onClick(() => { + if (this.context) { + this.context.drawTriangle(); + } + }) +``` + +# 恭喜您 + +通过本篇Codelab你已经学会了使用XComponent组件来调用Native API创建EGL/GLES环境,并使用OpenGL ES进行开发渲染。同时也掌握了使用回调函数来响应触摸事件,以及使用Native API在应用的对应生命周期调用C++方法。 + diff --git a/NativeAPI/XComponent/build-profile.json5 b/NativeAPI/XComponent/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..fc53829be062f3a883f815802e6039c733ebb352 --- /dev/null +++ b/NativeAPI/XComponent/build-profile.json5 @@ -0,0 +1,26 @@ +{ + "app": { + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default", + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/build-profile.json5 b/NativeAPI/XComponent/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3087ac4d5e3cbb6ac412080c79d46ec93792f6ff --- /dev/null +++ b/NativeAPI/XComponent/entry/build-profile.json5 @@ -0,0 +1,21 @@ +{ + "apiType": 'stageMode', + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "-v -DOHOS_STL=c++_shared", + "abiFilters": [ + "armeabi-v7a", + ], + "cppFlags": "", + } + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/hvigorfile.js b/NativeAPI/XComponent/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..d7720ee6a7aad5c617d1fd2f6fc8c87067bfa32c --- /dev/null +++ b/NativeAPI/XComponent/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/NativeAPI/XComponent/entry/package.json b/NativeAPI/XComponent/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..606384604f63fb9cbefd5456e7750497b499228a --- /dev/null +++ b/NativeAPI/XComponent/entry/package.json @@ -0,0 +1,16 @@ +{ + "license": "ISC", + "devDependencies": { + "@types/libhello.so": "file:./src/main/cpp/types/libhello" + }, + "name": "entry", + "ohos": { + "org": "huawei", + "directoryLevel": "module", + "buildTool": "hvigor" + }, + "description": "example description", + "repository": {}, + "version": "1.0.0", + "dependencies": {} +} diff --git a/NativeAPI/XComponent/entry/src/main/cpp/CMakeLists.txt b/NativeAPI/XComponent/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..71b5ae2355fa3e65f7640c373ad9d459dbbb771b --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,53 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.4.1) +project(XComponent) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +add_definitions(-DOHOS_PLATFORM) +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include + ) +add_library(nativerender SHARED + render/egl_core.cpp + render/plugin_render.cpp + manager/plugin_manager.cpp + napi_init.cpp + ) + +find_library( # Sets the name of the path variable. + EGL-lib + # Specifies the name of the NDK library that + # you want CMake to locate. + EGL ) + +find_library( # Sets the name of the path variable. + GLES-lib + # Specifies the name of the NDK library that + # you want CMake to locate. + GLESv3 ) + +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 ) + +find_library( # Sets the name of the path variable. + libace-lib + # Specifies the name of the NDK library that + # you want CMake to locate. + ace_ndk.z ) + +find_library( # Sets the name of the path variable. + libnapi-lib + # Specifies the name of the NDK library that + # you want CMake to locate. + ace_napi.z ) + +find_library( # Sets the name of the path variable. + libuv-lib + # Specifies the name of the NDK library that + # you want CMake to locate. + uv ) + +target_link_libraries(nativerender PUBLIC ${EGL-lib} ${GLES-lib} ${hilog-lib} ${libace-lib} ${libnapi-lib} ${libuv-lib} libc++.a) \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.cpp b/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38dce2583acccb41758ea0ededfcb14a956bded8 --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +#include +#include + +#include "plugin_manager.h" + + +enum ContextType { + APP_LIFECYCLE, + JS_PAGE_LIFECYCLE, +}; + +PluginManager PluginManager::manager_; + +napi_value PluginManager::getContext(napi_env env, napi_callback_info info) +{ + napi_status status; + napi_value exports; + size_t argc = 1; + napi_value args[1] = {nullptr}; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + if (argc != 1) { + napi_throw_type_error(env, NULL, "Wrong number of arguments"); + return nullptr; + } + + napi_valuetype valuetype; + status = napi_typeof(env, args[0], &valuetype); + + if (status != napi_ok) { + return nullptr; + } + + if (valuetype != napi_number) { + napi_throw_type_error(env, NULL, "Wrong type of arguments"); + return nullptr; + } + + int64_t value; + napi_get_value_int64(env, args[0], &value); + napi_create_object(env, &exports); + + switch (value) { + case APP_LIFECYCLE: { + /***** 应用 APP 生命周期注册 *****/ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "getContext: APP_LIFECYCLE"); + /***** Register App Lifecycle *****/ + napi_property_descriptor desc[] = { + { "onCreate", nullptr, PluginManager::NapiOnCreate, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "onShow", nullptr, PluginManager::NapiOnShow, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "onHide", nullptr, PluginManager::NapiOnHide, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "onDestroy", nullptr, PluginManager::NapiOnDestroy, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + } + break; + + case JS_PAGE_LIFECYCLE: { + /***** 声明式开发范式 JS Page 生命周期注册 *****/ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "getContext: JS_PAGE_LIFECYCLE"); + /***** Register JS Page Lifecycle *****/ + napi_property_descriptor desc[] = { + { "onPageShow", nullptr, PluginManager::NapiOnPageShow, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "onPageHide", nullptr, PluginManager::NapiOnPageHide, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + } + break; + + default: + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "PluginManager", "getContext: wrong type of arguments"); + } + return exports; +} + + +bool PluginManager::Export(napi_env env, napi_value exports) +{ + napi_status status; + napi_value exportInstance = nullptr; + OH_NativeXComponent *nativeXComponent = nullptr; + int32_t ret; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + + status = napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); + if (status != napi_ok) { + return false; + } + + status = napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)); + if (status != napi_ok) { + return false; + } + + ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); + if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + return false; + } + + std::string id(idStr); + auto context = PluginManager::GetInstance(); + if (context) { + context->setNativeXComponent(id, nativeXComponent); + auto render = context->GetRender(id); + OH_NativeXComponent_RegisterCallback(nativeXComponent, &PluginRender::callback_); + render->Export(env, exports); + return true; + } + return false; +} + + +void PluginManager::setNativeXComponent(std::string& id, OH_NativeXComponent* nativeXComponent) +{ + if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) { + nativeXComponentMap_[id] = nativeXComponent; + } else { + if (nativeXComponentMap_[id] != nativeXComponent) { + nativeXComponentMap_[id] = nativeXComponent; + } + } +} + + +PluginRender* PluginManager::GetRender(std::string& id) +{ + if (pluginRenderMap_.find(id) == pluginRenderMap_.end()) { + PluginRender* instance = PluginRender::getInstance(id); + pluginRenderMap_[id] = instance; + return instance; + } else { + return pluginRenderMap_[id]; + } +} + + +napi_value PluginManager::NapiOnCreate(napi_env env, napi_callback_info info) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "NapiOnCreate"); + // do something + return nullptr; +} + + +napi_value PluginManager::NapiOnShow(napi_env env, napi_callback_info info) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "NapiOnShow"); + // do something + return nullptr; +} + + +napi_value PluginManager::NapiOnHide(napi_env env, napi_callback_info info) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "NapiOnHide"); + // do something + return nullptr; +} + + +napi_value PluginManager::NapiOnDestroy(napi_env env, napi_callback_info info) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "NapiOnDestroy"); + // do something + return nullptr; +} + + +napi_value PluginManager::NapiOnPageShow(napi_env env, napi_callback_info info) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "NapiOnPageShow"); + // do something + return nullptr; +} + + +napi_value PluginManager::NapiOnPageHide(napi_env env, napi_callback_info info) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginManager", "NapiOnPageHide"); + // do something + return nullptr; +} + + diff --git a/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.h b/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..665269210082f93f749086ab6f6d06be3593551c --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef PLUGIN_MANAGER_H +#define PLUGIN_MANAGER_H + +#include +#include + +#include +#include +#include +#include +#include + +#include "../render/plugin_render.h" + + +class PluginManager { +public: + ~PluginManager() {} + + static PluginManager* GetInstance() + { + return &PluginManager::manager_; + } + + static napi_value getContext(napi_env env, napi_callback_info info); + + /******************************APP Lifecycle******************************/ + static napi_value NapiOnCreate(napi_env env, napi_callback_info info); + static napi_value NapiOnShow(napi_env env, napi_callback_info info); + static napi_value NapiOnHide(napi_env env, napi_callback_info info); + static napi_value NapiOnDestroy(napi_env env, napi_callback_info info); + /*********************************************************************/ + + /******************************声明式范式******************************/ + /** JS Page : Lifecycle **/ + static napi_value NapiOnPageShow(napi_env env, napi_callback_info info); + static napi_value NapiOnPageHide(napi_env env, napi_callback_info info); + /*************************************************************************/ + + void setNativeXComponent(std::string& id, OH_NativeXComponent* nativeXComponent); + PluginRender* GetRender(std::string& id); + +public: + bool Export(napi_env env, napi_value exports); + +private: + static PluginManager manager_; + + std::unordered_map nativeXComponentMap_; + std::unordered_map pluginRenderMap_; +}; + +#endif \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/cpp/napi_init.cpp b/NativeAPI/XComponent/entry/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e32cad1f9812de443c2547d60bdf7922b3f8ff0a --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/cpp/napi_init.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "manager/plugin_manager.h" + + +static napi_value Init(napi_env env, napi_value exports) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Init", "Init begins"); + napi_property_descriptor desc[] = { + { "getContext", nullptr, PluginManager::getContext, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + + bool ret = PluginManager::GetInstance()->Export(env, exports); + if (!ret) { + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Init", "Init failed"); + } + return exports; +} + + +static napi_module nativerenderModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "nativerender", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&nativerenderModule); +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.cpp b/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3eba653b0ab93b75eace8b9202ed6a5736226ca4 --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.cpp @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include +#include +#include +#include +#include + +#include "egl_core.h" +#include "plugin_render.h" + + +char vertexShader[] = +"#version 300 es\n" +"layout(location = 0) in vec4 a_position;\n" +"layout(location = 1) in vec4 a_color;\n" +"out vec4 v_color;\n" +"void main()\n" +"{\n" +" gl_Position = a_position;\n" +" v_color = a_color;\n" +"}\n"; + + +char fragmentShader[] = +"#version 300 es\n" +"precision mediump float;\n" +"in vec4 v_color;\n" +"out vec4 fragColor;\n" +"void main()\n" +"{\n" +" fragColor = v_color;\n" +"}\n"; + + +void EGLCore::eglContextInit(void* window, int w, int h) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "EGLCore", "eglContextInit ===> window = %{public}p, w = %{public}d, h = %{public}d", window, w, h); + width_ = w; + height_ = h; + mEglWindow = static_cast(window); + + // init + EGLint majorVersion; + EGLint minorVersion; + mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (mEglDisplay == EGL_NO_DISPLAY) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglGetDisplay ===> unable to get EGL display"); + return; + } + if (!eglInitialize(mEglDisplay, &majorVersion, &minorVersion)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglInitialize ===> unable to get initialize EGL display"); + return; + } + + // choose config + EGLint attribList[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + + const EGLint maxConfigs = 1; + EGLint numConfigs; + if (!eglChooseConfig(mEglDisplay, attribList, &mEglConfig, maxConfigs, &numConfigs)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglChooseConfig ===> unable to choose configs"); + return; + } + + // create surface + EGLint winAttribs[] = { + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, + EGL_NONE + }; + if (mEglWindow) { + mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mEglWindow, winAttribs); + if (mEglSurface == nullptr) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglCreateWindowSurface ===> unable to create surface"); + return; + } + } + + // create context + EGLint verList[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, verList); + if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "eglMakeCurrent ===> error = %{public}d", eglGetError()); + } + + // create program + mProgramHandle = createProgram(vertexShader, fragmentShader); + if (!mProgramHandle) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "createProgram ===> unable to create program"); + return; + } +} + + +void EGLCore::draw() +{ + GLfloat color[] = { + 0.5f, 0.6f, 0.3f, 1.0f + }; + + const GLfloat rectangleVertices[] = { + -0.5f, 0.5f, + 0.5f, 0.5f, + 0.5f, -0.5f, + -0.5f, -0.5f + }; + + glViewport(0, 0, width_, height_); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(mProgramHandle); + GLint positionHandle = glGetAttribLocation(mProgramHandle, "a_position"); + glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, rectangleVertices); + glEnableVertexAttribArray(positionHandle); + glVertexAttrib4fv(1, color); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableVertexAttribArray(positionHandle); + + glFlush(); + glFinish(); + eglSwapBuffers(mEglDisplay, mEglSurface); + flag = true; +} + + +void EGLCore::changeColor() +{ + if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "elgMakeCurrent ===> error = %{public}d", eglGetError()); + } + + GLfloat color[] = { + 0.9f, 0.5f, 0.7f, 1.0f + }; + + const GLfloat rectangleVertices[] = { + -0.5f, 0.5f, + 0.5f, 0.5f, + 0.5f, -0.5f, + -0.5f, -0.5f + }; + + glViewport(0, 0, width_, height_); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(mProgramHandle); + GLint positionHandle = glGetAttribLocation(mProgramHandle, "a_position"); + glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, rectangleVertices); + glEnableVertexAttribArray(positionHandle); + glVertexAttrib4fv(1, color); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableVertexAttribArray(positionHandle); + + if (flag) { + eglSwapBuffers(mEglDisplay, mEglSurface); + } +} + + +GLuint EGLCore::loadShader(GLenum type, const char *shaderSrc) +{ + GLuint shader; + GLint compiled; + + shader = glCreateShader(type); + if (shader == 0) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "glCreateShader ===> unable to load shader"); + return 0; + } + + glShaderSource(shader, 1, &shaderSrc, nullptr); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 1) { + char *infoLog = (char*)malloc(sizeof(char) * infoLen); + glGetShaderInfoLog(shader, infoLen, nullptr, infoLog); + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "glCompileShader ===> error = \n%s\n", infoLog); + free(infoLog); + } + glDeleteShader(shader); + return 0; + } + return shader; +} + + +GLuint EGLCore::createProgram(const char * vertexShader, const char * fragShader) +{ + GLuint vertex; + GLuint fragment; + GLuint program; + GLint linked; + + vertex = loadShader(GL_VERTEX_SHADER, vertexShader); + if (vertex == 0) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "createProgram ===> vertex error"); + return 0; + } + + fragment = loadShader(GL_FRAGMENT_SHADER, fragShader); + if (fragment == 0) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "createProgram ===> fragment error"); + glDeleteShader(vertex); + return 0; + } + + program = glCreateProgram(); + if (program == 0) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "createProgram ===> program error"); + glDeleteShader(vertex); + glDeleteShader(fragment); + return 0; + } + + glAttachShader(program, vertex); + glAttachShader(program, fragment); + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &linked); + if (!linked) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "createProgram ===> linked error"); + GLint infoLen = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen > 1) { + char *infoLog = (char *)malloc(sizeof(char) * infoLen); + glGetProgramInfoLog(program, infoLen, nullptr, infoLog); + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "EGLCore", "glLinkProgram ===> error = \n%s\n", infoLog); + free(infoLog); + } + glDeleteShader(vertex); + glDeleteShader(fragment); + glDeleteProgram(program); + return 0; + } + glDeleteShader(vertex); + glDeleteShader(fragment); + return program; +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.h b/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.h new file mode 100644 index 0000000000000000000000000000000000000000..9c379e4d9ea663e77eaafb8ae2320b8c66496aa7 --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 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 EGL_CORE_H +#define EGL_CORE_H + +#include + +#include +#include +#include + + +class EGLCore { +public: + explicit EGLCore(std::string& id) : id_(id) {}; + ~EGLCore() {} + void eglContextInit(void* window, int w, int h); + void draw(); + void changeColor(); + +public: + std::string id_; + int width_; + int height_; + +private: + GLuint loadShader(GLenum type, const char *shaderSrc); + GLuint createProgram(const char *vertexShader, const char *fragShader); + +private: + EGLNativeWindowType mEglWindow; + EGLDisplay mEglDisplay = EGL_NO_DISPLAY; + EGLConfig mEglConfig = EGL_NO_CONFIG_KHR; + EGLSurface mEglSurface = EGL_NO_SURFACE; + EGLContext mEglContext = EGL_NO_CONTEXT; + GLuint mProgramHandle; + bool flag = false; +}; + +#endif diff --git a/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.cpp b/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c964ec76723b05fdca7844151d802cf854c1c9a3 --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include +#include +#include + +#include "plugin_render.h" +#include "../manager/plugin_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +std::unordered_map PluginRender::instance_; +OH_NativeXComponent_Callback PluginRender::callback_; + + +void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Callback", "OnSurfaceCreatedCB"); + + int32_t xID; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + xID = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + + if (xID != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Callback", "OnSurfaceCreatedCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = PluginRender::getInstance(id); + int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &render->width_, &render->height_); + if (xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS && render) { + render->eglCore_->eglContextInit(window, render->width_, render->height_); + } +} + + +void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Callback", "OnSurfaceChangedCB"); + + int32_t xID; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + xID = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + + if (xID != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Callback", "OnSurfaceChangedCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = PluginRender::getInstance(id); + if (render) { + // do something + } +} + + +void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Callback", "OnSurfaceDestroyedCB"); + + int32_t xID; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + xID = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + + if (xID != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Callback", "OnSurfaceDestroyedCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = PluginRender::getInstance(id); + if (render) { + // do something + } +} + + +void DispatchTouchEventCB(OH_NativeXComponent* component, void* window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "Callback", "DispatchTouchEventCB"); + + int32_t xID; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + xID = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + + if (xID != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Callback", "DispatchTouchEventCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = PluginRender::getInstance(id); + if (render) { + render->eglCore_->changeColor(); + } +} + + +PluginRender::PluginRender(std::string& id) : id_(id) +{ + eglCore_ = new EGLCore(id); + auto renderCallback = &PluginRender::callback_; + renderCallback->OnSurfaceCreated = OnSurfaceCreatedCB; + renderCallback->OnSurfaceChanged = OnSurfaceChangedCB; + renderCallback->OnSurfaceDestroyed = OnSurfaceDestroyedCB; + renderCallback->DispatchTouchEvent = DispatchTouchEventCB; +} + + +PluginRender* PluginRender::getInstance(std::string& id) +{ + if (instance_.find(id) == instance_.end()) { + PluginRender* instance = new PluginRender(id); + instance_[id] = instance; + return instance; + } else { + return instance_[id]; + } +} + + +napi_value PluginRender::Export(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + { "drawTriangle", nullptr, PluginRender::NapiDrawRectangle, nullptr, nullptr, nullptr, napi_default, nullptr} + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} + + +napi_value PluginRender::NapiDrawRectangle(napi_env env, napi_callback_info info) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PluginRender", "NapiDrawRectangle"); + napi_value exportInstance; + napi_value thisArg; + napi_status status; + OH_NativeXComponent *nativeXComponent = nullptr; + + int32_t xID; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + + napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr); + + status = napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); + if (status != napi_ok) { + return nullptr; + }; + + status = napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)); + if (status != napi_ok) { + return nullptr; + } + + xID = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); + if (xID != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "PluginRender", "NapiDrawRectangle: Unable to get XComponent id"); + return nullptr; + } + + std::string id(idStr); + PluginRender* render = PluginRender::getInstance(id); + if (render) { + render->eglCore_->draw(); + } + return nullptr; +} + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.h b/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.h new file mode 100644 index 0000000000000000000000000000000000000000..32eaaef940def8fe52ba5cabaf4230f693631586 --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 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_RENDER_H +#define PLUGIN_RENDER_H + +#include +#include + +#include +#include + +#include "egl_core.h" + + +class PluginRender { +public: + explicit PluginRender(std::string& id); + ~PluginRender() {} + static PluginRender* getInstance(std::string& id); + +public: + napi_value Export(napi_env env, napi_value exports); + + // Exposed to JS developers by NAPI + static napi_value NapiDrawRectangle(napi_env env, napi_callback_info info); + +public: + static std::unordered_map instance_; + static OH_NativeXComponent_Callback callback_; + + EGLCore* eglCore_; + + std::string id_; + uint64_t width_; + uint64_t height_; + + double x_; + double y_; + OH_NativeXComponent_TouchEvent touchEvent_; +}; + +#endif diff --git a/NativeAPI/XComponent/entry/src/main/ets/Application/AbilityStage.ts b/NativeAPI/XComponent/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ceb0c290ae831a45143a5e2b42d4351f2fc3d7e --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 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 AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/ets/MainAbility/MainAbility.ts b/NativeAPI/XComponent/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3b9118990a732ecb5ee66ebad1395228ba3a85a --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 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 Ability from '@ohos.application.Ability' +import nativerender from "libnativerender.so"; + +export enum ContextType { + APP_LIFECYCLE, + JSPAGE_LIFECYCLE, +} + +const nativeAppLifecycle = nativerender.getContext(ContextType.APP_LIFECYCLE); + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + nativeAppLifecycle.onCreate(); + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + nativeAppLifecycle.onDestroy(); + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + nativeAppLifecycle.onShow(); + windowStage.setUIContent(this.context, "pages/index", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + nativeAppLifecycle.onHide(); + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/NativeAPI/XComponent/entry/src/main/ets/pages/index.ets b/NativeAPI/XComponent/entry/src/main/ets/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..a9d739b0ac7fd3d90058a84654af99743485e906 --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/ets/pages/index.ets @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 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 nativerender from "libnativerender.so"; +import { ContextType } from "../MainAbility/MainAbility" + +const nativePageLifecycle = nativerender.getContext(ContextType.JSPAGE_LIFECYCLE); + +@Entry +@Component +struct Index { + private context = null; + private aboutToAppear(): void { + console.log('[LIFECYCLE-Index] aboutToAppear'); + nativePageLifecycle.aboutToAppear(); + } + private aboutToDisappear(): void { + console.log('[LIFECYCLE-Index] aboutToDisappear'); + nativePageLifecycle.aboutToDisappear(); + } + + private onPageShow(): void { + console.log('[LIFECYCLE-Page] onPageShow'); + nativePageLifecycle.onPageShow(); + } + + private onPageHide(): void { + console.log('[LIFECYCLE-Page] onPageHide'); + nativePageLifecycle.onPageHide(); + } + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text('XComponent示例') + .fontSize(36) + .margin({bottom: 10}) + Button('绘制矩形') + .margin({ bottom: 10 }) + .onClick(() => { + if (this.context) { + this.context.drawTriangle(); + } + }) + Column() { + XComponent({ id: 'xcomponentId', type: 'texture', libraryname: 'nativerender'}) + .onLoad((context) => { + this.context = context; + }) + .onDestroy(() => { + }) + } + .width('80%') + .aspectRatio(1) + + } + .width('100%') + .height('100%') + } +} + diff --git a/NativeAPI/XComponent/entry/src/main/module.json5 b/NativeAPI/XComponent/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..035cdc75464278063f3d80f9fc859ac37d6b8b61 --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/module.json5 @@ -0,0 +1,37 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/resources/base/element/string.json b/NativeAPI/XComponent/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..b2abead79e769c2eb4db09f825bde7248bfdd6aa --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "label" + }, + { + "name": "MainAbility_desc", + "value": "description" + } + ] +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/resources/base/media/icon.png b/NativeAPI/XComponent/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NativeAPI/XComponent/entry/src/main/resources/base/media/icon.png differ diff --git a/NativeAPI/XComponent/entry/src/main/resources/base/profile/main_pages.json b/NativeAPI/XComponent/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..feec276e105eeb8d621c20aaf838f318b0a94150 --- /dev/null +++ b/NativeAPI/XComponent/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/index" + ] +} diff --git a/NativeAPI/XComponent/figures/1.jpg b/NativeAPI/XComponent/figures/1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b574c2834a96e407926293ac9a4801b9a209879e Binary files /dev/null and b/NativeAPI/XComponent/figures/1.jpg differ diff --git a/NativeAPI/XComponent/figures/2.jpg b/NativeAPI/XComponent/figures/2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cc716edbf848e7ed85b272633ea8d4bde9644776 Binary files /dev/null and b/NativeAPI/XComponent/figures/2.jpg differ diff --git a/NativeAPI/XComponent/figures/3.jpg b/NativeAPI/XComponent/figures/3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1d1908389ddb62f71cb95d91739e6ab056d965bd Binary files /dev/null and b/NativeAPI/XComponent/figures/3.jpg differ diff --git a/NativeAPI/XComponent/figures/zh-cn_image_0000001214154402.png b/NativeAPI/XComponent/figures/zh-cn_image_0000001214154402.png new file mode 100644 index 0000000000000000000000000000000000000000..9d752ff5311af2816bf898cb2c18ef33bf085726 Binary files /dev/null and b/NativeAPI/XComponent/figures/zh-cn_image_0000001214154402.png differ diff --git a/NativeAPI/XComponent/figures/zh-cn_image_0000001312007181.png b/NativeAPI/XComponent/figures/zh-cn_image_0000001312007181.png new file mode 100644 index 0000000000000000000000000000000000000000..c08320e3588e2cb620a1b41e9a497a563e8dfc01 Binary files /dev/null and b/NativeAPI/XComponent/figures/zh-cn_image_0000001312007181.png differ diff --git a/NativeAPI/XComponent/figures/zh-cn_image_0000001318156501.png b/NativeAPI/XComponent/figures/zh-cn_image_0000001318156501.png new file mode 100644 index 0000000000000000000000000000000000000000..7a659bfe60c57e2768d27a5896f58c5c3a93387a Binary files /dev/null and b/NativeAPI/XComponent/figures/zh-cn_image_0000001318156501.png differ diff --git a/NativeAPI/XComponent/hvigorfile.js b/NativeAPI/XComponent/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..5f2735e3deeaf655828407544bbed9365c258278 --- /dev/null +++ b/NativeAPI/XComponent/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/NativeAPI/XComponent/package.json b/NativeAPI/XComponent/package.json new file mode 100644 index 0000000000000000000000000000000000000000..4d0e61b6b8d1c47f913e8898eb23ed79181af341 --- /dev/null +++ b/NativeAPI/XComponent/package.json @@ -0,0 +1,18 @@ +{ + "license": "ISC", + "devDependencies": {}, + "name": "xcomponent", + "ohos": { + "org": "huawei", + "directoryLevel": "project", + "buildTool": "hvigor" + }, + "description": "example description", + "repository": {}, + "version": "1.0.0", + "dependencies": { + "@ohos/hvigor-ohos-plugin": "1.0.6", + "hypium": "^1.0.0", + "@ohos/hvigor": "1.0.6" + } +} diff --git a/NetworkManagement/SmartChatEtsOH/AppScope/app.json5 b/NetworkManagement/SmartChatEtsOH/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..369e1bcf91dd4140a3fa2ea036f83fafa7742756 --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/AppScope/app.json5 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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.example.smartchatetsoh", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true + } +} diff --git a/NetworkManagement/SmartChatEtsOH/AppScope/resources/base/element/string.json b/NetworkManagement/SmartChatEtsOH/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..3e581d9585c23a4a50fc09833ac42cc6649ca55c --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "SmartChatEtsOH" + } + ] +} diff --git a/NetworkManagement/SmartChatEtsOH/AppScope/resources/base/media/app_icon.png b/NetworkManagement/SmartChatEtsOH/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/AppScope/resources/base/media/app_icon.png differ diff --git a/NetworkManagement/SmartChatEtsOH/LICENSE b/NetworkManagement/SmartChatEtsOH/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..381eb507bc1eef9b5158e496dedab769e810b657 --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2022 Huawei Device Co., Ltd. All rights reserved. + + 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. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/README.md b/NetworkManagement/SmartChatEtsOH/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3ccc6714ee3d1149ef8296ccc6d3bfcbc9ef8ff9 --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/README.md @@ -0,0 +1,253 @@ +# 项目介绍 + +本篇Codelab使用基于HTTP协议和服务端建立连接,实现了一个和智能机器人进行通信对话的聊天案例。在这个案例中,客户端可以给服务端发送聊天信息,服务端接收到请求后会对客户端进行自动回复。案例效果如下所示: + +![](figures/20220520-153245(WeLinkPC).jpg) +# 搭建OpenHarmony环境 + +完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: + +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。 + + 以3.1版本为例: + + ![](figures/zh-cn_image_0000001306366081.png) + +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-standard-env-setup.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-standard-running-rk3568-burning.md) + +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E5%88%9B%E5%BB%BAets%E5%B7%A5%E7%A8%8B)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E4%BD%BF%E7%94%A8%E7%9C%9F%E6%9C%BA%E8%BF%90%E8%A1%8C%E5%BA%94%E7%94%A8)。 +# 数据请求API介绍 + + + + + + + + + + + + + + + + + + + + + + + + + +

方法

+

说明

+

creatHttp

+

创建一个HTTP网络请求,包括发起请求、中断请求、订阅/取消订阅HTTP Response Header 事件。

+

request

+

发送请求。

+

destroy

+

中断请求。

+

on(headerReceive)

+

订阅HTTP Response Header 事件。

+

off(headerReceive)

+

取消订阅HTTP Response Header 事件。

+

once(headerReceive)

+

订阅HTTP Response Header 事件,但只触发一次。

+
+ +>![](public_sys-resources/icon-note.gif) **说明:** +>相关API可以参考:[数据请求](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-http.md) +# 代码结构解读 +``` +├─AppScope # app全局目录 +│ └─resources +│ └─base +│ ├─element +│ └─media +└─entry # entry目录 + └─src + └─main + ├─ets # ets代码 + │ ├─Application + │ ├─MainAbility + │ └─pages + └─resources # 资源目录 + └─base + ├─element + ├─media + └─profile +``` + +- AppScope:App作用域目录。 +- entry/src/main/ets:程序目录。 + - Application:stage模型目录。 + - AbilityStage.ts:stage模型文件。 + + - MainAbility:程序入口目录。 + - MainAbility.ts:程序入口类。 + + - pages:存放应用页面。 + - ChatPage.ets:聊天界面。 + + +- entry/src/main/resources:资源文件目录。 +- module.json5:应用配置文件,包含网络权限配置。 +# 相关权限 + +本篇Codelab需要在module.json5中配置如下权限: + +``` +"reqPermissions": [ + { + "name": "ohos.permission.INTERNET" + } +] +``` +# 聊天界面实现 + +本节将介绍聊天界面布局的实现,效果图如下: + +![](figures/20220520-153245(WeLinkPC)-0.jpg) + +界面由三部分组成: + +1. 顶部的Text组件展示标题。 + + ``` + @Component + struct Title { + private title: string + build() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.title).fontSize(30).fontColor("#fdfdfd") + }.height(80).backgroundColor("#333534") + } + } + ``` + +2. 中间的Image组件展示用户头像;Text组件展示聊天内容。 + + ``` + // 左侧机器人头像和聊天信息 + @Component + struct LeftDialogBox { + private imageSrc: string + private chatMsg: string + build() { + Row() { + Image($rawfile(this.imageSrc)).width(80).height(80).margin({ left: 10, right: 10 }) + Text(this.chatMsg) + .fontSize(25) + .backgroundColor("#d7f6f3f3") + .padding(10) + .borderRadius(10) + } + .width('100%') + .padding({ top: 20, bottom: 20 , right: 280}) + .alignItems(VerticalAlign.Top) + } + } + // 右侧本人头像和聊天信息 + @Component + struct RightDialogBox { + private imageSrc: string + private chatMsg: string + build() { + Row() { + Image($rawfile(this.imageSrc)).width(80).height(80).margin({ left: 10, right: 10 }) + Text(this.chatMsg) + .fontSize(25) + .backgroundColor("#d7f6f3f3") + .padding(10) + .borderRadius(10) + } + .width('100%') + .padding({ top: 20, bottom: 20 , left: 280}) + .alignItems(VerticalAlign.Top) + .direction(Direction.Rtl) + } + } + ``` + +3. 底部左侧的TextInput组件用于输入聊天信息,底部右侧的Button组件发送聊天信息。 + + ``` + Row() { + TextInput({ placeholder: '', text: '' }) + .height(60) + .fontSize(30) + .margin(10) + .width('80%') + .onChange((value: string) => { + this.sendMsg = value + }) + Button("发送").height(50) + .width(100) + .margin(10) + .onClick(() => { + ... + }) + } + ``` +# 使用HTTP实现和服务端的通信 + +本节将介绍在聊天界面中,如何使用HTTP和服务端进行通信。 + +1. 导入http模块,创建HTTP请求,用于发起请求、中断请求、订阅/取消订阅HTTP Response Header 事件。 + + ``` + // 导入http模块 + import http from '@ohos.net.http'; + // 创建HTTP请求 + let httpRequest = http.createHttp(); + ``` + +2. 给“发送”按钮绑定点击事件,调用智能机器人API接口实现发送消息功能。 + + ``` + Button("发送").height(50) + .width(100) + .margin(10) + .onClick(() => { + let sendMsg = "http://******" + this.sendMsg // 用户可根据需要,选择合适的智能机器人聊天API进行测试 + this.sendMsg = "" + ... + // 发起HTTP网络请求 + httpRequest.request(sendMsg, + { + method: http.RequestMethod.GET, + header: { + 'Content-Type': 'application/json' + }, + readTimeout: 60000, + connectTimeout: 60000 + }, (err, data) => { + if (!err) { + console.info('httpRequest:' + data.result); + // 请求响应 + this.msgArr.push("1-" + JSON.parse(data.result) + .content) + this.scroller.scrollPage({ next: true }) + } else { + console.info('httpRequest:' + err.data); + } + }); + } + + ``` +# 总结与回顾 + +本篇Codelab介绍如何基于HTTP协议及相关API实现一个简单的智能聊天机器人案例。 +# 恭喜您 + +通过本篇Codelab的学习,您已经学会了: + +基于HTTP协议发起网络请求相关API的使用。 \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/build-profile.json5 b/NetworkManagement/SmartChatEtsOH/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b3d424906a475f28d1220bd4bd6c89ea8481fec5 --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/build-profile.json5 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 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": { + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/entry/build-profile.json5 b/NetworkManagement/SmartChatEtsOH/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..8d4191ee3893b90de4b15ff67cfce2e295b0609f --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/build-profile.json5 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 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": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/entry/hvigorfile.js b/NetworkManagement/SmartChatEtsOH/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..bd53638b93d5c2c3c96571a7c8431c3fee80569f --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/hvigorfile.js @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 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. + */ + +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/NetworkManagement/SmartChatEtsOH/entry/package.json b/NetworkManagement/SmartChatEtsOH/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..992c771b9e6be8904ce4204f075df58a9b0902cc --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/package.json @@ -0,0 +1,14 @@ +{ + "license":"ISC", + "devDependencies":{}, + "name":"entry", + "ohos":{ + "org":"huawei", + "directoryLevel":"module", + "buildTool":"hvigor" + }, + "description":"example description", + "repository":{}, + "version":"1.0.0", + "dependencies":{} +} \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/Application/AbilityStage.ts b/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..396606ff7396988f0849e54a294700ad86e22678 --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 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 AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/MainAbility/MainAbility.ts b/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..daa36ccf06f75d4caa8f885c7648b11e17ea89c9 --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 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 Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + + windowStage.setUIContent(this.context, "pages/ChatPage", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/pages/ChatPage.ets b/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/pages/ChatPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..dbda1a0b0579abfab523ef4c2a6e009b61d588d9 --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/src/main/ets/pages/ChatPage.ets @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2022 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. + */ + +// @ts-nocheck +import http from '@ohos.net.http'; +@Entry +@Component +struct Index { + @State msgArr: string[] = ['1-您好!这是使用基于TS扩展的类Web开发范式 实现的一个人工智能聊天窗口,有什么想和我聊的吗?', + ] + private sendMsg: string = "" + scroller: Scroller = new Scroller() + build() { + Column() { + Title({ title: "智能聊天机器人" }) + Scroll(this.scroller) { + Column() { + ForEach(this.msgArr, (item) => { + DialogBox({ chatMsg: item }) + }, item => item) + }.width('100%') + }.layoutWeight(1) + Divider().color(0xCCCCCC) + Row() { + TextInput({ placeholder: '', text: '' }) + .height(60) + .fontSize(30) + .margin(10) + .width('80%') + .onChange((value: string) => { + this.sendMsg = value + }) + Button("发送").height(50) + .width(100) + .margin(10) + .onClick(() => { + this.msgArr.push("2-" + this.sendMsg) + this.scroller.scrollPage({ next: true }) + let sendMsg = "http://******" + this.sendMsg // 用户可根据需要,选择合适的智能机器人聊天API进行测试 + this.sendMsg = "" + let httpRequest = http.createHttp(); + httpRequest.request(sendMsg, + { + method: http.RequestMethod.GET, + header: { + 'Content-Type': 'application/json' + }, + readTimeout: 60000, + connectTimeout: 60000 + }, (err, data) => { + if (!err) { + console.info('httpRequest:' + data.result); + this.msgArr.push("1-" + JSON.parse(data.result) + .content) + this.scroller.scrollPage({ next: true }) + } else { + console.info('httpRequest:' + err.data); + } + }); + }) + } + }.height("100%") + } +} +@Component +struct Title { + private title: string + + build() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.title).fontSize(30).fontColor("#fdfdfd") + }.height(80).backgroundColor("#333534") + } +} +@Component +struct DialogBox { + private chatMsg: string + + build() { + Row() { + if (this.chatMsg.search("1-") != -1) { + LeftDialogBox({ imageSrc: "person(0).jpg", chatMsg: this.chatMsg.replace("1-", "") }) + } else if (this.chatMsg.search("2-") != -1) { + RightDialogBox({ imageSrc: "person(1).png", chatMsg: this.chatMsg.replace("2-", "") }) + } + } + } +} + +@Component +struct LeftDialogBox { + private imageSrc: string + private chatMsg: string + + build() { + Row() { + Image($rawfile(this.imageSrc)).width(80).height(80).margin({ left: 10, right: 10 }) + Text(this.chatMsg) + .fontSize(25) + .backgroundColor("#d7f6f3f3") + .padding(10) + .borderRadius(10) + } + .width('100%') + .padding({ top: 20, bottom: 20 , right: 280}) + .alignItems(VerticalAlign.Top) + } +} + +@Component +struct RightDialogBox { + private imageSrc: string + private chatMsg: string + + build() { + Row() { + Image($rawfile(this.imageSrc)).width(80).height(80).margin({ left: 10, right: 10 }) + Text(this.chatMsg) + .fontSize(25) + .backgroundColor("#d7f6f3f3") + .padding(10) + .borderRadius(10) + } + .width('100%') + .padding({ top: 20, bottom: 20 , left: 280}) + .alignItems(VerticalAlign.Top) + .direction(Direction.Rtl) + } +} \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/module.json5 b/NetworkManagement/SmartChatEtsOH/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b63994ba3616b54b6412bae8263d00906e4f51cc --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/src/main/module.json5 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 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", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + } + ] + } +} \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/element/string.json b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..2f8637f1e67500f0f7993b0f32651fca2264cff2 --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "SmartChatEtsOH" + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/media/icon.png b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/media/icon.png differ diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/profile/main_pages.json b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..5617c006b243a0c9c207705e407d354cf987e75f --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/ChatPage" + ] +} diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/rawfile/person(0).jpg b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/rawfile/person(0).jpg new file mode 100644 index 0000000000000000000000000000000000000000..691627c258b99de1d23a8e7944cb456e54ba18db Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/rawfile/person(0).jpg differ diff --git a/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/rawfile/person(1).png b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/rawfile/person(1).png new file mode 100644 index 0000000000000000000000000000000000000000..9845aa73947912db1d943c83486d2ccefb9d3118 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/entry/src/main/resources/rawfile/person(1).png differ diff --git a/NetworkManagement/SmartChatEtsOH/figures/20220520-153245(WeLinkPC)-0.jpg b/NetworkManagement/SmartChatEtsOH/figures/20220520-153245(WeLinkPC)-0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac6934505f51bd95d53be05f1c7dd1114c523263 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/figures/20220520-153245(WeLinkPC)-0.jpg differ diff --git a/NetworkManagement/SmartChatEtsOH/figures/20220520-153245(WeLinkPC).jpg b/NetworkManagement/SmartChatEtsOH/figures/20220520-153245(WeLinkPC).jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac6934505f51bd95d53be05f1c7dd1114c523263 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/figures/20220520-153245(WeLinkPC).jpg differ diff --git a/NetworkManagement/SmartChatEtsOH/figures/zh-cn_image_0000001306366081.png b/NetworkManagement/SmartChatEtsOH/figures/zh-cn_image_0000001306366081.png new file mode 100644 index 0000000000000000000000000000000000000000..9d752ff5311af2816bf898cb2c18ef33bf085726 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/figures/zh-cn_image_0000001306366081.png differ diff --git a/NetworkManagement/SmartChatEtsOH/hvigorfile.js b/NetworkManagement/SmartChatEtsOH/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..0e173ec792d3d0be66b6a9a7b23fd525cad20f6f --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/hvigorfile.js @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 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. + */ + +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/NetworkManagement/SmartChatEtsOH/package.json b/NetworkManagement/SmartChatEtsOH/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8f92526f56ad064da3441c7252b61f172413513c --- /dev/null +++ b/NetworkManagement/SmartChatEtsOH/package.json @@ -0,0 +1,18 @@ +{ + "license": "ISC", + "devDependencies": {}, + "name": "smartchatetsoh", + "ohos": { + "org": "huawei", + "directoryLevel": "project", + "buildTool": "hvigor" + }, + "description": "example description", + "repository": {}, + "version": "1.0.0", + "dependencies": { + "@ohos/hvigor-ohos-plugin": "1.1.1-rc", + "hypium": "^1.0.0", + "@ohos/hvigor": "1.1.1-rc" + } +} diff --git a/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-caution.gif b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-caution.gif differ diff --git a/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-danger.gif b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-danger.gif differ diff --git a/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-note.gif b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-note.gif differ diff --git a/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-notice.gif b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-notice.gif differ diff --git a/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-tip.gif b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-tip.gif differ diff --git a/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-warning.gif b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/SmartChatEtsOH/public_sys-resources/icon-warning.gif differ diff --git a/NetworkManagement/TcpSocketDemo/AppScope/app.json5 b/NetworkManagement/TcpSocketDemo/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..af7380afc041d044d48931595adad130c271746b --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/AppScope/app.json5 @@ -0,0 +1,11 @@ +{ + "app": { + "bundleName": "com.huawei.myapplication", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true + } +} diff --git a/NetworkManagement/TcpSocketDemo/AppScope/resources/base/element/string.json b/NetworkManagement/TcpSocketDemo/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..98ee5f2517cd9c1de788a30107f173bbf3efef57 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "TcpSocketDemo" + } + ] +} diff --git a/NetworkManagement/TcpSocketDemo/AppScope/resources/base/media/app_icon.png b/NetworkManagement/TcpSocketDemo/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/AppScope/resources/base/media/app_icon.png differ diff --git a/NetworkManagement/TcpSocketDemo/LICENSE b/NetworkManagement/TcpSocketDemo/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..80576ef141485b36eea4aebf25af97020bc2de44 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved. + + 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. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/README.md b/NetworkManagement/TcpSocketDemo/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a3e8a5e0dce16b72b0a1b615237824886a285c7d --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/README.md @@ -0,0 +1,150 @@ +# 项目介绍 + +本篇Codelab基于TCP的Socket与服务端建立连接,实现了一个能和服务端进行通信对话的聊天案例。在这个案例中,客户端可以给服务端发送聊天信息,服务端也可以给客户端发送数据。案例效果如下所示: + +![](figures/zh-cn_image_0000001309522189.png)![](figures/zh-cn_image_0000001260963808.png) + +# 搭建OpenHarmony环境 + +完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**Hi3516DV300**开发板为例,参照以下步骤进行: + +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。 + + 以3.0版本为例: + + ![](figures/取版本.png) + +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-standard-env-setup.md) + 2. [完成Hi3516开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-steps-hi3516-burn.md) + +3. 搭建开发环境 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E5%88%9B%E5%BB%BAets%E5%B7%A5%E7%A8%8B)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E4%BD%BF%E7%94%A8%E7%9C%9F%E6%9C%BA%E8%BF%90%E8%A1%8C%E5%BA%94%E7%94%A8)。 + +# TCP相关API介绍 + + + + + + + + + + + + + + + + + + + + + + +

方法

+

说明

+

bind

+

绑定IP地址和端口

+

connect

+

连接到指定的IP地址和端口

+

send

+

通过TCPSocket连接发送数据

+

on('message')

+

订阅TCPSocket连接的接收消息事件

+

close

+

关闭TCPPSocket连接

+
+ +>![](public_sys-resources/icon-note.gif) **说明:** +>1、相关API可以参考:[TCPSocket连接](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-socket.md#tcpsocket) + +# 相关权限 + +基于TCP的Socket通信需要在module.json5中配置如下权限: + +``` +"reqPermissions": [ + { + "name": "ohos.permission.INTERNET" + } +] +``` +# 基于TCP的Socket与服务端的通信 + +基于TCP的Socket与服务端的通信,实现客户端和服务端的聊天。实现客户端相对来说比服务器要简单的多,因为其不需要监听,只需要连接发送数据即可。客户端实现主要分为: + +1. 调用TCPSocket的方法前,需要先通过socket.constructTCPSocketInstance创建TCPSocket对象。 + + ``` + let tcpSocket= socket.constructTCPSocketInstance(); + ``` + +2. 调用tcpSocket.bind\(\)绑定IP地址和端口。 + + ``` + tcpSocket.bind({address: '192.168.xx.xxx', port: xxxx, family: 1}, err => { + if (err) { + console.log('bind fail'); + return; + } + console.log('bind success'); + }) + ``` + +3. 调用tcpSocket.connect\(\)连接到指定的IP地址和端口 + + ``` + tcpSocket.connect({ address: {address: '192.168.xx.xxx', port: xxxx, family: 1} , timeout: 6000}, err => { + if (err) { + console.log('connect fail'); + return; + } + console.log('connect success'); + }) + ``` + +4. 调用tcpSocket.send\(\)发送数据。 + + ``` + let promise = tcpSocket.connect({ address: {address: '192.168.xx.xxx', port: xxxx, family: 1} , timeout: 6000}); + promise.then(() => { + console.log('connect success'); + tcp.send({ + data:'Hello, server!' + },err => { + if (err) { + console.log('send fail'); + return; + } + console.log('send success'); + }) + }).catch(err => { + console.log('connect fail'); + }); + ``` + +5. 调用tcpSocket.on\(\)订阅TCPSocket连接的接收消息。 + + ``` + tcpSocket.on('message', value => { + console.log("on message, message:" + value.message + ", remoteInfo:" + value.remoteInfo) + }); + ``` +# 总结和回顾 + +本篇Codelab介绍基于TCP的Scoket与服务端通信,讲解如何与服务端建立连接,发送信息给服务端,监听服务器返回信息。 + +# 恭喜您 + +通过本Codelab的学习,您已经学会了基于TCP的Socket通信。 + + + + + + diff --git a/NetworkManagement/TcpSocketDemo/build-profile.json5 b/NetworkManagement/TcpSocketDemo/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ee735436c35d78a2c7ce41fe89b14c48abc76fe2 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/build-profile.json5 @@ -0,0 +1,26 @@ +{ + "app": { + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default" + } + ], + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/build-profile.json5 b/NetworkManagement/TcpSocketDemo/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7dc37bb919dada5132609c409200db266559004f --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/build-profile.json5 @@ -0,0 +1,13 @@ +{ + "apiType": 'stageMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/hvigorfile.js b/NetworkManagement/TcpSocketDemo/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..d7720ee6a7aad5c617d1fd2f6fc8c87067bfa32c --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/NetworkManagement/TcpSocketDemo/entry/package.json b/NetworkManagement/TcpSocketDemo/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c7685ac4e7c0d79df04c96744f0d8f22cb4a9025 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/package.json @@ -0,0 +1,14 @@ +{ + "license": "ISC", + "devDependencies": {}, + "name": "entry", + "ohos": { + "org": "huawei", + "directoryLevel": "module", + "buildTool": "hvigor" + }, + "description": "example description", + "repository": {}, + "version": "1.0.0", + "dependencies": {} +} diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Application/AbilityStage.ts b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ceb0c290ae831a45143a5e2b42d4351f2fc3d7e --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 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 AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/ets/MainAbility/MainAbility.ts b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..6816feaa4dd44aadb5fa7e16b3252dbfd78cc410 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 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 Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + globalThis.abilityWant = want; + } + + onDestroy() { + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + windowStage.setUIContent(this.context, "Pages/LoginPage", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + } + + onForeground() { + // Ability has brought to foreground + } + + onBackground() { + // Ability has back to background + } +}; diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Model/ChatMsg.ts b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Model/ChatMsg.ts new file mode 100644 index 0000000000000000000000000000000000000000..bdebe54c3965a4c96446c351a3b7549f53378d42 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Model/ChatMsg.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 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 class ChatMsg{ + isSend: boolean + message: string + + constructor(isSend: boolean, message: string) { + this.isSend = isSend + this.message = message + } + + toString() { + return '{isSend:' + this.isSend + ',age:' + this.message + ',message:}' + } + +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Pages/ChatPage.ets b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Pages/ChatPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..b4ac77aec53fb014eee3d874689b1fd031c8e763 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Pages/ChatPage.ets @@ -0,0 +1,138 @@ +// @ts-nocheck +/* + * Copyright (c) 2022 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 router from '@ohos.router'; +import ChatMsg from '../Model/ChatMsg'; +const TAG = '[TcpDemo.index]' +import TcpClient from '../Socket/TcpClient'; + +@Entry +@Component +export struct ChatPage { + @State msgArr: ChatMsg[]= [] + private localIp: string = router.getParams().localIp + private oppositeIp: string = router.getParams().oppositeIp + private sendMsg: string = "" + private tcpClient: TcpClient = null; + private scroller: Scroller = new Scroller() + + onPageShow() { + console.info("oppositeIp :"+ this.oppositeIp +"localIp:"+this.localIp) + this.tcpClient = new TcpClient(this.oppositeIp,8080); + this.tcpClient.getTCPSocket(this.localIp,() => { + console.info("tcp bind success") + }) + this.tcpClient.setOnMessageReceivedListener((str) => { + console.log(`${TAG} udp on message array buffer:${str}`); + this.msgArr.push(new ChatMsg(false, str)) + this.scroller.scrollPage({ next: true }) + }) + } + + aboutToDisappear() { + this.tcpClient.closeTcp() + } + + build() { + Column() { + Title({ title: `对端ip:`+this.oppositeIp }) + Scroll(this.scroller) { + Column() { + ForEach(this.msgArr, (item) => { + if (item.isSend) { + RightMessageBox({ msgStr: item.message }) + } else { + LeftMessageBox({ msgStr: item.message }) + } + }, item => item.toString()) + }.width('100%') + }.layoutWeight(1) + .width("100%") + + Divider().color(0xCCCCCC) + + Row() { + TextInput({ placeholder: '', text: '' }) + .height(60) + .fontSize(30) + .width('70%') + .margin(10) + .onChange((value: string) => { + this.sendMsg = value + }) + + Button("发送") + .height(60) + .width(100) + .margin(10) + .fontSize(30) + .onClick(() => { + this.msgArr.push(new ChatMsg(true, this.sendMsg)) + this.scroller.scrollPage({ next: true }) + this.tcpClient.sendMag(this.sendMsg) + }) + } + }.height("100%") + .width("100%") + } +} + +@Component +struct Title { + private title: string + build() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.title).fontSize(30).fontColor("#fdfdfd") + }.height(80).backgroundColor("#333534") + } +} + +@Component +struct LeftMessageBox { + private msgStr: string + build() { + Row() { + Image($r("app.media.kang")).width(100).height(100).margin({ left: 10, right: 10 }) + Text(this.msgStr) + .fontSize(30) + .backgroundColor('#ff78dd4d') + .padding(15) + .borderRadius(10) + } + .width('100%') + .margin(20) + .alignItems(VerticalAlign.Center) + } +} + +@Component +struct RightMessageBox { + private msgStr: string + build() { + Row() { + Image($r("app.media.xiong")).width(100).height(100).margin({ left: 10, right: 10 }) + Text(this.msgStr) + .fontSize(30) + .backgroundColor('#ff78dd4d') + .padding(15) + .borderRadius(10) + } + .width('100%') + .margin(20) + .alignItems(VerticalAlign.Center) + .direction(Direction.Rtl) + } +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Pages/LoginPage.ets b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Pages/LoginPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..203777af8712a4f9b8b68eb50c93972e8cc69edf --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Pages/LoginPage.ets @@ -0,0 +1,106 @@ + +/* + * Copyright (c) 2022 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 wifi from '@ohos.wifi'; +import router from '@ohos.router'; +import prompt from '@system.prompt'; +import SocketUtil from '../Util/SocketUtil'; + +'../../ets/Pages/ChatPage' +@Entry +@Component +struct LoginPage { + @State userName: string = '请选择用户名' + @State oppositeIp: string = '' + @State localIp : string ='' + + private socketUtil: SocketUtil = new SocketUtil(wifi.getIpInfo().ipAddress) + + onPageShow(){ + this.localIp = this.socketUtil.resolveIP() + } + + checkInput() : any{ + if (this.oppositeIp === '') { + this.showMessage('对端ip不能为空') + return false + } + if (this.localIp === '' || this.localIp === '0.0.0.0') { + this.showMessage('请检查网络环境') + return false + } + return true + } + + showMessage(msg: string) { + prompt.showToast({ + message: msg + }) + } + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Row() { + Text('本地ip') + .fontSize(35) + .width('25%') + .fontWeight(FontWeight.Bold) + Text(this.localIp) + .fontSize(35) + }.width('80%') + + Row() { + Text('对端ip') + .fontSize(35) + .width('25%') + .fontWeight(FontWeight.Bold) + TextInput({ placeholder: '请输入对端ip' }) + .height(75) + .fontSize(35) + .maxLength(30) + .layoutWeight(1) + .placeholderFont({ size: 35 }) + .type(InputType.Number) + .onChange((value: string) => { + this.oppositeIp = value + }) + }.height(75) + .margin({ top: 45 }) + .width('80%') + + Text('确定') + .height(75) + .textAlign(TextAlign.Center) + .fontColor(Color.White) + .borderRadius(20) + .fontSize(35) + .width('80%') + .margin({ top: 45 }) + .backgroundColor(0x1890ff) + .onClick(() => { + if (!this.checkInput()) { + return + } + router.push({ + url: 'Pages/ChatPage', + params: { localIp: this.localIp, oppositeIp: this.oppositeIp} + }) + }) + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Socket/TcpClient.ts b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Socket/TcpClient.ts new file mode 100644 index 0000000000000000000000000000000000000000..c12e4173af17e1e4af858e813fcb43a000129f68 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Socket/TcpClient.ts @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 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 socket from '@ohos.net.socket'; + +export default class TcpClient{ + + private port: number = 8080 + private tcpSocket: any = null + private address: string + + constructor(address: string,port: number){ + this.address = address + this.port = port + } + + getTCPSocket(localIp:string,callback) { + console.info("tcp bind localIp:"+localIp) + if(this.tcpSocket != null) { + callback() + return + } + console.info("tcp bind next:") + this.tcpSocket = socket.constructTCPSocketInstance(); + console.info("tcp bind next next:") + this.tcpSocket.bind({ address: localIp, port: this.port, family: 1 },err=> { + if (!err) { + console.log('bind success'); + } + console.log('bind fail'); + }) + } + + sendMag(msg: string) { + this.tcpSocket.connect({ address: {address: this.address, port:this.port, family: 1} , timeout: 6000},err => { + if (!err) { + this.tcpSocket.send({ + data:msg + },err => { + if(err) { + console.info('send fail'); + return; + } + console.info('send success'); + }) + } + }); + } + + closeTcp() { + this.tcpSocket.close(err => { + if (!err) { + this.tcpSocket = null + return + } + }) + } + + setOnMessageReceivedListener(callback) { + this.tcpSocket.on("message", function (data) { + console.log("TCP data: " + JSON.stringify(data)) + let buffer = data.message + let dataView = new DataView(buffer) + console.log("TCP length " + dataView.byteLength) + let str = "" + for (let i = 0;i < dataView.byteLength; ++i) { + let c = String.fromCharCode(dataView.getUint8(i)) + if (c !== "\n") { + str += c + } + } + callback(str) + }) + } +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Util/SocketUtil.ts b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Util/SocketUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..93e340a2109b2567d66a1b14a5cf19aafc247832 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/ets/Util/SocketUtil.ts @@ -0,0 +1,31 @@ + +/* + * Copyright (c) 2022 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. + */ +const TAG = '[TcpDemo.index]' + +export default class SocketUtil{ + private ip: any + constructor(localIp: any){ + this.ip = localIp + } + + resolveIP() : any{ + if (this.ip < 0 || this.ip > 0xFFFFFFFF) { + throw (`${TAG} The number is not normal!`); + } + return (this.ip >>> 24) + "." + (this.ip >> 16 & 0xFF) + "." + (this.ip >> 8 & 0xFF) + "." + (this.ip & 0xFF); + } + +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/module.json5 b/NetworkManagement/TcpSocketDemo/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3622810c3cd2cc5a250dc2d51d12b73c09d07cc4 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/module.json5 @@ -0,0 +1,45 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + }, + { + "name": "ohos.permission.GET_WIFI_INFO" + } + ] + } +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/element/string.json b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..490210a3908f47722dc942d49dacc98b97669a5f --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/icon.png b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/icon.png differ diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/kang.png b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/kang.png new file mode 100644 index 0000000000000000000000000000000000000000..b56fa5b01e4d1293786346edb50d8bedd5b585f9 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/kang.png differ diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/xiong.png b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/xiong.png new file mode 100644 index 0000000000000000000000000000000000000000..53e2d81b0bbe58cebf8eea9a4000515db4ae1dc4 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/media/xiong.png differ diff --git a/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/profile/main_pages.json b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..4915e7471deec805cc468b407026406a16a0b097 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,6 @@ +{ + "src": [ + "Pages/LoginPage", + "Pages/ChatPage" + ] +} diff --git a/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001260963808.png b/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001260963808.png new file mode 100644 index 0000000000000000000000000000000000000000..5a6c58464d23c5e624a30cfa01024310fb3f1305 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001260963808.png differ diff --git a/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001263545622.png b/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001263545622.png new file mode 100644 index 0000000000000000000000000000000000000000..325530a77c65bf87e4ae0abb699cf64717fa52b7 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001263545622.png differ diff --git a/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001309522189.png b/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001309522189.png new file mode 100644 index 0000000000000000000000000000000000000000..9e3115f48f6cf82c5a03600f188546895c714ed1 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/figures/zh-cn_image_0000001309522189.png differ diff --git "a/NetworkManagement/TcpSocketDemo/figures/\345\217\226\347\211\210\346\234\254.png" "b/NetworkManagement/TcpSocketDemo/figures/\345\217\226\347\211\210\346\234\254.png" new file mode 100644 index 0000000000000000000000000000000000000000..9a4203fdba7d630c4d6cf0b60685f27afd85d28a Binary files /dev/null and "b/NetworkManagement/TcpSocketDemo/figures/\345\217\226\347\211\210\346\234\254.png" differ diff --git a/NetworkManagement/TcpSocketDemo/hvigorfile.js b/NetworkManagement/TcpSocketDemo/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..5f2735e3deeaf655828407544bbed9365c258278 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/NetworkManagement/TcpSocketDemo/package.json b/NetworkManagement/TcpSocketDemo/package.json new file mode 100644 index 0000000000000000000000000000000000000000..42b52fd9c03f6a9b18f00a80b323ded94b1bbfe3 --- /dev/null +++ b/NetworkManagement/TcpSocketDemo/package.json @@ -0,0 +1,18 @@ +{ + "license": "ISC", + "devDependencies": {}, + "name": "tcpsocketdemo", + "ohos": { + "org": "huawei", + "directoryLevel": "project", + "buildTool": "hvigor" + }, + "description": "example description", + "repository": {}, + "version": "1.0.0", + "dependencies": { + "@ohos/hvigor-ohos-plugin": "1.1.1-rc", + "hypium": "^1.0.0", + "@ohos/hvigor": "1.1.1-rc" + } +} diff --git a/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-caution.gif b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-caution.gif differ diff --git a/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-danger.gif b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-danger.gif differ diff --git a/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-note.gif b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-note.gif differ diff --git a/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-notice.gif b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-notice.gif differ diff --git a/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-tip.gif b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-tip.gif differ diff --git a/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-warning.gif b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/TcpSocketDemo/public_sys-resources/icon-warning.gif differ diff --git a/NetworkManagement/UdpDemoOH/AppScope/app.json5 b/NetworkManagement/UdpDemoOH/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..516d3cdeedff119268bd08b17ec93b2d017e9081 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/AppScope/app.json5 @@ -0,0 +1,11 @@ +{ + "app": { + "bundleName": "com.huawei.cookbook", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name", + "distributedNotificationEnabled": true + } +} diff --git a/NetworkManagement/UdpDemoOH/AppScope/resources/base/element/string.json b/NetworkManagement/UdpDemoOH/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..adf96aba106df079d87e8bf7a349213d42321a76 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "UdpDemoOH" + } + ] +} diff --git a/NetworkManagement/UdpDemoOH/AppScope/resources/base/media/app_icon.png b/NetworkManagement/UdpDemoOH/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NetworkManagement/UdpDemoOH/AppScope/resources/base/media/app_icon.png differ diff --git a/NetworkManagement/UdpDemoOH/LICENSE b/NetworkManagement/UdpDemoOH/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..80576ef141485b36eea4aebf25af97020bc2de44 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/LICENSE @@ -0,0 +1,78 @@ + Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved. + + 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. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/README.md b/NetworkManagement/UdpDemoOH/README.md new file mode 100644 index 0000000000000000000000000000000000000000..abb1a7bedca3aab9d78fb7fa5b643cf81de52049 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/README.md @@ -0,0 +1,473 @@ +# 使用UDP实现与服务端的通信 + +# 项目介绍 + +本篇Codelab使用基于UDP协议的socket和服务端建立连接,实现了一个能和服务端进行通信对话的聊天案例。在这个案例中,客户端可以给服务端发送聊天信息,服务端也可以给客户端发送数据。案例效果如下所示: + +![](figures/zh-cn_image_0000001262551948.png) ![](figures/zh-cn_image_0000001310072009.png) + +在客户端登录界面中输入服务端IP,点击“确定”按钮与服务端建立连接后,就可以进行通信了。 + +>![](public_sys-resources/icon-note.gif) **说明:** +>服务端可以是装有该案例程序的设备,也可以是装有能调试UDP协议的软件的设备。 + +基于UDP协议的socket和服务端通信的流程图如下: + +![](figures/zh-cn_image_0000001309297917.png) + +# 搭建OpenHarmony环境 + +完成本篇Codelab我们首先要完成开发环境的搭建,本示例以**RK3568**开发板为例,参照以下步骤进行: + +1. [获取OpenHarmony系统版本](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/get-code/sourcecode-acquire.md#%E8%8E%B7%E5%8F%96%E6%96%B9%E5%BC%8F3%E4%BB%8E%E9%95%9C%E5%83%8F%E7%AB%99%E7%82%B9%E8%8E%B7%E5%8F%96):标准系统解决方案(二进制)。 + + 以3.1版本为例: + + ![](figures/zh-cn_image_0000001214154402.png) + +2. 搭建烧录环境。 + 1. [完成DevEco Device Tool的安装](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-standard-env-setup.md) + 2. [完成RK3568开发板的烧录](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-ide-standard-running-rk3568-burning.md) + +3. 搭建开发环境。 + 1. 开始前请参考[工具准备](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-overview.md#%E5%B7%A5%E5%85%B7%E5%87%86%E5%A4%87),完成DevEco Studio的安装和开发环境配置。 + 2. 开发环境配置完成后,请参考[使用工程向导](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E5%88%9B%E5%BB%BAets%E5%B7%A5%E7%A8%8B)创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。 + 3. 工程创建完成后,选择使用[真机进行调测](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ets.md#%E4%BD%BF%E7%94%A8%E7%9C%9F%E6%9C%BA%E8%BF%90%E8%A1%8C%E5%BA%94%E7%94%A8)。 + + + +# UDP相关API介绍 + +UDP部分API如下: + + + + + + + + + + + + + + + + + + + +

方法

+

说明

+

bind

+

绑定IP地址和端口。

+

send

+

通过UDPSocket连接发送数据。

+

on('message')

+

订阅UDPSocket连接的接收消息事件。

+

close

+

关闭UDPSocket连接。

+
+ +>![](public_sys-resources/icon-note.gif) **说明:** +>相关API可以参考:[UDPSocket连接](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-socket.md#udpsocket) + + +# 代码结构解读 + +![](figures/zh-cn_image_0000001312109677.png) + +- AppScope:App作用域目录。 +- entry/src/main/ets:程序目录。 + - Application:stage模型目录。 + - AbilityStage.ts:stage模型文件。 + + - MainAbility:程序入口目录。 + - MainAbility.ts:程序入口类。 + + - Model:实体类目录。 + - ChatMsg.ets:用于封装聊天消息。 + + - pages:存放应用页面。 + - ChatPage.ets:聊天界面。 + - LoginPage.ets:登录界面。 + + - Utils:工具类目录。 + - SocketUtil.ts:用于封装解析IP地址的函数。 + - UdpClient.ts:用于封装UDP相关API。 + + +- entry/src/main/resources:资源文件目录。 +- module.json5:应用配置文件,包含网络权限配置。 + + +# 相关权限 + +基于UDP的socket通信需要在module.json5中配置如下权限: + +``` +"requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + }, + { + "name": "ohos.permission.GET_WIFI_INFO" + } +] +``` + +其中INTERNET权限用于使用网络socket,GET\_WIFI\_INFO权限用于获取WLAN信息(比如获取本机IP)。 +# 登录界面实现 + +登录界面主要功能是获取本机IP和服务端IP,这两个参数是UDP通信功能所需要的,下面将介绍登录界面布局和功能的实现。 + +1. 实现登录页面布局,主要代码如下: + + ``` + @Entry + @Component + struct Login { + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Row() { + Text('本地IP').fontSize(35).width('25%').fontWeight(FontWeight.Bold) + Text(localIp) + .fontSize(35) + }.width('80%') + + Row() { + Text('对端IP').fontSize(35).width('25%').fontWeight(FontWeight.Bold) + TextInput({ placeholder: '请输入对端IP' }) + ... + }.height(75) + + Text('确定') + .onClick(() => { + ... + }) + } + } + ``` + +2. 导入SocketUtil.ts文件中的resolveIP函数,获取本机IP地址。 + + ``` + import { resolveIP } from '../Utils/SocketUtil' + + let localIp = resolveIP(wifi.getIpInfo().ipAddress) + ``` + +3. 获取用户输入的服务端IP地址。 + + ``` + let oppositeIp = "" + + TextInput({ placeholder: '请输入对端IP' }) + ... + .onChange((value: string) => { + oppositeIp = value + }) + ``` + +4. 跳转到聊天界面,将本机IP和用户输入的服务端IP作为参数传递到ChatPage.ets。 + + ``` + Text('确定') + ... + .onClick(() => { + ... + router.push({ + url: 'pages/ChatPage', + params: { localIp: localIp, oppositeIp: oppositeIp} + }) + }) + ``` + + + +# 聊天界面实现 + +本节将介绍聊天界面布局的实现,效果图如下: + +![](figures/zh-cn_image_0000001310272077.png) + +从以上效果图可以看出,布局由标题栏、聊天消息列表和底部栏组成。 + +1. 标题栏用于显示对端IP地址,主要实现代码如下: + + ``` + @Component + struct Title { + private title: string + + build() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.title).fontSize(30).fontColor("#fdfdfd") + }.height(80).backgroundColor("#333534") + } + } + ``` + +2. 聊天消息列表用于显示聊天内容,右侧为己方发送的消息,左侧为对端发送的消息。主要实现代码如下: + + ``` + Scroll(this.scroller) { + Column() { + ForEach(this.msgArr, (item) => { + if (item.isSend) { + RightMessageBox({ msgStr: item.message }) + } else { + LeftMessageBox({ msgStr: item.message }) + } + }, item => item.id) + }.width('100%') + } + .layoutWeight(1) + .width("100%") + ``` + +3. 左侧消息组件LeftMessageBox 实现代码如下: + + ``` + @Component + struct LeftMessageBox { + private msgStr: string + + build() { + Row() { + Image($r("app.media.xiong")).width(100).height(100).margin({ left: 10, right: 10 }) + Text(this.msgStr) + .fontSize(30) + .backgroundColor('#22BE2C') + .padding(15) + .borderRadius(10) + } + .width('100%') + .padding({top:20,bottom:20,right:280}) + .alignItems(VerticalAlign.Center) + } + } + ``` + +4. 右侧消息组件RightMessageBox实现代码如下: + + ``` + @Component + struct RightMessageBox { + private msgStr: string + + build() { + Row() { + Image($r("app.media.kang")).width(100).height(100).margin({ left: 10, right: 10 }) + Text(this.msgStr) + .fontSize(30) + .backgroundColor('#FFF200') + .padding(15) + .borderRadius(10) + } + .width('100%') + .padding({top:20,bottom:20,left:280}) + .alignItems(VerticalAlign.Center) + .direction(Direction.Rtl) + } + } + ``` + +5. 底部栏用于输入和发送消息,主要实现代码如下: + + ``` + Row() { + TextInput({ placeholder: '', text: '' }) + .height(60) + .fontSize(30) + .width('70%') + .margin(10) + ... + + Button("发送") + .height(60) + .width(100) + .margin(10) + .fontSize(30) + ... + } + ``` + + + +# UdpClient类实现 + +将UDP相关API的实现封装到UdpClient类中,减少聊天界面代码冗余。UdpClient类主要功能有创建UDPSocket对象、绑定IP地址和端口、发送消息、订阅消息以及关闭UDPSocket连接等,实现步骤如下: + +1. 导入socket 模块,定义构造函数,在构造函数中使用constructUDPSocketInstance创建UDPSocket对象。 + + ``` + import socket from '@ohos.net.socket'; + + export default class UdpClient { + private localIp: string= '' + private oppositeIp: string= '' + private udp: any= null + + constructor(localIp: string, oppositeIp: string) { + this.localIp = localIp + this.oppositeIp = oppositeIp + this.udp = socket.constructUDPSocketInstance(); + } + } + ``` + +2. 定义bindUdp函数,绑定本机IP地址和端口,端口可以指定或由系统随机分配,这里为了方便演示指定客户端端口为9000。 + + ``` + bindUdp() { + let promise = this.udp.bind({ + address: this.localIp, port: 9000, family: 1 + }); + promise.then(() => { + console.log(`${TAG} udp bind success`); + }).catch(err => { + console.log(`${TAG} udp bind failed:${JSON.stringify(err)}`); + }); + } + ``` + +3. 定义函数sendMsg,用于发送消息,这里为了方便演示指定服务端端口为9000。 + + ``` + sendMsg(msg: string) { + let promise = this.udp.send({ + data: msg, + address: { + address: this.oppositeIp, + port: 9000, + family: 1 + } + }); + promise.then(() => { + console.log(`${TAG} udp send success:${msg}`); + }).catch(err => { + console.log(`${TAG} udp send fail:${JSON.stringify(err)}`); + }); + } + ``` + +4. 定义函数onMessage,用于订阅服务端消息。 + + ``` + onMessage(callback) { + this.udp.on('message', value => { + console.log(`${TAG} udp on message:${value.message}`); + // 收到的是ArrayBuffer 需要进行转换解析 + let dataView = new DataView(value.message) + console.log(`${TAG} udp message length:${dataView.byteLength}`); + let str = "" + for (let i = 0;i < dataView.byteLength; ++i) { + let c = String.fromCharCode(dataView.getUint8(i)) + if (c !== "\n") { + str += c + } + } + console.log(`${TAG} udp on message array buffer:${str}`); + callback(str) + }); + } + ``` + +5. 定义closeUdp函数,用于关闭UDPSocket连接。 + + ``` + closeUdp() { + let promise = this.udp.close(); + promise.then(() => { + console.log(`${TAG} udp close success`); + }).catch(err => { + console.log(`${TAG} udp close fail:${JSON.stringify(err)}`); + }); + } + ``` + + + +# 使用UDP实现和服务端通信 + +上一节完成了UdpClient类的封装,下面介绍在聊天界面中,如何使用UdpClient类和服务端进行通信。 + +1. 创建ChatMsg类用于封装发送和订阅的消息。 + + ``` + export default class ChatMsg { + isSend: boolean + message: string + id: string; + constructor(isSend: boolean, message: string) { + this.id = `${NextId++}`; + this.isSend = isSend + this.message = message + } + } + ``` + +2. 获取从登录界面传过来的对端IP和本机IP,定义消息数组。 + + ``` + import router from '@ohos.router'; + + @Entry + @Component + export struct ChatPage { + @State msgArr: ChatMsg[]= [] + private localIp: string = router.getParams().localIp + private oppositeIp: string = router.getParams().oppositeIp + } + ``` + +3. 在ChatPage.ets中导入UdpClient类,创建UdpClient对象,使用UdpClient对象调用bindUdp和onMessage函数。 + + ``` + import UdpClient from '../Utils/UdpClient'; + + onPageShow() { + this.udpClient = new UdpClient(this.localIp, this.oppositeIp) + this.udpClient.bindUdp() + this.udpClient.onMessage((msg) => { + this.msgArr.push(new ChatMsg(false, msg)) + }) + } + ``` + +4. 给“发送”按钮绑定点击事,使用UdpClient对象调用sendMsg函数实现发送消息功能 + + ``` + Button("发送") + ... + .onClick(() => { + this.msgArr.push(new ChatMsg(true, this.sendMsg)) + this.udpClient.sendMsg(this.sendMsg) + this.sendMsg = '' + }) + ``` + +5. 在aboutToDisappear中关闭UDPSocket连接。 + + ``` + aboutToDisappear() { + this.udpClient.closeUdp() + } + ``` + + + +# 总结和回顾 + +本篇Codelab介绍基于UDP协议的socket的相关API的使用,通过一个简单的聊天案例,向开发者讲解了如何使用UDP与服务端建立连接、发送信息给服务端以及订阅服务器返回信息。 + +通过本Codelab的学习,您已经学会了: + +- 基于UDP协议的socket相关API的使用 + + + + diff --git a/NetworkManagement/UdpDemoOH/build-profile.json5 b/NetworkManagement/UdpDemoOH/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d7b1117cdb34aab2983ac65026d9e8dcc91332d1 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/build-profile.json5 @@ -0,0 +1,27 @@ +{ + "app": { + "signingConfigs": [], + "compileSdkVersion": 9, + "compatibleSdkVersion": 9, + "products": [ + { + "name": "default", + "signingConfig": "default", + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/build-profile.json5 b/NetworkManagement/UdpDemoOH/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7dc37bb919dada5132609c409200db266559004f --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/build-profile.json5 @@ -0,0 +1,13 @@ +{ + "apiType": 'stageMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/hvigorfile.js b/NetworkManagement/UdpDemoOH/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..d7720ee6a7aad5c617d1fd2f6fc8c87067bfa32c --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks diff --git a/NetworkManagement/UdpDemoOH/entry/package.json b/NetworkManagement/UdpDemoOH/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c4e988f30f2ec9e3430a4d0c8f05e89fabbc2659 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/package.json @@ -0,0 +1,13 @@ +{ + "name": "entry", + "version": "1.0.0", + "ohos": { + "org": "huawei", + "buildTool": "hvigor", + "directoryLevel": "module" + }, + "description": "example description", + "repository": {}, + "license": "ISC", + "dependencies": {} +} diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/ets/Application/AbilityStage.ts b/NetworkManagement/UdpDemoOH/entry/src/main/ets/Application/AbilityStage.ts new file mode 100644 index 0000000000000000000000000000000000000000..32dfe93ccff0375201857794de902cec4d239442 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/ets/Application/AbilityStage.ts @@ -0,0 +1,7 @@ +import AbilityStage from "@ohos.application.AbilityStage" + +export default class MyAbilityStage extends AbilityStage { + onCreate() { + console.log("[Demo] MyAbilityStage onCreate") + } +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/ets/MainAbility/MainAbility.ts b/NetworkManagement/UdpDemoOH/entry/src/main/ets/MainAbility/MainAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..05fbb13c1f7df237a91067998cb301aba975c591 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/ets/MainAbility/MainAbility.ts @@ -0,0 +1,34 @@ +import Ability from '@ohos.application.Ability' + +export default class MainAbility extends Ability { + onCreate(want, launchParam) { + console.log("[Demo] MainAbility onCreate") + globalThis.abilityWant = want; + } + + onDestroy() { + console.log("[Demo] MainAbility onDestroy") + } + + onWindowStageCreate(windowStage) { + // Main window is created, set main page for this ability + console.log("[Demo] MainAbility onWindowStageCreate") + + windowStage.setUIContent(this.context, "pages/LoginPage", null) + } + + onWindowStageDestroy() { + // Main window is destroyed, release UI related resources + console.log("[Demo] MainAbility onWindowStageDestroy") + } + + onForeground() { + // Ability has brought to foreground + console.log("[Demo] MainAbility onForeground") + } + + onBackground() { + // Ability has back to background + console.log("[Demo] MainAbility onBackground") + } +}; diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/ets/Model/ChatMsg.ets b/NetworkManagement/UdpDemoOH/entry/src/main/ets/Model/ChatMsg.ets new file mode 100644 index 0000000000000000000000000000000000000000..2c7375a15d54296e2a12338f0d73e65cacb46388 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/ets/Model/ChatMsg.ets @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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. + */ +let NextId:number = 0; + +export default class ChatMsg { + isSend: boolean + message: string + id: string; + constructor(isSend: boolean, message: string) { + this.id = `${NextId++}`; + this.isSend = isSend + this.message = message + } +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/ets/Utils/SocketUtil.ts b/NetworkManagement/UdpDemoOH/entry/src/main/ets/Utils/SocketUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..253c34a4d88c3ca7e597411dfe540bbb7d68b4e6 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/ets/Utils/SocketUtil.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 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 function resolveIP(ip) { + if(ip < 0 || ip > 0xFFFFFFFF){ + throw ("The number is not normal!"); + } + return (ip>>>24) + "." + (ip>>16 & 0xFF) + "." + (ip>>8 & 0xFF) + "." + (ip & 0xFF); +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/ets/Utils/UdpClient.ts b/NetworkManagement/UdpDemoOH/entry/src/main/ets/Utils/UdpClient.ts new file mode 100644 index 0000000000000000000000000000000000000000..4396ed797a0883a7ffb5a4422c4d0fa6779e0cbf --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/ets/Utils/UdpClient.ts @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 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 socket from '@ohos.net.socket'; + +const TAG = '[UdpDemo.UdpClient]' + +export default class UdpClient { + private localIp: string= '' + private oppositeIp: string= '' + private udp: any= null + + constructor(localIp: string, oppositeIp: string) { + this.localIp = localIp + this.oppositeIp = oppositeIp + this.udp = socket.constructUDPSocketInstance(); + console.log(`${TAG} localIp is:${localIp}`); + console.log(`${TAG} oppositeIp is:${oppositeIp}`); + } + + bindUdp() { + let promise = this.udp.bind({ + address: this.localIp, port: 9000, family: 1 + }); + promise.then(() => { + console.log(`${TAG} udp bind success`); + }).catch(err => { + console.log(`${TAG} udp bind failed:${JSON.stringify(err)}`); + }); + } + + sendMsg(msg: string) { + let promise = this.udp.send({ + data: msg, + address: { + address: this.oppositeIp, + port: 9000, + family: 1 + } + }); + promise.then(() => { + console.log(`${TAG} udp send success:${msg}`); + }).catch(err => { + console.log(`${TAG} udp send fail:${JSON.stringify(err)}`); + }); + } + + onMessage(callback) { + this.udp.on('message', value => { + console.log(`${TAG} udp on message:${value.message}`); + // 收到的是ArrayBuffer 需要进行转换解析 + let dataView = new DataView(value.message) + console.log(`${TAG} udp message length:${dataView.byteLength}`); + let str = "" + for (let i = 0;i < dataView.byteLength; ++i) { + let c = String.fromCharCode(dataView.getUint8(i)) + if (c !== "\n") { + str += c + } + } + console.log(`${TAG} udp on message array buffer:${str}`); + callback(str) + }); + } + + closeUdp() { + let promise = this.udp.close(); + promise.then(() => { + console.log(`${TAG} udp close success`); + }).catch(err => { + console.log(`${TAG} udp close fail:${JSON.stringify(err)}`); + }); + } +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/ets/pages/ChatPage.ets b/NetworkManagement/UdpDemoOH/entry/src/main/ets/pages/ChatPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..d2bce43626f5bcfbf7d4967d775666ae1b71bbf3 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/ets/pages/ChatPage.ets @@ -0,0 +1,140 @@ +// @ts-nocheck +/* + * Copyright (c) 2022 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 router from '@ohos.router'; +import ChatMsg from '../Model/ChatMsg'; +import UdpClient from '../Utils/UdpClient'; + +@Entry +@Component +export struct ChatPage { + @State msgArr: ChatMsg[] = [] + private sendMsg: string = "" + private localIp: string = router.getParams().localIp + private oppositeIp: string = router.getParams().oppositeIp + private udpClient: UdpClient = null + scroller: Scroller = new Scroller() + + onPageShow() { + this.udpClient = new UdpClient(this.localIp, this.oppositeIp) + this.udpClient.bindUdp() + this.udpClient.onMessage((msg) => { + this.msgArr.push(new ChatMsg(false, msg)) + this.scroller.scrollPage({ next: true }) + }) + } + + aboutToDisappear() { + this.udpClient.closeUdp() + } + + build() { + Column() { + Title({ title: `对端ip:${this.oppositeIp}` }) + + Scroll(this.scroller) { + Column() { + ForEach(this.msgArr, (item) => { + if (item.isSend) { + RightMessageBox({ msgStr: item.message }) + } else { + LeftMessageBox({ msgStr: item.message }) + } + }, item => item.id) + }.width('100%') + }.layoutWeight(1) + .width("100%") + + Divider().color(0xCCCCCC) + + Row() { + TextInput({ placeholder: '', text: '' }) + .height(60) + .fontSize(30) + .width('70%') + .margin(10) + .onChange((value: string) => { + this.sendMsg = value + }) + + Button("发送") + .height(60) + .width(100) + .margin(10) + .fontSize(30) + .onClick(() => { + if (this.sendMsg != '') { + this.msgArr.push(new ChatMsg(true, this.sendMsg)) + this.scroller.scrollPage({ next: true }) + this.udpClient.sendMsg(this.sendMsg) + this.sendMsg = '' + } + }) + } + }.height("100%") + .width("100%") + } +} + +@Component +struct Title { + private title: string + + build() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.title).fontSize(30).fontColor("#fdfdfd") + }.height(80).backgroundColor("#333534") + } +} + +@Component +struct LeftMessageBox { + private msgStr: string + + build() { + Row() { + Image($r("app.media.xiong")).width(100).height(100).margin({ left: 10, right: 10 }) + Text(this.msgStr) + .fontSize(30) + .backgroundColor('#22BE2C') + .padding(15) + .borderRadius(10) + } + .width('100%') + .padding({ top: 20, bottom: 20, right: 280 }) + .alignItems(VerticalAlign.Center) + } +} + +@Component +struct RightMessageBox { + private msgStr: string + + build() { + Row() { + Image($r("app.media.kang")).width(100).height(100).margin({ left: 10, right: 10 }) + Text(this.msgStr) + .fontSize(30) + .backgroundColor('#FFF200') + .padding(15) + .borderRadius(10) + } + .width('100%') + .padding({ top: 20, bottom: 20, left: 280 }) + .alignItems(VerticalAlign.Center) + .direction(Direction.Rtl) + } +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/ets/pages/LoginPage.ets b/NetworkManagement/UdpDemoOH/entry/src/main/ets/pages/LoginPage.ets new file mode 100644 index 0000000000000000000000000000000000000000..7eeeea103f5b66bcb351db803d0e7af12cfc44a1 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/ets/pages/LoginPage.ets @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022 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 wifi from '@ohos.wifi'; +import router from '@ohos.router'; +import prompt from '@system.prompt'; +import { resolveIP } from '../Utils/SocketUtil' + +let localIp = resolveIP(wifi.getIpInfo().ipAddress) +let oppositeIp = "" + +@Entry +@Component +struct Login { + + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Row() { + Text('本地IP').fontSize(35).width('25%').fontWeight(FontWeight.Bold) + + Text(localIp) + .fontSize(35) + }.width('80%') + + Row() { + Text('对端IP').fontSize(35).width('25%').fontWeight(FontWeight.Bold) + + TextInput({ placeholder: '请输入对端IP' }) + .height(75) + .fontSize(35) + .maxLength(30) + .layoutWeight(1) + .placeholderFont({ size: 35 }) + .type(InputType.Number) + .onChange((value: string) => { + oppositeIp = value + }) + }.height(75) + .margin({ top: 45 }) + .width('80%') + + + Text('确定') + .height(75) + .textAlign(TextAlign.Center) + .fontColor(Color.White) + .borderRadius(20) + .fontSize(35) + .width('80%') + .margin({ top: 45 }) + .backgroundColor('#1890ff') + .onClick(() => { + if (oppositeIp === '') { + prompt.showToast({ + message: '对端ip不能为空' + }) + return + } + + if (localIp === '' || localIp === '0.0.0.0') { + prompt.showToast({ + message: '请检查网络环境' + }) + return + } + + router.push({ + url: 'pages/ChatPage', + params: { localIp: localIp, oppositeIp: oppositeIp} + }) + }) + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/module.json5 b/NetworkManagement/UdpDemoOH/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3622810c3cd2cc5a250dc2d51d12b73c09d07cc4 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/module.json5 @@ -0,0 +1,45 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "srcEntrance": "./ets/Application/AbilityStage.ts", + "description": "$string:entry_desc", + "mainElement": "MainAbility", + "deviceTypes": [ + "phone", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "uiSyntax": "ets", + "abilities": [ + { + "name": "MainAbility", + "srcEntrance": "./ets/MainAbility/MainAbility.ts", + "description": "$string:MainAbility_desc", + "icon": "$media:icon", + "label": "$string:MainAbility_label", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + }, + { + "name": "ohos.permission.GET_WIFI_INFO" + } + ] + } +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/element/string.json b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..490210a3908f47722dc942d49dacc98b97669a5f --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/icon.png b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/icon.png differ diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/kang.png b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/kang.png new file mode 100644 index 0000000000000000000000000000000000000000..b56fa5b01e4d1293786346edb50d8bedd5b585f9 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/kang.png differ diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/xiong.png b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/xiong.png new file mode 100644 index 0000000000000000000000000000000000000000..53e2d81b0bbe58cebf8eea9a4000515db4ae1dc4 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/media/xiong.png differ diff --git a/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/profile/main_pages.json b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..80faf2031dcc54f4bd34fb8c06893ddf591fac18 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,6 @@ +{ + "src": [ + "pages/LoginPage", + "pages/ChatPage" + ] +} \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001214154402.png b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001214154402.png new file mode 100644 index 0000000000000000000000000000000000000000..9d752ff5311af2816bf898cb2c18ef33bf085726 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001214154402.png differ diff --git a/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001262551948.png b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001262551948.png new file mode 100644 index 0000000000000000000000000000000000000000..96e8995665e8cdf85a03386e5cc1f7f80350938f Binary files /dev/null and b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001262551948.png differ diff --git a/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001309297917.png b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001309297917.png new file mode 100644 index 0000000000000000000000000000000000000000..c783cd0de761ad9379acd92915a6ba670595c2ad Binary files /dev/null and b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001309297917.png differ diff --git a/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001310072009.png b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001310072009.png new file mode 100644 index 0000000000000000000000000000000000000000..b12d239e3340c33a642fd398329a0e806147ac0b Binary files /dev/null and b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001310072009.png differ diff --git a/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001310272077.png b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001310272077.png new file mode 100644 index 0000000000000000000000000000000000000000..b12d239e3340c33a642fd398329a0e806147ac0b Binary files /dev/null and b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001310272077.png differ diff --git a/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001312109677.png b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001312109677.png new file mode 100644 index 0000000000000000000000000000000000000000..a97e65c57ee28cb60caf244ee730eeab4cceb2d0 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/figures/zh-cn_image_0000001312109677.png differ diff --git a/NetworkManagement/UdpDemoOH/hvigorfile.js b/NetworkManagement/UdpDemoOH/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..5f2735e3deeaf655828407544bbed9365c258278 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').appTasks \ No newline at end of file diff --git a/NetworkManagement/UdpDemoOH/package.json b/NetworkManagement/UdpDemoOH/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3733bdca7a387fb73789d49704f51b2d52e07152 --- /dev/null +++ b/NetworkManagement/UdpDemoOH/package.json @@ -0,0 +1,17 @@ +{ + "name": "udpdemooh", + "version": "1.0.0", + "ohos": { + "org": "huawei", + "buildTool": "hvigor", + "directoryLevel": "project" + }, + "description": "example description", + "repository": {}, + "license": "ISC", + "dependencies": { + "hypium": "^1.0.0", + "@ohos/hvigor": "1.1.1-rc", + "@ohos/hvigor-ohos-plugin": "1.1.1-rc" + } +} diff --git a/NetworkManagement/UdpDemoOH/public_sys-resources/icon-caution.gif b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-caution.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-caution.gif differ diff --git a/NetworkManagement/UdpDemoOH/public_sys-resources/icon-danger.gif b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-danger.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-danger.gif differ diff --git a/NetworkManagement/UdpDemoOH/public_sys-resources/icon-note.gif b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-note.gif new file mode 100644 index 0000000000000000000000000000000000000000..6314297e45c1de184204098efd4814d6dc8b1cda Binary files /dev/null and b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-note.gif differ diff --git a/NetworkManagement/UdpDemoOH/public_sys-resources/icon-notice.gif b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-notice.gif new file mode 100644 index 0000000000000000000000000000000000000000..86024f61b691400bea99e5b1f506d9d9aef36e27 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-notice.gif differ diff --git a/NetworkManagement/UdpDemoOH/public_sys-resources/icon-tip.gif b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-tip.gif new file mode 100644 index 0000000000000000000000000000000000000000..93aa72053b510e456b149f36a0972703ea9999b7 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-tip.gif differ diff --git a/NetworkManagement/UdpDemoOH/public_sys-resources/icon-warning.gif b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..6e90d7cfc2193e39e10bb58c38d01a23f045d571 Binary files /dev/null and b/NetworkManagement/UdpDemoOH/public_sys-resources/icon-warning.gif differ diff --git a/README.md b/README.md index 2ffb2c3e219656808efa4daba84411d007050c52..ac5b619e1def247cec9fcd48d7a1fff1276c2208 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,5 @@ # OpenHarmony Codelabs -- [概要简介](#section117915431558) -- [目录](#sectionMenu) -- [使用说明](#section1954919258619) -- [约束与限制](#section682025019613) -- [相关仓](#section01752910717) - ## 概要简介 为帮助开发者快速熟悉OpenHarmony的能力以及相关的应用开发流程,我们提供了一系列的基于趣味场景的应用示例,即Codelabs,开发者可以根据我们的文档一步步的学习和完成简单项目的开发。 @@ -13,7 +7,8 @@ ## 目录 - Ability - - [Page内和Page间导航跳转](https://gitee.com/openharmony/codelabs/tree/master/Ability/PageAbility)(API8+) + - [Page内和Page间导航跳转(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Ability/PageAbility)(API8+) + - [为应用添加运行时权限(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Ability/AccessPermission)(API9+) - ArkUI - [极简声明式UI范式(eTS)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/SimpleGalleryEts)(API8+) - [购物应用(eTS)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/ShoppingEts)(API8+) @@ -31,24 +26,31 @@ - [流式布局(eTS)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/FlowLayoutEts)(API8+) - [弹窗(eTS)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/CustomDialogEts)(API8+) - [一次开发多端部署(eTS)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/MultiDeploymentEts)(API8+) + - [Web组件加载本地H5小程序(eTS)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/WebComponent)(API9+) + - [像素转换(eTS)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/PixelUnitsDemo)(API9+) - 分布式 - - [分布式调度启动远程FA](https://gitee.com/openharmony/codelabs/tree/master/Distributed/RemoteStartFA)(API8+) - - [分布式新闻客户端](https://gitee.com/openharmony/codelabs/tree/master/Distributed/NewsDemo)(API8+) + - [分布式调度启动远程FA(JS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/RemoteStartFA)(API8+) + - [分布式新闻客户端(JS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/NewsDemo)(API8+) - [分布式手写板(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/DistributeDatabaseDrawEts)(API8+) - [分布式鉴权(JS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/GameAuthOpenH)(API8+) - [分布式游戏手柄(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/HandleGameApplication)(API8+) - [分布式邮件(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/OHMailETS)(API8+) - [分布式亲子早教系统(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/OpenHarmonyPictureGame)(API8+) - [分布式遥控器(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Distributed/RemoteControllerETS)(API8+) +- 公共事件与通知 + - [闹钟应用(eTS)](https://gitee.com/openharmony/codelabs/tree/master/CommonEventAndNotification/AlarmClock)(API9+) - 媒体 - - [图片编辑模板](https://gitee.com/openharmony/codelabs/tree/master/Media/ImageEditorTemplate)(API8+) - - [图片常见操作](https://gitee.com/openharmony/codelabs/tree/master/Media/ImageJsDemo)(API8+) - - [简易视频播放器](https://gitee.com/openharmony/codelabs/tree/master/Media/VideoOpenHarmony)(API8+) - - [音频播放器](https://gitee.com/openharmony/codelabs/tree/master/Media/Audio_OH_ETS)(API9+) + - [图片编辑模板(JS)](https://gitee.com/openharmony/codelabs/tree/master/Media/ImageEditorTemplate)(API8+) + - [图片常见操作(JS)](https://gitee.com/openharmony/codelabs/tree/master/Media/ImageJsDemo)(API8+) + - [简易视频播放器(JS)](https://gitee.com/openharmony/codelabs/tree/master/Media/VideoOpenHarmony)(API8+) + - [音频播放器(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Media/Audio_OH_ETS)(API9+) +- NativeAPI + - [第一个Native C++应用(eTS)](https://gitee.com/openharmony/codelabs/tree/master/NativeAPI/NativeTemplateDemo)(API9+) + - [Native Component(eTS)](https://gitee.com/openharmony/codelabs/tree/master/NativeAPI/XComponent)(API9+) - 数据库 - - [分布式数据库](https://gitee.com/openharmony/codelabs/tree/master/Data/JsDistributedData)(API8+) - - [关系型数据库](https://gitee.com/openharmony/codelabs/tree/master/Data/JSRelationshipData)(API8+) - - [轻量级偏好数据库](https://gitee.com/openharmony/codelabs/tree/master/Data/Database)(API8+) + - [分布式数据库(JS)](https://gitee.com/openharmony/codelabs/tree/master/Data/JsDistributedData)(API8+) + - [关系型数据库(JS)](https://gitee.com/openharmony/codelabs/tree/master/Data/JSRelationshipData)(API8+) + - [轻量级偏好数据库(JS)](https://gitee.com/openharmony/codelabs/tree/master/Data/Database)(API8+) - [备忘录(eTS)](https://gitee.com/openharmony/codelabs/tree/master/Data/NotePad_OH_ETS)(API8+) - 设备开发 - [轻量系统环境搭建指导](https://gitee.com/openharmony/codelabs/tree/master/Device/DeviceEnvironmentSetupGuide)(指导文档) @@ -59,8 +61,14 @@ - [智能猫眼](https://gitee.com/openharmony/codelabs/tree/master/Device/smart_cat_eye)(开发板类型:Hi3516DV300,OpenHarmony系统:OpenHarmony 3.0.2 LTS) - [OpenHarmony最小系统移植](https://gitee.com/openharmony/codelabs/tree/master/Device/PortingOpenHarmony)(开发板类型:RK3568,OpenHarmony系统:Rk3568 3.1 Release) - [HDF驱动模型Wi-Fi驱动](https://gitee.com/openharmony/codelabs/tree/master/Device/WifiDemo)(开发板类型:Hi3516DV300,OpenHarmony系统:OpenHarmony 3.1 Release) + - [OLED屏幕显示](https://gitee.com/openharmony/codelabs/tree/master/Device/OLED%E5%B1%8F%E5%B9%95%E7%9A%84%E6%98%BE%E7%A4%BA)(开发板类型:Hi3861,OpenHarmony系统:OpenHarmony 3.0 LTS) + - [智能门禁](https://gitee.com/openharmony/codelabs/tree/master/Device/smart_door_access)(开发板类型:RK3568,OpenHarmony系统:OpenHarmony 3.0.2 LTS) - 三方库 - - [VCard](https://gitee.com/openharmony/codelabs/tree/master/ThirdPartyComponents/VCardDemo)(API8+) + - [VCard(eTS)](https://gitee.com/openharmony/codelabs/tree/master/ThirdPartyComponents/VCardDemo)(API8+) +- 网络管理 + - [使用UDP实现与服务端通信(eTS)](https://gitee.com/openharmony/codelabs/tree/master/NetworkManagement/UdpDemoOH)(API9+) + - [使用HTTP实现与服务端通信(eTS)](https://gitee.com/openharmony/codelabs/tree/master/NetworkManagement/SmartChatEtsOH)(API9+) + - [使用TCP实现与服务端通信(eTS)](https://gitee.com/openharmony/codelabs/tree/master/NetworkManagement/TcpSocketDemo)(API9+) ## 使用说明