From 1fd501f0be312c895b0243c05aa0129ab08ea555 Mon Sep 17 00:00:00 2001 From: knpingan Date: Fri, 11 Mar 2022 19:10:03 +0800 Subject: [PATCH] connected tag service for communication. Signed-off-by: knpingan --- LICENSE | 177 ++++++++++ OAT.xml | 30 ++ README.md | 68 ++-- README_zh.md | 64 ++++ bundle.json | 81 +++++ figures/en-us_image_0000001086731550.gif | Bin 0 -> 80363 bytes figures/zh-cn_image_0000001124327253.png | Bin 0 -> 52496 bytes .../native_cpp/connected_tag_base/BUILD.gn | 56 ++++ .../include/connected_tag_callback_stub.h | 46 +++ .../include/connected_tag_impl.h | 48 +++ .../include/iconnected_tag.h | 42 +++ .../include/iconnected_tag_callback.h | 29 ++ .../connected_tag_base/include/log.h | 83 +++++ .../include/tag_session_proxy.h | 51 +++ .../interfaces/error_code.h | 29 ++ .../interfaces/i_tag_session.h | 38 +++ .../connected_tag_base/interfaces/ipc_cmd.h | 29 ++ .../src/connected_tag_callback_stub.cpp | 91 ++++++ .../src/connected_tag_impl.cpp | 80 +++++ .../src/tag_session_proxy.cpp | 149 +++++++++ .../native_cpp/napi/connected_tag/BUILD.gn | 50 +++ .../napi/connected_tag/nfc_napi_adapter.cpp | 108 ++++++ .../napi/connected_tag/nfc_napi_adapter.h | 50 +++ .../napi/connected_tag/nfc_napi_entry.cpp | 57 ++++ .../napi/connected_tag/nfc_napi_event.cpp | 289 ++++++++++++++++ .../napi/connected_tag/nfc_napi_event.h | 117 +++++++ .../napi/connected_tag/nfc_napi_utils.cpp | 308 ++++++++++++++++++ .../napi/connected_tag/nfc_napi_utils.h | 99 ++++++ sa_profile/connected_tag/1140.xml | 27 ++ sa_profile/connected_tag/BUILD.gn | 20 ++ services/connected_tag/BUILD.gn | 50 +++ services/connected_tag/etc/init/BUILD.gn | 29 ++ .../etc/init/nfc_connected_tag_service.cfg | 17 + .../etc/init/nfc_connected_tag_service.rc | 23 ++ .../include/connected_tag_callback_proxy.h | 35 ++ .../include/connected_tag_service_impl.h | 63 ++++ .../include/connected_tag_session_stub.h | 47 +++ .../src/connected_tag_callback_proxy.cpp | 46 +++ .../src/connected_tag_service_impl.cpp | 126 +++++++ .../src/connected_tag_session_stub.cpp | 89 +++++ services/connected_tag/src/hardware/BUILD.gn | 55 ++++ .../include/connected_tag_hdi_adapter.h | 35 ++ .../src/connected_tag_hdi_adapter.cpp | 81 +++++ 43 files changed, 2987 insertions(+), 25 deletions(-) create mode 100644 LICENSE create mode 100755 OAT.xml create mode 100644 README_zh.md create mode 100755 bundle.json create mode 100755 figures/en-us_image_0000001086731550.gif create mode 100755 figures/zh-cn_image_0000001124327253.png create mode 100755 interfaces/kits/native_cpp/connected_tag_base/BUILD.gn create mode 100755 interfaces/kits/native_cpp/connected_tag_base/include/connected_tag_callback_stub.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/include/connected_tag_impl.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/include/iconnected_tag.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/include/iconnected_tag_callback.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/include/log.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/include/tag_session_proxy.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/interfaces/error_code.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/interfaces/i_tag_session.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/interfaces/ipc_cmd.h create mode 100755 interfaces/kits/native_cpp/connected_tag_base/src/connected_tag_callback_stub.cpp create mode 100755 interfaces/kits/native_cpp/connected_tag_base/src/connected_tag_impl.cpp create mode 100755 interfaces/kits/native_cpp/connected_tag_base/src/tag_session_proxy.cpp create mode 100755 interfaces/kits/native_cpp/napi/connected_tag/BUILD.gn create mode 100755 interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_adapter.cpp create mode 100755 interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_adapter.h create mode 100755 interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_entry.cpp create mode 100755 interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_event.cpp create mode 100755 interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_event.h create mode 100755 interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_utils.cpp create mode 100755 interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_utils.h create mode 100755 sa_profile/connected_tag/1140.xml create mode 100755 sa_profile/connected_tag/BUILD.gn create mode 100755 services/connected_tag/BUILD.gn create mode 100755 services/connected_tag/etc/init/BUILD.gn create mode 100755 services/connected_tag/etc/init/nfc_connected_tag_service.cfg create mode 100755 services/connected_tag/etc/init/nfc_connected_tag_service.rc create mode 100755 services/connected_tag/include/connected_tag_callback_proxy.h create mode 100755 services/connected_tag/include/connected_tag_service_impl.h create mode 100755 services/connected_tag/include/connected_tag_session_stub.h create mode 100755 services/connected_tag/src/connected_tag_callback_proxy.cpp create mode 100755 services/connected_tag/src/connected_tag_service_impl.cpp create mode 100755 services/connected_tag/src/connected_tag_session_stub.cpp create mode 100755 services/connected_tag/src/hardware/BUILD.gn create mode 100755 services/connected_tag/src/hardware/include/connected_tag_hdi_adapter.h create mode 100755 services/connected_tag/src/hardware/src/connected_tag_hdi_adapter.cpp diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4947287 --- /dev/null +++ b/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + 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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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/OAT.xml b/OAT.xml new file mode 100755 index 0000000..6c995a8 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 78a1763..29ccb59 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,55 @@ -# communication_nfc +# NFC -#### 介绍 -NFC英文全称Near Field Communication,近距离无线通信。提供NFC有源标签的读写能力。 +- [Introduction](#section13587125816351) +- [Architecture](#section13587185873516) +- [Directory Structure](#section161941989596) +- [Constraints](#section119744591305) +- [Usage](#section1312121216216) +- [Repositories Involved](#section1371113476307) -#### 软件架构 -软件架构说明 +## Introduction + +Near-field communication \(NFC\) is a non-contact identification and interconnection technology for short-distance wireless communication between mobile devices, consumer electronic products, PCs, and smart devices. + +The NFC module provides connected tag reading and writing. + +## Architecture + +**Figure 1** NFC architecture -#### 安装教程 +![](figures/en-us_image_0000001086731550.gif) -1. xxxx -2. xxxx -3. xxxx +## Directory Structure -#### 使用说明 +The main code directory structure of Intelligent Soft Bus is as follows: -1. xxxx -2. xxxx -3. xxxx +``` +/foundation/communication +├── interfaces # 接口代码 +│ └── kits +│ └── native_cpp # 本地SDK库 +│ └── connected_tag_base # NFC有源标签SDK实现 +│ └── napi # native api +│ └── connected_tag # NFC有源标签native api +└── sa_profile # 服务属性声明 +│ └── connected_tag # NFC有源标签服务属性声明 +└── services # 子系统服务代码 + └── connected_tag # NFC有源标签服务 + ├── etc # 系统服务配置 + ├── include # 头文件 + └── src # 源文件 +``` -#### 参与贡献 +## Constraints -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +- Devices must has the connected tag chip. + +## Usage -#### 特技 -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +## Repositories Involved + +hmf/communication/nfc + diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..52c3489 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,64 @@ +# NFC组件 + +- [简介](#section11660541593) +- [系统架构](#section342962219551) +- [目录](#section161941989596) +- [约束](#section119744591305) +- [说明](#section1312121216216) +- [使用说明](#section129654513264) +- [相关仓](#section1371113476307) + +## 简介 + +近距离无线通信技术\(Near Field Communication,NFC\) ,是一种非接触式识别和互联技术,可以在移动设备、消费类电子产品、PC和智能设备间进行近距离无线通信。 + +OpenHarmony中NFC服务提供有源标签读写业务能力。 + +## 系统架构 + +**图 1** NFC组件架构图 + + +![](figures/zh-cn_image_0000001124327253.png) + + + + +
+ +## 目录 + +``` +/foundation/communication/nfc +├── interfaces # 接口代码 +│ └── kits +│ └── native_cpp # 本地SDK库 +│ └── connected_tag_base # NFC有源标签SDK实现 +│ └── napi # native api +│ └── connected_tag # NFC有源标签native api +└── sa_profile # 服务属性声明 +│ └── connected_tag # NFC有源标签服务属性声明 +└── services # 子系统服务代码 + └── connected_tag # NFC有源标签服务 + ├── etc # 系统服务配置 + ├── include # 头文件 + └── src # 源文件 +``` + +## 约束 + +设备必须具备有源标签芯片,才能使用有源标签的读写服务。 + +## 说明 + +### 使用说明 + +- 有源标签的读写 + +设备必须具备有源标签芯片,才能使用有源标签的读写服务,参考“js-apis-connectedTag.md”有源标签开发指南。 + + +## 相关仓 + +hmf/communication/nfc + diff --git a/bundle.json b/bundle.json new file mode 100755 index 0000000..b1e5220 --- /dev/null +++ b/bundle.json @@ -0,0 +1,81 @@ +{ + "name": "@ohos/communication_nfc", + "version": "3.1", + "description": "nfc service", + "homePage": "https://gitee.com/openharmony", + "license": "Apache License 2.0", + "repository": "https://gitee.com/openharmony/communication_nfc", + "domain": "os", + "language": "", + "publishAs": "code-segment", + "private": false, + "scripts": {}, + "tags": [ + "foundation" + ], + "keywords": [ + "communication", + "nfc" + ], + "envs": [], + "dirs": [], + "author": { + "name": "", + "email": "", + "url": "" + }, + "contributors": [ + { + "name": "", + "email": "", + "url": "" + } + ], + "segment": { + "destPath": "foundation/communication/nfc" + }, + "component": { + "name": "nfc_connected_tag", + "subsystem": "communication", + "syscap": [ + "SystemCapability.Communication.ConnectedTag" + ], + "features": [], + "adapted_system_type": [ + ], + "rom": "", + "ram": "", + "deps": { + "components": [ + "ipc", + "hiviewdfx_hilog_native" + ], + "third_party": [ + ] + }, + "build": { + "sub_component": [ + "//foundation/communication/nfc/sa_profile/connected_tag:connected_tag_profile", + "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base:connected_tag_base", + "//foundation/communication/nfc/services/connected_tag:nfc_connected_tag_service", + "//foundation/communication/nfc/interfaces/kits/native_cpp/napi/connected_tag:connectedtag" + ], + "inner_kits": [ + { + "type": "so", + "name": "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base:connected_tag_base", + "header": { + "header_files": [ + "connected_tag_impl.h" + ], + "header_base": "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base/include" + } + } + ], + "test": [ + ] + }, + "hisysevent_config": [ + ] + } +} diff --git a/figures/en-us_image_0000001086731550.gif b/figures/en-us_image_0000001086731550.gif new file mode 100755 index 0000000000000000000000000000000000000000..0f995cdf2a0f8be5816cc6c554c5b7887302b905 GIT binary patch literal 80363 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 Bs+#}+ literal 0 HcmV?d00001 diff --git a/figures/zh-cn_image_0000001124327253.png b/figures/zh-cn_image_0000001124327253.png new file mode 100755 index 0000000000000000000000000000000000000000..a173bf4c348555644100851fc9a993ba8cb1b978 GIT binary patch literal 52496 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 literal 0 HcmV?d00001 diff --git a/interfaces/kits/native_cpp/connected_tag_base/BUILD.gn b/interfaces/kits/native_cpp/connected_tag_base/BUILD.gn new file mode 100755 index 0000000..9a48cf9 --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/BUILD.gn @@ -0,0 +1,56 @@ +# 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("//build/ohos.gni") +import("//build/ohos_var.gni") + +config("connected_tag_base_config") { + cflags_cc = [ + "-fPIC", + "-Wno-unused-parameter", + "-Wunused-private-field", + ] + include_dirs = [ + "//utils/system/safwk/native/include", + "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base/interfaces", + "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base/include", + ] +} + +config("connected_tag_base_public_config") { + include_dirs = [ + ] +} + +ohos_shared_library("connected_tag_base") { + configs = [ ":connected_tag_base_config" ] + public_configs = [ ":connected_tag_base_public_config" ] + sources = [ + "src/connected_tag_impl.cpp", + "src/tag_session_proxy.cpp", + "src/connected_tag_callback_stub.cpp", + ] + + deps = [ + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "samgr_standard:samgr_proxy", + ] + + subsystem_name = "communication" + part_name = "nfc_connected_tag" +} diff --git a/interfaces/kits/native_cpp/connected_tag_base/include/connected_tag_callback_stub.h b/interfaces/kits/native_cpp/connected_tag_base/include/connected_tag_callback_stub.h new file mode 100755 index 0000000..3886d30 --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/include/connected_tag_callback_stub.h @@ -0,0 +1,46 @@ +/* + * 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 OHOS_CONNECTED_TAG_CALLBACK_STUB_H +#define OHOS_CONNECTED_TAG_CALLBACK_STUB_H + +#include "iremote_stub.h" +#include "iremote_object.h" +#include "iconnected_tag_callback.h" +#include +#include "error_code.h" + +namespace OHOS { +namespace ConnectedTag { +class ConnectedTagCallBackStub : public IRemoteStub { +public: + ConnectedTagCallBackStub(); + virtual ~ConnectedTagCallBackStub(); + static ConnectedTagCallBackStub& GetInstance(); + ErrCode RegisterUserCallBack(const sptr &callBack); + + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + void OnNotify(int nfcRfState) override; + +private: + int RemoteOnNotify(MessageParcel &data, MessageParcel &reply); + sptr callback_; + std::shared_mutex callbackMutex; + bool mRemoteDied; +}; +} // namespace ConnectedTag +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/native_cpp/connected_tag_base/include/connected_tag_impl.h b/interfaces/kits/native_cpp/connected_tag_base/include/connected_tag_impl.h new file mode 100755 index 0000000..f863e13 --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/include/connected_tag_impl.h @@ -0,0 +1,48 @@ +/* + * 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 NAPI_CONNECTED_TAG_IMPL_H_ +#define NAPI_CONNECTED_TAG_IMPL_H_ + +#include "tag_session_proxy.h" +#include "error_code.h" +#include "iconnected_tag.h" +#include "iconnected_tag_callback.h" + +namespace OHOS { +namespace ConnectedTag { +class ConnectedTagImpl : public IConnectedTag { +public: + explicit ConnectedTagImpl(); + virtual ~ConnectedTagImpl(); + + static ConnectedTagImpl& GetInstance(); + + ErrCode Init() override; + + ErrCode Uninit() override; + + ErrCode ReadNdefTag(std::string &response) override; + + ErrCode WriteNdefTag(std::string data) override; + + ErrCode RegListener(const sptr &callback) override; + + ErrCode UnregListener(const sptr &callback) override; +private: + sptr tagSessionProxy_; +}; +} // namespace ConnectedTag +} // namespace OHOS +#endif /* NAPI_CONNECTED_TAG_IMPL_H_ */ diff --git a/interfaces/kits/native_cpp/connected_tag_base/include/iconnected_tag.h b/interfaces/kits/native_cpp/connected_tag_base/include/iconnected_tag.h new file mode 100755 index 0000000..954b3bd --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/include/iconnected_tag.h @@ -0,0 +1,42 @@ +/* + * 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 NAPI_ICONNECTED_TAG_H_ +#define NAPI_ICONNECTED_TAG_H_ + +#include "iremote_object.h" +#include "error_code.h" +#include "iconnected_tag_callback.h" + +namespace OHOS { +namespace ConnectedTag { +class IConnectedTag { +public: + virtual ~IConnectedTag() = default; + + virtual ErrCode Init() = 0; + + virtual ErrCode Uninit() = 0; + + virtual ErrCode ReadNdefTag(std::string &response) = 0; + + virtual ErrCode WriteNdefTag(std::string data) = 0; + + virtual ErrCode RegListener(const sptr &callback) = 0; + + virtual ErrCode UnregListener(const sptr &callback) = 0; +}; +} // namespace ConnectedTag +} // namespace OHOS +#endif /* NAPI_ICONNECTED_TAG_H_ */ diff --git a/interfaces/kits/native_cpp/connected_tag_base/include/iconnected_tag_callback.h b/interfaces/kits/native_cpp/connected_tag_base/include/iconnected_tag_callback.h new file mode 100755 index 0000000..40b4c58 --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/include/iconnected_tag_callback.h @@ -0,0 +1,29 @@ +/* + * 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 NFC_ICONNECTED_TAG_CALLBACK_H +#define NFC_ICONNECTED_TAG_CALLBACK_H +#include + +namespace OHOS { +namespace ConnectedTag { +class IConnectedTagCallBack : public IRemoteBroker { +public: + virtual void OnNotify(int nfcRfState) = 0; +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.connected_tag.IConnectedTagCallBack"); +}; +} // namespace ConnectedTag +} // namespace OHOS +#endif //NFC_ICONNECTED_TAG_CALLBACK_H diff --git a/interfaces/kits/native_cpp/connected_tag_base/include/log.h b/interfaces/kits/native_cpp/connected_tag_base/include/log.h new file mode 100755 index 0000000..b8ac126 --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/include/log.h @@ -0,0 +1,83 @@ +/* + * 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 NFC_LOG_H +#define NFC_LOG_H + +#define CONFIG_HILOG +#ifdef CONFIG_HILOG +#include "hilog/log.h" + +#ifdef HILOGF +#undef HILOGF +#endif + +#ifdef HILOGE +#undef HILOGE +#endif + +#ifdef HILOGW +#undef HILOGW +#endif + +#ifdef HILOGI +#undef HILOGI +#endif + +#ifdef HILOGD +#undef HILOGD +#endif + +#ifndef NFC_LOG_DOMAIN +#define NFC_LOG_DOMAIN 0xD006000 +#endif + +#ifndef NFC_LOG_TAG +#define NFC_LOG_TAG "Nfc_Connected_Tag" +#endif + +#ifdef LOG_LABEL +#undef LOG_LABEL +#endif + +static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, NFC_LOG_DOMAIN, NFC_LOG_TAG}; + +#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) + +#define HILOGF(fmt, ...) \ + (void)OHOS::HiviewDFX::HiLog::Fatal( \ + LOG_LABEL, "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define HILOGE(fmt, ...) \ + (void)OHOS::HiviewDFX::HiLog::Error( \ + LOG_LABEL, "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define HILOGW(fmt, ...) \ + (void)OHOS::HiviewDFX::HiLog::Warn( \ + LOG_LABEL, "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define HILOGI(fmt, ...) \ + (void)OHOS::HiviewDFX::HiLog::Info( \ + LOG_LABEL, "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define HILOGD(fmt, ...) \ + (void)OHOS::HiviewDFX::HiLog::Debug( \ + LOG_LABEL, "[%{public}s(%{public}s:%{public}d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#else + +#define HILOGF(...) +#define HILOGE(...) +#define HILOGW(...) +#define HILOGI(...) +#define HILOGD(...) +#endif // CONFIG_HILOG + +#endif // NFC_LOG_H diff --git a/interfaces/kits/native_cpp/connected_tag_base/include/tag_session_proxy.h b/interfaces/kits/native_cpp/connected_tag_base/include/tag_session_proxy.h new file mode 100755 index 0000000..54b68c8 --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/include/tag_session_proxy.h @@ -0,0 +1,51 @@ +/* + * 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 OHOS_NFC_TAG_SESSION_PROXY_H +#define OHOS_NFC_TAG_SESSION_PROXY_H +#include "i_tag_session.h" +#include +#include "iremote_proxy.h" + +namespace OHOS { +namespace ConnectedTag { +class TagSessionProxy : public IRemoteProxy, public IRemoteObject::DeathRecipient { +public: + explicit TagSessionProxy(const sptr &impl); + ~TagSessionProxy(); + + ErrCode Init() override; + + ErrCode Uninit() override; + + ErrCode ReadNdefTag(std::string &response) override; + + ErrCode WriteNdefTag(std::string data) override; + + ErrCode RegListener(const sptr &callback) override; + + ErrCode UnregListener(const sptr &callback) override; + + /** + * @Description Handle remote object died event. + * @param remoteObject remote object. + */ + void OnRemoteDied(const wptr &remoteObject) override; + +private: + bool mRemoteDied; +}; +} // namespace ConnectedTag +} // namespace OHOS +#endif diff --git a/interfaces/kits/native_cpp/connected_tag_base/interfaces/error_code.h b/interfaces/kits/native_cpp/connected_tag_base/interfaces/error_code.h new file mode 100755 index 0000000..12725df --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/interfaces/error_code.h @@ -0,0 +1,29 @@ +/* + * 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 OHOS_NFC_ERRCODE_H +#define OHOS_NFC_ERRCODE_H + +namespace OHOS { +namespace ConnectedTag { +/* Nfc errcode defines */ +enum ErrCode { + NFC_OPT_SUCCESS = 0, /* successfully */ + NFC_OPT_FAILED, /* failed */ + NFC_OPT_NOT_SUPPORTED, /* not supported */ +}; +} // namespace ConnectedTag +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/native_cpp/connected_tag_base/interfaces/i_tag_session.h b/interfaces/kits/native_cpp/connected_tag_base/interfaces/i_tag_session.h new file mode 100755 index 0000000..3e5f08c --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/interfaces/i_tag_session.h @@ -0,0 +1,38 @@ +/* + * 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 OHOS_I_TAG_SESSION_H +#define OHOS_I_TAG_SESSION_H +#include "iremote_broker.h" +#include "error_code.h" +#include "iconnected_tag_callback.h" + +namespace OHOS { +namespace ConnectedTag { +class ITagSession : public IRemoteBroker { +public: + virtual ~ITagSession() {} + + virtual ErrCode Init() = 0; + virtual ErrCode Uninit() = 0; + virtual ErrCode ReadNdefTag(std::string &response) = 0; + virtual ErrCode WriteNdefTag(std::string data) = 0; + virtual ErrCode RegListener(const sptr &callback) = 0; + virtual ErrCode UnregListener(const sptr &callback) = 0; +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.nfc.INfcConnectedTagService"); +}; +} // namespace ConnectedTag +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/native_cpp/connected_tag_base/interfaces/ipc_cmd.h b/interfaces/kits/native_cpp/connected_tag_base/interfaces/ipc_cmd.h new file mode 100755 index 0000000..6e776ed --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/interfaces/ipc_cmd.h @@ -0,0 +1,29 @@ +/* + * 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 OHOS_IPC_CMD_H +#define OHOS_IPC_CMD_H + +/* ------------connected tag module message define--------- */ +#define NFC_SVR_CMD_INIT 0x1001 +#define NFC_SVR_CMD_UNINIT 0x1002 +#define NFC_SVR_CMD_READ_NDEF_TAG 0x1003 +#define NFC_SVR_CMD_WRITE_NDEF_TAG 0x1004 + +#define CMD_ON_NOTIFY 0x2001 + +/* ---------Feature service ability id */ +#define NFC_CONNECTED_TAG_ABILITY_ID 1140 + +#endif \ No newline at end of file diff --git a/interfaces/kits/native_cpp/connected_tag_base/src/connected_tag_callback_stub.cpp b/interfaces/kits/native_cpp/connected_tag_base/src/connected_tag_callback_stub.cpp new file mode 100755 index 0000000..f319703 --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/src/connected_tag_callback_stub.cpp @@ -0,0 +1,91 @@ +/* + * 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 "connected_tag_callback_stub.h" +#include "ipc_cmd.h" +#include "error_code.h" +#include "log.h" + +namespace OHOS { +namespace ConnectedTag { +ConnectedTagCallBackStub::ConnectedTagCallBackStub() : callback_(nullptr), mRemoteDied(false) +{} + +ConnectedTagCallBackStub::~ConnectedTagCallBackStub() +{} + +ConnectedTagCallBackStub& ConnectedTagCallBackStub::GetInstance() +{ + static ConnectedTagCallBackStub sConnectedTagCallBackStub; + return sConnectedTagCallBackStub; +} + +void ConnectedTagCallBackStub::OnNotify(int nfcRfState) +{ + HILOGD("ConnectedTagCallBackStub::OnNotify"); + if (callback_) { + callback_->OnNotify(nfcRfState); + } +} + +int ConnectedTagCallBackStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + HILOGD("ConnectedTagCallBackStub::OnRemoteRequest!"); + if (mRemoteDied) { + HILOGE("Failed to `%{public}s`,Remote service is died!", __func__); + return NFC_OPT_FAILED; + } + int exception = data.ReadInt32(); + if (exception) { + HILOGE("ConnectedTagCallBackStub::OnRemoteRequest, got exception: %{public}d!", exception); + return NFC_OPT_FAILED; + } + int ret = NFC_OPT_FAILED; + switch (code) { + case CMD_ON_NOTIFY: { + ret = RemoteOnNotify(data, reply); + break; + } + default: { + ret = IPCObjectStub::OnRemoteRequest(code, data, reply, option); + break; + } + } + return ret; +} + +ErrCode ConnectedTagCallBackStub::RegisterUserCallBack(const sptr &callBack) +{ + std::shared_lock guard(callbackMutex); + if (callBack == nullptr) { + HILOGW("RegisterUserCallBack:callBack is nullptr!"); + } + callback_ = callBack; + return NFC_OPT_SUCCESS; +} + +int ConnectedTagCallBackStub::RemoteOnNotify(MessageParcel &data, MessageParcel &reply) +{ + HILOGD("run %{public}s datasize %{public}zu", __func__, data.GetRawDataSize()); + int state = data.ReadInt32(); + std::shared_lock guard(callbackMutex); + if (callback_) { + callback_->OnNotify(state); + } + reply.WriteInt32(NFC_OPT_SUCCESS); /* Reply 0 to indicate that no exception occurs. */ + return NFC_OPT_SUCCESS; +} +} // namespace ConnectedTag +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/native_cpp/connected_tag_base/src/connected_tag_impl.cpp b/interfaces/kits/native_cpp/connected_tag_base/src/connected_tag_impl.cpp new file mode 100755 index 0000000..d8fb8c9 --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/src/connected_tag_impl.cpp @@ -0,0 +1,80 @@ +/* + * 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 "connected_tag_impl.h" +#include "iservice_registry.h" +#include "ipc_cmd.h" +#include "log.h" + +namespace OHOS { +namespace ConnectedTag { + +ConnectedTagImpl::ConnectedTagImpl() +{ + HILOGI("ConnectedTagImpl() in"); + sptr sa_mgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (sa_mgr == nullptr) { + HILOGE("failed to get SystemAbilityManager"); + return; + } + + sptr object = sa_mgr->GetSystemAbility(NFC_CONNECTED_TAG_ABILITY_ID); + if (object == nullptr) { + HILOGE("failed to get connected tag SERVICE"); + return; + } + + tagSessionProxy_ = iface_cast(object); + if (tagSessionProxy_ == nullptr) { + tagSessionProxy_ = new (std::nothrow) TagSessionProxy(object); + } + + if (tagSessionProxy_ == nullptr) { + HILOGE("TagSessionProxy init failed!"); + } +} +ConnectedTagImpl::~ConnectedTagImpl() +{ +} +ConnectedTagImpl& ConnectedTagImpl::GetInstance() +{ + static ConnectedTagImpl tagImplSingleton; + return tagImplSingleton; +} +ErrCode ConnectedTagImpl::Init() +{ + return tagSessionProxy_->Init(); +} +ErrCode ConnectedTagImpl::Uninit() +{ + return tagSessionProxy_->Uninit(); +} +ErrCode ConnectedTagImpl::ReadNdefTag(std::string &response) +{ + return tagSessionProxy_->ReadNdefTag(response); +} +ErrCode ConnectedTagImpl::WriteNdefTag(std::string data) +{ + return tagSessionProxy_->WriteNdefTag(data); +} +ErrCode ConnectedTagImpl::RegListener(const sptr &callback) +{ + return tagSessionProxy_->RegListener(callback); +} +ErrCode ConnectedTagImpl::UnregListener(const sptr &callback) +{ + return tagSessionProxy_->UnregListener(callback); +} +} // namespace ConnectedTag +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/native_cpp/connected_tag_base/src/tag_session_proxy.cpp b/interfaces/kits/native_cpp/connected_tag_base/src/tag_session_proxy.cpp new file mode 100755 index 0000000..66762cc --- /dev/null +++ b/interfaces/kits/native_cpp/connected_tag_base/src/tag_session_proxy.cpp @@ -0,0 +1,149 @@ +/* + * 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 "tag_session_proxy.h" + #include "log.h" + #include "ipc_cmd.h" + #include "connected_tag_callback_stub.h" + +namespace OHOS { +namespace ConnectedTag { +TagSessionProxy::TagSessionProxy(const sptr &impl) : IRemoteProxy(impl), mRemoteDied(false) +{ + HILOGI("TagSessionProxy() in!"); + if (impl) { + if ((impl->IsProxyObject()) && (!impl->AddDeathRecipient(this))) { + HILOGD("AddDeathRecipient!"); + } else { + HILOGW("no recipient!"); + } + } +} +TagSessionProxy::~TagSessionProxy() +{ +} + +ErrCode TagSessionProxy::Init() +{ + if (mRemoteDied) { + HILOGD("failed to `%{public}s`,remote service is died!", __func__); + return NFC_OPT_FAILED; + } + MessageOption option; + MessageParcel data; + MessageParcel reply; + data.WriteInt32(NFC_OPT_SUCCESS); + + int error = Remote()->SendRequest(NFC_SVR_CMD_INIT, data, reply, option); + if (error != ERR_NONE) { + HILOGE("Init failed, error code is %{public}d", error); + return NFC_OPT_FAILED; + } + + int exception = reply.ReadInt32(); + if (exception) { + return NFC_OPT_FAILED; + } + return ErrCode(reply.ReadInt32()); +} +ErrCode TagSessionProxy::Uninit() +{ + if (mRemoteDied) { + HILOGD("failed to `%{public}s`,remote service is died!", __func__); + return NFC_OPT_FAILED; + } + MessageOption option; + MessageParcel data; + MessageParcel reply; + data.WriteInt32(NFC_OPT_SUCCESS); + + int error = Remote()->SendRequest(NFC_SVR_CMD_UNINIT, data, reply, option); + if (error != ERR_NONE) { + HILOGE("Uninit failed, error code is %{public}d", error); + return NFC_OPT_FAILED; + } + + int exception = reply.ReadInt32(); + if (exception) { + return NFC_OPT_FAILED; + } + return ErrCode(reply.ReadInt32()); +} +ErrCode TagSessionProxy::ReadNdefTag(std::string &response) +{ + if (mRemoteDied) { + HILOGD("failed to `%{public}s`,remote service is died!", __func__); + return NFC_OPT_FAILED; + } + MessageOption option; + MessageParcel data; + MessageParcel reply; + data.WriteInt32(NFC_OPT_SUCCESS); + + int error = Remote()->SendRequest(NFC_SVR_CMD_READ_NDEF_TAG, data, reply, option); + if (error != ERR_NONE) { + HILOGE("ReadNdefTag failed, error code is %{public}d", error); + return NFC_OPT_FAILED; + } + + int exception = reply.ReadInt32(); + if (exception) { + return NFC_OPT_FAILED; + } + response = reply.ReadString(); + return ErrCode(NFC_OPT_SUCCESS); +} +ErrCode TagSessionProxy::WriteNdefTag(std::string tagData) +{ + if (mRemoteDied) { + HILOGD("failed to `%{public}s`,remote service is died!", __func__); + return NFC_OPT_FAILED; + } + MessageOption option; + MessageParcel data; + MessageParcel reply; + data.WriteInt32(NFC_OPT_SUCCESS); + data.WriteString(tagData); + HILOGE("TagSessionProxy WriteNdefTag tagData is %{public}s", tagData.c_str()); + + int error = Remote()->SendRequest(NFC_SVR_CMD_WRITE_NDEF_TAG, data, reply, option); + if (error != ERR_NONE) { + HILOGE("WriteNdefTag failed,error code is %{public}d", error); + return NFC_OPT_FAILED; + } + + int exception = reply.ReadInt32(); + if (exception) { + return NFC_OPT_FAILED; + } + return ErrCode(reply.ReadInt32()); +} +ErrCode TagSessionProxy::RegListener(const sptr &callback) +{ + return OHOS::ConnectedTag::ConnectedTagCallBackStub::GetInstance().RegisterUserCallBack(callback); +} +ErrCode TagSessionProxy::UnregListener(const sptr &callback) +{ + return OHOS::ConnectedTag::ConnectedTagCallBackStub::GetInstance().RegisterUserCallBack(nullptr); +} + +void TagSessionProxy::OnRemoteDied(const wptr &remoteObject) +{ + HILOGD("Remote service is died!"); + mRemoteDied = true; +} +} // namespace ConnectedTag +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/native_cpp/napi/connected_tag/BUILD.gn b/interfaces/kits/native_cpp/napi/connected_tag/BUILD.gn new file mode 100755 index 0000000..9f3d419 --- /dev/null +++ b/interfaces/kits/native_cpp/napi/connected_tag/BUILD.gn @@ -0,0 +1,50 @@ +# 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("//build/ohos.gni") + +ohos_shared_library("connectedtag") { + install_enable = true + include_dirs = [ + "//third_party/node/src", + "//native_engine", + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base/include", + "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base/interfaces", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//base/notification/ces_standard/frameworks/core/include", + ] + + sources = [ + "nfc_napi_adapter.cpp", + "nfc_napi_event.cpp", + "nfc_napi_entry.cpp", + "nfc_napi_utils.cpp", + ] + 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/nfc/interfaces/kits/native_cpp/connected_tag_base:connected_tag_base", + "//utils/native/base:utils", + ] + + external_deps = [ "ipc:ipc_core" ] + + relative_install_dir = "module" + part_name = "nfc_connected_tag" + subsystem_name = "communication" +} diff --git a/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_adapter.cpp b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_adapter.cpp new file mode 100755 index 0000000..b8144a8 --- /dev/null +++ b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_adapter.cpp @@ -0,0 +1,108 @@ +/* + * 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 "nfc_napi_adapter.h" +#include "error_code.h" +#include "connected_tag_impl.h" +#include "log.h" +#include +#include + +namespace OHOS { +namespace ConnectedTag { +std::string g_writtenNdefData = ""; +napi_value Init(napi_env env, napi_callback_info info) +{ + TRACE_FUNC_CALL; + ConnectedTagImpl connectedTagPtr = OHOS::ConnectedTag::ConnectedTagImpl::GetInstance(); + ErrCode ret = connectedTagPtr.Init(); + napi_value result; + napi_get_boolean(env, ret == NFC_OPT_SUCCESS, &result); + return result; +} + +napi_value Uninit(napi_env env, napi_callback_info info) +{ + TRACE_FUNC_CALL; + ConnectedTagImpl connectedTagPtr = OHOS::ConnectedTag::ConnectedTagImpl::GetInstance(); + ErrCode ret = connectedTagPtr.Uninit(); + napi_value result; + napi_get_boolean(env, ret == NFC_OPT_SUCCESS, &result); + return result; +} + +napi_value ReadNdefTag(napi_env env, napi_callback_info info) +{ + TRACE_FUNC_CALL; + size_t argc = 2; + napi_value argv[argc]; + napi_value thisVar = nullptr; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)); + HILOGI("ReadNdefTag argc = %{public}d", argc); + + ReadAsyncContext *asyncContext = new ReadAsyncContext(env); + napi_create_string_latin1(env, "readNdefTag", NAPI_AUTO_LENGTH, &asyncContext->resourceName); + + asyncContext->executeFunc = [&](void* data) -> void { + ReadAsyncContext *context = static_cast(data); + TRACE_FUNC_CALL_NAME("connectedTagPtr->ReadNdefTag"); + ConnectedTagImpl connectedTagPtr = OHOS::ConnectedTag::ConnectedTagImpl::GetInstance(); + context->errorCode = connectedTagPtr.ReadNdefTag(context->respNdefData); + HILOGI("ReadNdefTag end errorCode = %{public}d", context->errorCode); + }; + + asyncContext->completeFunc = [&](void* data) -> void { + ReadAsyncContext *context = static_cast(data); + napi_create_string_utf8(context->env, context->respNdefData.c_str(), NAPI_AUTO_LENGTH, &context->result); + HILOGI("ReadNdefTag respNdefData=%{public}s, len = %{public}d", + context->respNdefData.c_str(), context->respNdefData.length()); + }; + + size_t nonCallbackArgNum = 0; + return DoAsyncWork(env, asyncContext, argc, argv, nonCallbackArgNum); +} + +napi_value WriteNdefTag(napi_env env, napi_callback_info info) +{ + TRACE_FUNC_CALL; + size_t argc = 2; + napi_value argv[argc]; + napi_value thisVar = nullptr; + void *data = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)); + + g_writtenNdefData = ""; + ParseString(env, g_writtenNdefData, argv[0]); + HILOGI("WriteNdefTag argc = %{public}d, data=%{public}s, len = %{public}d", argc, + g_writtenNdefData.c_str(), g_writtenNdefData.length()); + + WriteAsyncContext *asyncContext = new WriteAsyncContext(env); + napi_create_string_latin1(env, "writeNdefTag", NAPI_AUTO_LENGTH, &asyncContext->resourceName); + + asyncContext->executeFunc = [&](void* data) -> void { + WriteAsyncContext *context = static_cast(data); + TRACE_FUNC_CALL_NAME("connectedTagPtr->WriteNdefTag"); + ConnectedTagImpl connectedTagPtr = OHOS::ConnectedTag::ConnectedTagImpl::GetInstance(); + HILOGI("WriteNdefTag start ndefData = %{public}s", g_writtenNdefData.c_str()); + context->errorCode = connectedTagPtr.WriteNdefTag(g_writtenNdefData); + HILOGI("WriteNdefTag end errorCode = %{public}d", context->errorCode); + }; + + size_t nonCallbackArgNum = 1; + return DoAsyncWork(env, asyncContext, argc, argv, nonCallbackArgNum); +} +} // namespace ConnectedTag +} // namespace OHOS diff --git a/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_adapter.h b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_adapter.h new file mode 100755 index 0000000..236d2e9 --- /dev/null +++ b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_adapter.h @@ -0,0 +1,50 @@ +/* + * 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 NFC_NAPI_ADAPTER_H_ +#define NFC_NAPI_ADAPTER_H_ +#include "nfc_napi_utils.h" + +namespace OHOS { +namespace ConnectedTag { +napi_value Init(napi_env env, napi_callback_info info); +napi_value Uninit(napi_env env, napi_callback_info info); +napi_value ReadNdefTag(napi_env env, napi_callback_info info); +napi_value WriteNdefTag(napi_env env, napi_callback_info info); + +class ReadAsyncContext : public AsyncContext { +public: + std::string respNdefData; + ReadAsyncContext(napi_env env, napi_async_work work = nullptr, napi_deferred deferred = nullptr) : + AsyncContext(env, work, deferred){} + + ReadAsyncContext() = delete; + + virtual ~ReadAsyncContext(){} +}; + +class WriteAsyncContext : public AsyncContext { +public: + WriteAsyncContext(napi_env env, napi_async_work work = nullptr, napi_deferred deferred = nullptr) : + AsyncContext(env, work, deferred){} + + WriteAsyncContext() = delete; + + virtual ~WriteAsyncContext(){} +}; +} // namespace ConnectedTag +} // namespace OHOS + +#endif diff --git a/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_entry.cpp b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_entry.cpp new file mode 100755 index 0000000..f15e897 --- /dev/null +++ b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_entry.cpp @@ -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. + */ + +#include "nfc_napi_adapter.h" +#include "nfc_napi_event.h" +#include "log.h" + +namespace OHOS { +namespace ConnectedTag { +/* + * Module initialization function + */ +static napi_value InitJs(napi_env env, napi_value exports) +{ + HILOGI("Init, nfc_napi_entry"); + + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("init", Init), + DECLARE_NAPI_FUNCTION("uninit", Uninit), + DECLARE_NAPI_FUNCTION("readNdefTag", ReadNdefTag), + DECLARE_NAPI_FUNCTION("writeNdefTag", WriteNdefTag), + DECLARE_NAPI_FUNCTION("on", On), + DECLARE_NAPI_FUNCTION("off", Off), + }; + + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc)); + return exports; +} + +static napi_module nfcConnectedTagModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = NULL, + .nm_register_func = InitJs, + .nm_modname = "connectedTag", + .nm_priv = ((void *)0), + .reserved = { 0 } +}; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&nfcConnectedTagModule); +} +} // namespace ConnectedTag +} // namespace OHOS diff --git a/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_event.cpp b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_event.cpp new file mode 100755 index 0000000..17d4a4f --- /dev/null +++ b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_event.cpp @@ -0,0 +1,289 @@ +/* + * 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 "nfc_napi_event.h" +#include +#include "nfc_napi_utils.h" +#include "log.h" +#include "iconnected_tag_callback.h" +#include "connected_tag_impl.h" + +namespace OHOS { +namespace ConnectedTag { + +const std::string EVENT_NOTIFY = "notify"; + +static std::set g_supportEventList = { + EVENT_NOTIFY, +}; + +bool EventRegister::isEventRegistered = false; + +void NapiEvent::EventNotify(AsyncEventData *asyncEvent) +{ + HILOGI("Enter nfc event notify"); + if (asyncEvent == nullptr) { + HILOGE("asyncEvent is null."); + return; + } + uv_loop_s* loop = nullptr; + napi_get_uv_event_loop(asyncEvent->env, &loop); + + uv_work_t* work = new uv_work_t; + if (work == nullptr) { + HILOGE("uv_work_t work is null."); + delete asyncEvent; + asyncEvent = nullptr; + return; + } + + HILOGI("Get the event loop, napi_env: %{public}p", asyncEvent->env); + work->data = asyncEvent; + uv_queue_work( + loop, + work, + [](uv_work_t* work) {}, + [](uv_work_t* work, int status) { + AsyncEventData *asyncData = static_cast(work->data); + if (asyncData == nullptr) { + HILOGE("asyncData is null."); + return; + } + HILOGI("Napi event uv_queue_work, env: %{public}p, status: %{public}d", asyncData->env, status); + napi_handle_scope scope = nullptr; + napi_open_handle_scope(asyncData->env, &scope); + if (scope == nullptr) { + HILOGE("scope is nullptr"); + napi_close_handle_scope(asyncData->env, scope); + return; + } + napi_value undefine; + napi_get_undefined(asyncData->env, &undefine); + napi_value handler = nullptr; + napi_get_reference_value(asyncData->env, asyncData->callbackRef, &handler); + + HILOGI("Push event to js, env: %{public}p, ref : %{public}p", asyncData->env, &asyncData->callbackRef); + if (napi_call_function(asyncData->env, nullptr, handler, 1, &asyncData->jsEvent, &undefine) != napi_ok) { + HILOGE("Report event to Js failed"); + } + napi_close_handle_scope(asyncData->env, scope); + if (asyncData != nullptr) { + delete asyncData; + asyncData = nullptr; + } + delete work; + work = nullptr; + } + ); +} + +bool NapiEvent::CheckIsRegister(const std::string& type) +{ + return g_eventRegisterInfo.find(type) != g_eventRegisterInfo.end(); +} + +class NfcListenerEvent : public IConnectedTagCallBack, public NapiEvent { +public: + NfcListenerEvent() { + } + + virtual ~NfcListenerEvent() { + } + +public: + void OnNotify(int nfcRfState) override { + HILOGI("OnNotify rcvd nfcRfState: %{public}d", nfcRfState); + CheckAndNotify(EVENT_NOTIFY, nfcRfState); + } + + OHOS::sptr AsObject() override { + return nullptr; + } +}; + +sptr nfcListenerEvent = + sptr(new (std::nothrow) NfcListenerEvent()); + +napi_value On(napi_env env, napi_callback_info cbinfo) { + TRACE_FUNC_CALL; + size_t requireArgc = 2; + size_t argc = 2; + napi_value argv[2] = {0}; + napi_value thisVar = 0; + napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr); + napi_valuetype eventName = napi_undefined; + napi_typeof(env, argv[0], &eventName); + napi_valuetype handler = napi_undefined; + napi_typeof(env, argv[1], &handler); + + if (argc != requireArgc || eventName != napi_string || handler != napi_function) + { + HILOGE("On args invalid, failed!"); + napi_value result; + napi_get_boolean(env, false, &result); + return result; + } + + char type[64] = {0}; + size_t typeLen = 0; + napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen); + EventRegister::GetInstance().Register(env, type, argv[1]); + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} + +napi_value Off(napi_env env, napi_callback_info cbinfo) { + TRACE_FUNC_CALL; + size_t requireArgc = 1; + size_t requireArgcWithCb = 2; + size_t argc = 2; + napi_value argv[2] = {0}; + napi_value thisVar = 0; + napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr); + napi_valuetype eventName = napi_undefined; + napi_typeof(env, argv[0], &eventName); + + if ((argc != requireArgc && argc != requireArgcWithCb) || eventName != napi_string) + { + HILOGE("On args invalid, failed!"); + napi_value result; + napi_get_boolean(env, false, &result); + return result; + } + + if (argc == requireArgcWithCb) + { + napi_valuetype handler = napi_undefined; + napi_typeof(env, argv[1], &handler); + if (handler != napi_function) + { + HILOGE("On args invalid napi_function, failed!"); + napi_value result; + napi_get_boolean(env, false, &result); + return result; + } + } + + char type[64] = {0}; + size_t typeLen = 0; + napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen); + EventRegister::GetInstance().Unregister(env, type, argc >= requireArgcWithCb ? argv[1] : nullptr); + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} + +ErrCode EventRegister::RegisterNfcEvents() +{ + ConnectedTagImpl connectedTag = OHOS::ConnectedTag::ConnectedTagImpl::GetInstance(); + ErrCode ret = connectedTag.RegListener(nfcListenerEvent); + if (ret != NFC_OPT_SUCCESS) { + HILOGE("RegisterNfcEvents nfcListenerEvent failed!"); + return ret; + } + return ret; +} + +EventRegister& EventRegister::GetInstance() +{ + static EventRegister inst; + return inst; +} + +bool EventRegister::IsEventSupport(const std::string& type) +{ + return g_supportEventList.find(type) != g_supportEventList.end(); +} + +void EventRegister::Register(const napi_env& env, const std::string& type, napi_value handler) +{ + HILOGI("Register event: %{public}s, env: %{public}p", type.c_str(), env); + + if (!IsEventSupport(type)) { + HILOGE("Register type error or not support!"); + return; + } + std::unique_lock guard(g_regInfoMutex); + if (!isEventRegistered) { + if (RegisterNfcEvents() != NFC_OPT_SUCCESS) { + return; + } + isEventRegistered = true; + } + napi_ref handlerRef = nullptr; + napi_create_reference(env, handler, 1, &handlerRef); + RegObj regObj(env, handlerRef); + auto iter = g_eventRegisterInfo.find(type); + if (iter == g_eventRegisterInfo.end()) { + g_eventRegisterInfo[type] = std::vector{regObj}; + } else { + iter->second.emplace_back(regObj); + } +} + +void EventRegister::DeleteRegisterObj(std::vector& vecRegObjs, napi_value& handler) +{ + auto iter = vecRegObjs.begin(); + for (; iter != vecRegObjs.end();) { + napi_value handlerTemp = nullptr; + napi_get_reference_value(iter->m_regEnv, iter->m_regHanderRef, &handlerTemp); + bool isEqual = false; + napi_strict_equals(iter->m_regEnv, handlerTemp, handler, &isEqual); + if (isEqual) { + napi_delete_reference(iter->m_regEnv, iter->m_regHanderRef); + HILOGI("Delete register object ref."); + iter = vecRegObjs.erase(iter); + } else { + ++iter; + } + } +} + +void EventRegister::DeleteAllRegisterObj(std::vector& vecRegObjs) +{ + for (auto& each : vecRegObjs) { + napi_delete_reference(each.m_regEnv, each.m_regHanderRef); + } + vecRegObjs.clear(); +} + +void EventRegister::Unregister(const napi_env& env, const std::string& type, napi_value handler) +{ + HILOGI("Unregister event: %{public}s, env: %{public}p", type.c_str(), env); + + if (!IsEventSupport(type)) { + HILOGE("Unregister type error or not support!"); + return; + } + + std::unique_lock guard(g_regInfoMutex); + auto iter = g_eventRegisterInfo.find(type); + if (iter == g_eventRegisterInfo.end()) { + HILOGE("Unregister type not registered!"); + return; + } + if (handler != nullptr) { + DeleteRegisterObj(iter->second, handler); + } else { + HILOGW("All callback is unsubscribe for event: %{public}s", type.c_str()); + DeleteAllRegisterObj(iter->second); + } + if (iter->second.empty()) { + g_eventRegisterInfo.erase(iter); + } +} +} // namespace ConnectedTag +} // namespace OHOS diff --git a/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_event.h b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_event.h new file mode 100755 index 0000000..94cce71 --- /dev/null +++ b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_event.h @@ -0,0 +1,117 @@ +/* + * 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 NFC_NAPI_EVENT_H_ +#define NFC_NAPI_EVENT_H_ + +#include +#include +#include +#include +#include +#include "napi/native_api.h" +#include "error_code.h" + +namespace OHOS { +namespace ConnectedTag { +class AsyncEventData { +public: + napi_env env; + napi_ref callbackRef; + napi_value jsEvent; + + explicit AsyncEventData(napi_env e, napi_ref r, napi_value v) { + env = e; + callbackRef = r; + jsEvent = v; + } + + AsyncEventData() = delete; + + virtual ~AsyncEventData() { + } +}; + +class RegObj { +public: + RegObj() : m_regEnv(0), m_regHanderRef(nullptr) { + } + explicit RegObj(const napi_env& env, const napi_ref& ref) { + m_regEnv = env; + m_regHanderRef = ref; + } + + ~RegObj() { + } + + napi_env m_regEnv; + napi_ref m_regHanderRef; +}; + +static std::shared_mutex g_regInfoMutex; +static std::map> g_eventRegisterInfo; + +class NapiEvent { +public: + bool CheckIsRegister(const std::string& type); + void EventNotify(AsyncEventData *asyncEvent); + + template + void CheckAndNotify(const std::string& type, const T& obj) { + std::shared_lock guard(g_regInfoMutex); + if (!CheckIsRegister(type)) { + return; + } + + std::vector& vecObj = g_eventRegisterInfo[type]; + for (auto& each : vecObj) { + napi_value result; + napi_create_int32(each.m_regEnv, obj, &result); + AsyncEventData *asyncEvent = new AsyncEventData(each.m_regEnv, each.m_regHanderRef, result); + if (asyncEvent == nullptr) { + return; + } + EventNotify(asyncEvent); + } + } +}; + +class EventRegister { +public: + EventRegister() { + } + ~EventRegister() { + } + + static EventRegister& GetInstance(); + + void Register(const napi_env& env, const std::string& type, napi_value handler); + void Unregister(const napi_env& env, const std::string& type, napi_value handler); + +private: + ErrCode RegisterNfcEvents(); + bool IsEventSupport(const std::string& type); + void DeleteRegisterObj(std::vector& vecRegObjs, napi_value& handler); + void DeleteAllRegisterObj(std::vector& vecRegObjs); + + static bool isEventRegistered; +}; + +napi_value On(napi_env env, napi_callback_info cbinfo); +napi_value Off(napi_env env, napi_callback_info cbinfo); +} // namespace ConnectedTag +} // namespace OHOS + +#endif diff --git a/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_utils.cpp b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_utils.cpp new file mode 100755 index 0000000..5256407 --- /dev/null +++ b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_utils.cpp @@ -0,0 +1,308 @@ +/* + * 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 "nfc_napi_utils.h" +#include "securec.h" +#include "log.h" + +namespace OHOS { +namespace ConnectedTag { +TraceFuncCall::TraceFuncCall(const std::string funcName): m_funcName(funcName) +{ + if (m_isTrace) { + m_startTime = std::chrono::steady_clock::now(); + HILOGD("Call func: %{public}s (start)", m_funcName.c_str()); + } +} + +TraceFuncCall::~TraceFuncCall() +{ + if (m_isTrace) { + auto us = std::chrono::duration_cast + (std::chrono::steady_clock::now() - m_startTime).count(); + constexpr int usForPerMs = 1000; + HILOGD("Call func: %{public}s (end), time cost:%{public}lldus, %{public}lldms", + m_funcName.c_str(), us, us / usForPerMs); + } +} + +napi_value UndefinedNapiValue(const napi_env& env) +{ + napi_value result; + napi_get_undefined(env, &result); + return result; +} + +napi_value JsObjectToInt(const napi_env& env, const napi_value& object, const char* fieldStr, int& fieldRef) +{ + bool hasProperty = false; + NAPI_CALL(env, napi_has_named_property(env, object, fieldStr, &hasProperty)); + if (hasProperty) { + napi_value field; + napi_valuetype valueType; + + napi_get_named_property(env, object, fieldStr, &field); + NAPI_CALL(env, napi_typeof(env, field, &valueType)); + NAPI_ASSERT(env, valueType == napi_number, "Wrong argument type. Number expected."); + napi_get_value_int32(env, field, &fieldRef); + } else { + HILOGW("Js to int no property: %{public}s", fieldStr); + } + return UndefinedNapiValue(env); +} + +napi_value JsObjectToBool(const napi_env& env, const napi_value& object, const char* fieldStr, bool& fieldRef) +{ + bool hasProperty = false; + NAPI_CALL(env, napi_has_named_property(env, object, fieldStr, &hasProperty)); + if (hasProperty) { + napi_value field; + napi_valuetype valueType; + + napi_get_named_property(env, object, fieldStr, &field); + NAPI_CALL(env, napi_typeof(env, field, &valueType)); + NAPI_ASSERT(env, valueType == napi_boolean, "Wrong argument type. Bool expected."); + napi_get_value_bool(env, field, &fieldRef); + } else { + HILOGW("Js to bool no property: %{public}s", fieldStr); + } + return UndefinedNapiValue(env); +} + +napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result) +{ + napi_value value; + napi_status status = napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value); + if (status != napi_ok) { + HILOGE("Set value create utf8 string error! field: %{public}s", fieldStr); + return status; + } + status = napi_set_named_property(env, result, fieldStr, value); + if (status != napi_ok) { + HILOGE("Set utf8 string named property error! field: %{public}s", fieldStr); + } + return status; +} + +napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result) +{ + napi_value value; + napi_status status = napi_create_int32(env, intValue, &value); + if (status != napi_ok) { + HILOGE("Set value create int32 error! field: %{public}s", fieldStr); + return status; + } + status = napi_set_named_property(env, result, fieldStr, value); + if (status != napi_ok) { + HILOGE("Set int32 named property error! field: %{public}s", fieldStr); + } + return status; +} + +napi_status SetValueUnsignedInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result) +{ + napi_value value; + napi_status status = napi_create_uint32(env, intValue, &value); + if (status != napi_ok) { + HILOGE("Set value create unsigned int32 error! field: %{public}s", fieldStr); + return status; + } + status = napi_set_named_property(env, result, fieldStr, value); + if (status != napi_ok) { + HILOGE("Set unsigned int32 named property error! field: %{public}s", fieldStr); + } + return status; +} + +napi_status SetValueInt64(const napi_env& env, const char* fieldStr, const int64_t intValue, napi_value& result) +{ + napi_value value; + napi_status status = napi_create_int64(env, intValue, &value); + if (status != napi_ok) { + HILOGE("Set value create int64 error! field: %{public}s", fieldStr); + return status; + } + status = napi_set_named_property(env, result, fieldStr, value); + if (status != napi_ok) { + HILOGE("Set int64 named property error! field: %{public}s", fieldStr); + } + return status; +} + +napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result) +{ + napi_value value; + napi_status status = napi_get_boolean(env, boolvalue, &value); + if (status != napi_ok) { + HILOGE("Set value create boolean error! field: %{public}s", fieldStr); + return status; + } + status = napi_set_named_property(env, result, fieldStr, value); + if (status != napi_ok) { + HILOGE("Set boolean named property error! field: %{public}s", fieldStr); + } + return status; +} + +static napi_value InitAsyncCallBackEnv(const napi_env& env, AsyncContext *asyncContext, + const size_t argc, const napi_value *argv, const size_t nonCallbackArgNum) +{ + for (size_t i = nonCallbackArgNum; i != argc; ++i) { + napi_valuetype valuetype; + NAPI_CALL(env, napi_typeof(env, argv[i], &valuetype)); + NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected."); + napi_create_reference(env, argv[i], 1, &asyncContext->callback[i - nonCallbackArgNum]); + } + return nullptr; +} + +static napi_value InitAsyncPromiseEnv(const napi_env& env, AsyncContext *asyncContext, napi_value& promise) +{ + napi_deferred deferred; + NAPI_CALL(env, napi_create_promise(env, &deferred, &promise)); + asyncContext->deferred = deferred; + return nullptr; +} + +static napi_value DoCallBackAsyncWork(const napi_env& env, AsyncContext *asyncContext) +{ + napi_create_async_work( + env, + nullptr, + asyncContext->resourceName, + [](napi_env env, void* data) { + if (data == nullptr) { + HILOGE("Async data parameter is null"); + return; + } + AsyncContext *context = static_cast(data); + context->executeFunc(context); + }, + [](napi_env env, napi_status status, void* data) { + if (data == nullptr) { + HILOGE("Async data parameter is null"); + return; + } + AsyncContext *context = static_cast(data); + napi_value undefine; + napi_get_undefined(env, &undefine); + napi_value callback; + context->completeFunc(data); + constexpr int ARGS_TWO = 2; + napi_value result[ARGS_TWO] = {nullptr}; + napi_create_uint32(env, context->errorCode, &result[0]); + result[1] = context->result; + if (context->errorCode == ERR_CODE_SUCCESS) { + napi_get_reference_value(env, context->callback[0], &callback); + napi_call_function(env, nullptr, callback, ARGS_TWO, result, &undefine); + } else { + if (context->callback[1]) { + napi_get_reference_value(env, context->callback[1], &callback); + napi_call_function(env, nullptr, callback, ARGS_TWO, result, &undefine); + } else { + HILOGE("Get callback func[1] is null"); + } + } + if (context->callback[0] != nullptr) { + napi_delete_reference(env, context->callback[0]); + } + if (context->callback[1] != nullptr) { + napi_delete_reference(env, context->callback[1]); + } + napi_delete_async_work(env, context->work); + delete context; + }, + (void *)asyncContext, + &asyncContext->work); + NAPI_CALL(env, napi_queue_async_work(env, asyncContext->work)); + return UndefinedNapiValue(env); +} + +static napi_value DoPromiseAsyncWork(const napi_env& env, AsyncContext *asyncContext) +{ + napi_create_async_work( + env, + nullptr, + asyncContext->resourceName, + [](napi_env env, void *data) { + if (data == nullptr) { + HILOGE("Async data parameter is null"); + return; + } + AsyncContext *context = static_cast(data); + context->executeFunc(context); + }, + [](napi_env env, napi_status status, void *data) { + if (data == nullptr) { + HILOGE("Async data parameter is null"); + return; + } + AsyncContext *context = static_cast(data); + context->completeFunc(data); + if (context->errorCode == ERR_CODE_SUCCESS) { + napi_resolve_deferred(context->env, context->deferred, context->result); + } else { + napi_reject_deferred(context->env, context->deferred, context->result); + } + napi_delete_async_work(env, context->work); + delete context; + }, + (void *)asyncContext, + &asyncContext->work); + napi_queue_async_work(env, asyncContext->work); + return UndefinedNapiValue(env); +} + +napi_value DoAsyncWork(const napi_env& env, AsyncContext *asyncContext, + const size_t argc, const napi_value *argv, const size_t nonCallbackArgNum) +{ + if (argc > nonCallbackArgNum) { + InitAsyncCallBackEnv(env, asyncContext, argc, argv, nonCallbackArgNum); + return DoCallBackAsyncWork(env, asyncContext); + } else { + napi_value promise; + InitAsyncPromiseEnv(env, asyncContext, promise); + DoPromiseAsyncWork(env, asyncContext); + return promise; + } +} + +bool ParseString(napi_env env, std::string ¶m, napi_value args) { + napi_valuetype valuetype; + napi_typeof(env, args, &valuetype); + + HILOGI("param=%{public}d.", valuetype); + if(valuetype != napi_string) { + HILOGE("Wrong argument type. String expected."); + return false; + } + size_t size = 0; + + if (napi_get_value_string_utf8(env, args, nullptr, 0, &size) != napi_ok) { + HILOGE("can not get string size"); + param = ""; + return false; + } + param.reserve(size + 1); + param.resize(size); + if (napi_get_value_string_utf8(env, args, param.data(), (size + 1), &size) != napi_ok) { + HILOGE("can not get string value"); + param = ""; + return false; + } + return true; +} +} // namespace ConnectedTag +} // namespace OHOS diff --git a/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_utils.h b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_utils.h new file mode 100755 index 0000000..6cc35c4 --- /dev/null +++ b/interfaces/kits/native_cpp/napi/connected_tag/nfc_napi_utils.h @@ -0,0 +1,99 @@ +/* + * 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 NFC_NAPI_UTILS_H_ +#define NFC_NAPI_UTILS_H_ + +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace ConnectedTag { +class TraceFuncCall final { +public: + TraceFuncCall(std::string funcName); + + TraceFuncCall() = delete; + + ~TraceFuncCall(); + +private: + std::string m_funcName; + std::chrono::steady_clock::time_point m_startTime; + bool m_isTrace = true; +}; + +#define TRACE_FUNC_CALL TraceFuncCall func(__func__) +#define TRACE_FUNC_CALL_NAME(name) TraceFuncCall funcName(name) + +constexpr int ERR_CODE_SUCCESS = 0; + +class AsyncContext { +public: + napi_env env; + napi_async_work work; + napi_deferred deferred; + napi_ref callback[2] = { 0 }; + std::function executeFunc; + std::function completeFunc; + napi_value resourceName; + napi_value result; + int errorCode; + + AsyncContext(napi_env e, napi_async_work w = nullptr, napi_deferred d = nullptr) + { + env = e; + work = w; + deferred = d; + executeFunc = nullptr; + completeFunc = nullptr; + result = nullptr; + errorCode = ERR_CODE_SUCCESS; + } + + AsyncContext() = delete; + + virtual ~AsyncContext() + { + } +}; + +napi_value UndefinedNapiValue(const napi_env& env); +napi_value JsObjectToString(const napi_env& env, const napi_value& object, + const char* fieldStr, const int bufLen, std::string& fieldRef); +napi_value JsObjectToInt(const napi_env& env, const napi_value& object, const char* fieldStr, int& fieldRef); +napi_value JsObjectToBool(const napi_env& env, const napi_value& object, const char* fieldStr, bool& fieldRef); +napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result); +napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result); +napi_status SetValueUnsignedInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result); +napi_status SetValueInt64(const napi_env& env, const char* fieldStr, const int64_t intValue, napi_value& result); +napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolValue, napi_value& result); +napi_value DoAsyncWork(const napi_env& env, AsyncContext *asyncContext, + const size_t argc, const napi_value *argv, const size_t nonCallbackArgNum); +bool ParseString(napi_env env, std::string ¶m, napi_value args); + +enum class SecTypeJs { + SEC_TYPE_INVALID = 0, /* Invalid security type */ + SEC_TYPE_OPEN = 1, /* Open */ + SEC_TYPE_WEP = 2, /* Wired Equivalent Privacy (WEP) */ + SEC_TYPE_PSK = 3, /* Pre-shared key (PSK) */ + SEC_TYPE_SAE = 4, /* Simultaneous Authentication of Equals (SAE) */ +}; +} // namespace ConnectedTag +} // namespace OHOS + +#endif diff --git a/sa_profile/connected_tag/1140.xml b/sa_profile/connected_tag/1140.xml new file mode 100755 index 0000000..aad9fe6 --- /dev/null +++ b/sa_profile/connected_tag/1140.xml @@ -0,0 +1,27 @@ + + + + nfc_connected_tag_service + + 1140 + libnfc_connected_tag_service.z.so + + + true + false + 1 + + diff --git a/sa_profile/connected_tag/BUILD.gn b/sa_profile/connected_tag/BUILD.gn new file mode 100755 index 0000000..f72ddfc --- /dev/null +++ b/sa_profile/connected_tag/BUILD.gn @@ -0,0 +1,20 @@ +# 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("//build/ohos/sa_profile/sa_profile.gni") + +ohos_sa_profile("connected_tag_profile") { + sources = [ "1140.xml" ] + + part_name = "nfc_connected_tag" +} diff --git a/services/connected_tag/BUILD.gn b/services/connected_tag/BUILD.gn new file mode 100755 index 0000000..3ff3805 --- /dev/null +++ b/services/connected_tag/BUILD.gn @@ -0,0 +1,50 @@ +# 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("//build/ohos.gni") +import("//build/ohos_var.gni") + +ROOT = "//foundation/communication/nfc/services/connected_tag" + +ohos_shared_library("nfc_connected_tag_service") { + include_dirs = [ + "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base/interfaces", + "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base/include", + "$ROOT/src/hardware/include", + "include", + ] + + sources = [ + "src/connected_tag_session_stub.cpp", + "src/connected_tag_service_impl.cpp", + "src/connected_tag_callback_proxy.cpp", + ] + + deps = [ + "$ROOT/src/hardware:connected_tag_hdi_adapter", + "$ROOT/etc/init:etc", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//utils/native/base:utils", + ] + + external_deps = [ + "hisysevent_native:libhisysevent", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core" + ] + + part_name = "nfc_connected_tag" + subsystem_name = "communication" +} diff --git a/services/connected_tag/etc/init/BUILD.gn b/services/connected_tag/etc/init/BUILD.gn new file mode 100755 index 0000000..0ab93df --- /dev/null +++ b/services/connected_tag/etc/init/BUILD.gn @@ -0,0 +1,29 @@ +# 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("//build/ohos.gni") +import("//build/ohos_var.gni") + +group("etc") { + deps = [ + ":nfc_connected_tag_service.rc", + ] +} + +ohos_prebuilt_etc("nfc_connected_tag_service.rc") { + source = "nfc_connected_tag_service.cfg" + + relative_install_dir = "init" + part_name = "nfc_connected_tag" + subsystem_name = "communication" +} diff --git a/services/connected_tag/etc/init/nfc_connected_tag_service.cfg b/services/connected_tag/etc/init/nfc_connected_tag_service.cfg new file mode 100755 index 0000000..d1909f4 --- /dev/null +++ b/services/connected_tag/etc/init/nfc_connected_tag_service.cfg @@ -0,0 +1,17 @@ +{ + "jobs" : [{ + "name" : "post-fs-data", + "cmds" : [ + "mkdir /data/nfc_connected_tag", + "start nfc_connected_tag_service" + ] + } + ], + "services" : [{ + "name" : "nfc_connected_tag_service", + "path" : ["/system/bin/sa_main", "/system/profile/nfc_connected_tag_service.xml"], + "uid" : "root", + "gid" : ["root", "shell"] + } + ] +} diff --git a/services/connected_tag/etc/init/nfc_connected_tag_service.rc b/services/connected_tag/etc/init/nfc_connected_tag_service.rc new file mode 100755 index 0000000..a91f4ed --- /dev/null +++ b/services/connected_tag/etc/init/nfc_connected_tag_service.rc @@ -0,0 +1,23 @@ +# 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. + +on post-fs-data + mkdir /data/nfc_connected_tag + start nfc_connected_tag_service + +service nfc_connected_tag_service /system/bin/sa_main /system/profile/nfc_connected_tag_service.xml + class z_core + user root + group root shell + seclabel u:r:nfc_connected_tag_service:s0 + diff --git a/services/connected_tag/include/connected_tag_callback_proxy.h b/services/connected_tag/include/connected_tag_callback_proxy.h new file mode 100755 index 0000000..702e5a3 --- /dev/null +++ b/services/connected_tag/include/connected_tag_callback_proxy.h @@ -0,0 +1,35 @@ +/* + * 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 OHOS_CONNECTED_TAG_CALLBACK_PROXY_H +#define OHOS_CONNECTED_TAG_CALLBACK_PROXY_H + +#include "iconnected_tag_callback.h" +#include "iremote_proxy.h" +#include "ipc_cmd.h" + +namespace OHOS { +namespace ConnectedTag { +class ConnectedTagCallBackProxy : public IRemoteProxy { +public: + explicit ConnectedTagCallBackProxy(const sptr &remote); + virtual ~ConnectedTagCallBackProxy() {} + + void OnNotify(int nfcRfState) override; +private: + static inline BrokerDelegator g_delegator; +}; +} // namespace ConnectedTag +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/connected_tag/include/connected_tag_service_impl.h b/services/connected_tag/include/connected_tag_service_impl.h new file mode 100755 index 0000000..7fbfea6 --- /dev/null +++ b/services/connected_tag/include/connected_tag_service_impl.h @@ -0,0 +1,63 @@ +/* + * 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 OHOS_NFC_CONNECTED_TAG_SERVICE_IMPL_H +#define OHOS_NFC_CONNECTED_TAG_SERVICE_IMPL_H + +#include "system_ability.h" +#include "connected_tag_session_stub.h" +#include "iremote_object.h" +#include "error_code.h" + +namespace OHOS { +namespace ConnectedTag { +enum ServiceRunningState { + STATE_NOT_START, + STATE_RUNNING +}; +class NfcConnectedTagServiceImpl : public SystemAbility, public TagSessionStub { +DECLARE_SYSTEM_ABILITY(NfcConnectedTagServiceImpl); +public: + NfcConnectedTagServiceImpl(); + virtual ~NfcConnectedTagServiceImpl(); + + static sptr GetInstance(); + + void OnStart() override; + void OnStop() override; + + ErrCode Init() override; + + ErrCode Uninit() override; + + ErrCode ReadNdefTag(std::string &response) override; + + ErrCode WriteNdefTag(std::string data) override; + + ErrCode RegListener(const sptr &callback) override; + + ErrCode UnregListener(const sptr &callback) override; +private: + bool ServiceInit(); + +private: + static sptr g_instance; + static std::mutex g_instanceLock; + bool mPublishFlag; + ServiceRunningState mState; +}; +} // namespace OHOS_NFC_CONNECTED_TAG_SERVICE_IMPL_H +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/connected_tag/include/connected_tag_session_stub.h b/services/connected_tag/include/connected_tag_session_stub.h new file mode 100755 index 0000000..e3bbf3c --- /dev/null +++ b/services/connected_tag/include/connected_tag_session_stub.h @@ -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. + */ +#ifndef OHOS_TAG_SESSION_STUB_H +#define OHOS_TAG_SESSION_STUB_H + +#include +#include "i_tag_session.h" +#include "iremote_stub.h" +#include +#include + +namespace OHOS { +namespace ConnectedTag { +class TagSessionStub: public IRemoteStub { +public: + TagSessionStub(); + virtual ~TagSessionStub(); + + using handleFunc = void (TagSessionStub::*)(uint32_t code, MessageParcel &data, MessageParcel &reply); + using HandleFuncMap = std::map; + + virtual int OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; +private: + void InitHandleMap(); + void OnInit(uint32_t code, MessageParcel &data, MessageParcel &reply); + void OnUninit(uint32_t code, MessageParcel &data, MessageParcel &reply); + void OnReadNdefTag(uint32_t code, MessageParcel &data, MessageParcel &reply); + void OnWriteNdefTag(uint32_t code, MessageParcel &data, MessageParcel &reply); +private: + HandleFuncMap handleFuncMap; +}; +} // namespace Nfc_Connected_Tag +} // namespace OHOS +#endif diff --git a/services/connected_tag/src/connected_tag_callback_proxy.cpp b/services/connected_tag/src/connected_tag_callback_proxy.cpp new file mode 100755 index 0000000..6d1502e --- /dev/null +++ b/services/connected_tag/src/connected_tag_callback_proxy.cpp @@ -0,0 +1,46 @@ +/* + * 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 "connected_tag_callback_proxy.h" +#include "ipc_cmd.h" +#include "log.h" + +namespace OHOS { +namespace ConnectedTag { +ConnectedTagCallBackProxy::ConnectedTagCallBackProxy(const sptr &impl) + : IRemoteProxy(impl) +{} + +void ConnectedTagCallBackProxy::OnNotify(int nfcRfState) +{ + HILOGD("ConnectedTagCallBackProxy::OnNotify"); + MessageOption option; + MessageParcel data; + MessageParcel reply; + data.WriteInt32(0); + data.WriteInt32(nfcRfState); + + int error = Remote()->SendRequest(CMD_ON_NOTIFY, data, reply, option); + if (error != ERR_NONE) { + HILOGE("Set Attr(%{public}d) failed,error code is %{public}d", CMD_ON_NOTIFY, error); + return; + } + int exception = reply.ReadInt32(); + if (exception) { + HILOGE("notify CMD_ON_NOTIFY state change failed!"); + } + return; +} +} // namespace ConnectedTag +} // namespace OHOS \ No newline at end of file diff --git a/services/connected_tag/src/connected_tag_service_impl.cpp b/services/connected_tag/src/connected_tag_service_impl.cpp new file mode 100755 index 0000000..7560ed7 --- /dev/null +++ b/services/connected_tag/src/connected_tag_service_impl.cpp @@ -0,0 +1,126 @@ +/* + * 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 "connected_tag_service_impl.h" +#include "error_code.h" +#include "connected_tag_hdi_adapter.h" +#include "ipc_cmd.h" +#include "log.h" + +namespace OHOS { +namespace ConnectedTag { +std::mutex NfcConnectedTagServiceImpl::g_instanceLock; +sptr NfcConnectedTagServiceImpl::g_instance; +const bool REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(NfcConnectedTagServiceImpl::GetInstance().GetRefPtr()); + +sptr NfcConnectedTagServiceImpl::GetInstance() +{ + if (g_instance == nullptr) { + std::lock_guard autoLock(g_instanceLock); + if (g_instance == nullptr) { + auto service = new (std::nothrow) NfcConnectedTagServiceImpl; + g_instance = service; + } + } + return g_instance; +} + +NfcConnectedTagServiceImpl::NfcConnectedTagServiceImpl() + : SystemAbility(NFC_CONNECTED_TAG_ABILITY_ID, true), mPublishFlag(false), mState(ServiceRunningState::STATE_NOT_START) +{ +} + +NfcConnectedTagServiceImpl::~NfcConnectedTagServiceImpl() +{ +} + +void NfcConnectedTagServiceImpl::OnStart() +{ + HILOGI("NfcConnectedTagServiceImpl::OnStart() in"); + if (mState == ServiceRunningState::STATE_RUNNING) { + HILOGI("Service has already started."); + return; + } + if (!ServiceInit()) { + HILOGE("Failed to init service"); + OnStop(); + return; + } + mState = ServiceRunningState::STATE_RUNNING; + HILOGI("Start service!"); +} + +void NfcConnectedTagServiceImpl::OnStop() +{ + HILOGI("NfcConnectedTagServiceImpl::OnStop() in"); + mState = ServiceRunningState::STATE_NOT_START; + mPublishFlag = false; + HILOGI("Stop service!"); +} + +bool NfcConnectedTagServiceImpl::ServiceInit() +{ + HILOGI("NfcConnectedTagServiceImpl::ServiceInit() in!"); + if (!mPublishFlag) { + bool ret = Publish(NfcConnectedTagServiceImpl::GetInstance()); + if (!ret) { + HILOGE("Failed to publish service!"); + return false; + } + mPublishFlag = true; + } + return true; +} + +ErrCode NfcConnectedTagServiceImpl::Init() +{ + HILOGE("NfcConnectedTagServiceImpl:Init() in!"); + if (NfcHdiAdapter::GetInstance().Init() == 0) { + return NFC_OPT_SUCCESS; + } + return NFC_OPT_FAILED; +} + +ErrCode NfcConnectedTagServiceImpl::Uninit() +{ + if (NfcHdiAdapter::GetInstance().Uninit() == 0) { + return NFC_OPT_SUCCESS; + } + return NFC_OPT_FAILED; +} + +ErrCode NfcConnectedTagServiceImpl::ReadNdefTag(std::string &response) +{ + response = NfcHdiAdapter::GetInstance().ReadNdefTag(); + return NFC_OPT_SUCCESS; +} + +ErrCode NfcConnectedTagServiceImpl::WriteNdefTag(std::string data) +{ + if (NfcHdiAdapter::GetInstance().WriteNdefTag(data) == 0) { + return NFC_OPT_SUCCESS; + } + return NFC_OPT_FAILED; +} + +ErrCode NfcConnectedTagServiceImpl::RegListener(const sptr &callback) +{ + return NFC_OPT_SUCCESS; +} +ErrCode NfcConnectedTagServiceImpl::UnregListener(const sptr &callback) +{ + return NFC_OPT_SUCCESS; +} +} // namespace ConnectedTag +} // namespace OHOS \ No newline at end of file diff --git a/services/connected_tag/src/connected_tag_session_stub.cpp b/services/connected_tag/src/connected_tag_session_stub.cpp new file mode 100755 index 0000000..2d2ce07 --- /dev/null +++ b/services/connected_tag/src/connected_tag_session_stub.cpp @@ -0,0 +1,89 @@ +/* + * 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 "i_tag_session.h" +#include "log.h" +#include "error_code.h" +#include "ipc_cmd.h" +#include "connected_tag_session_stub.h" + +namespace OHOS { +namespace ConnectedTag { +TagSessionStub::TagSessionStub() +{ + HILOGI("TagSessionStub: TagSessionStub called."); + InitHandleMap(); +} +TagSessionStub::~TagSessionStub() +{} +void TagSessionStub::InitHandleMap() +{ + handleFuncMap[NFC_SVR_CMD_INIT] = &TagSessionStub::OnInit; + handleFuncMap[NFC_SVR_CMD_UNINIT] = &TagSessionStub::OnUninit; + handleFuncMap[NFC_SVR_CMD_READ_NDEF_TAG] = &TagSessionStub::OnReadNdefTag; + handleFuncMap[NFC_SVR_CMD_WRITE_NDEF_TAG] = &TagSessionStub::OnWriteNdefTag; +} +int TagSessionStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + int exception = data.ReadInt32(); + if (exception) { + return NFC_OPT_FAILED; + } + + HandleFuncMap::iterator iter = handleFuncMap.find(code); + if (iter == handleFuncMap.end()) { + HILOGW("not find function to deal, code %{public}u", code); + reply.WriteInt32(0); + reply.WriteInt32(NFC_OPT_NOT_SUPPORTED); + } else { + (this->*(iter->second))(code, data, reply); + return NFC_OPT_SUCCESS; + } + HILOGW("TagSessionStub::OnRemoteRequest, default case, need check."); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} +void TagSessionStub::OnInit(uint32_t code, MessageParcel &data, MessageParcel &reply) +{ + HILOGI("run %{public}s code %{public}u, datasize %{public}zu", __func__, code, data.GetRawDataSize()); + ErrCode ret = Init(); + reply.WriteInt32(0); + reply.WriteInt32(ret); +} +void TagSessionStub::OnUninit(uint32_t code, MessageParcel &data, MessageParcel &reply) +{ + HILOGI("run %{public}s code %{public}u, datasize %{public}zu", __func__, code, data.GetRawDataSize()); + ErrCode ret = Uninit(); + reply.WriteInt32(0); + reply.WriteInt32(ret); +} +void TagSessionStub::OnReadNdefTag(uint32_t code, MessageParcel &data, MessageParcel &reply) +{ + HILOGI("run %{public}s code %{public}u, datasize %{public}zu", __func__, code, data.GetRawDataSize()); + std::string response; + ReadNdefTag(response); + reply.WriteInt32(0); + reply.WriteString(response); +} +void TagSessionStub::OnWriteNdefTag(uint32_t code, MessageParcel &data, MessageParcel &reply) +{ + std::string dataToWrite = data.ReadString(); + HILOGI("run %{public}s datasize %{public}zu, str = %{public}s, len = %{public}d", + __func__, data.GetRawDataSize(), dataToWrite.c_str(), dataToWrite.length()); + + ErrCode ret = WriteNdefTag(dataToWrite); + reply.WriteInt32(0); + reply.WriteInt32(ret); +} +} // namespace ConnectedTag +} // namespace OHOS \ No newline at end of file diff --git a/services/connected_tag/src/hardware/BUILD.gn b/services/connected_tag/src/hardware/BUILD.gn new file mode 100755 index 0000000..de49bf1 --- /dev/null +++ b/services/connected_tag/src/hardware/BUILD.gn @@ -0,0 +1,55 @@ +# 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("//build/ohos.gni") +import("//drivers/adapter/uhdf2/uhdf.gni") + +ohos_shared_library("connected_tag_hdi_adapter") { + include_dirs = [ + "include", + "//foundation/communication/nfc/interfaces/kits/native_cpp/connected_tag_base/include", + "//drivers/peripheral/nfc/connected_tag/v1_0/client", + ] + + cflags = [ "-fPIC" ] + + sources = [ + "src/connected_tag_hdi_adapter.cpp", + ] + + deps = [ + "$hdf_uhdf_path/hdi:libhdi", + "$hdf_uhdf_path/host:libhdf_host", + "$hdf_uhdf_path/ipc:libhdf_ipc_adapter", + "$hdf_uhdf_path/utils:libhdf_utils", + "//utils/native/base:utils", + "//utils/native/base:utilsecurec_shared", + ] + + if (is_standard_system) { + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "connected_tag_device_driver:connected_tag_client", + ] + } else { + external_deps = [ + "hilog:libhilog", + "ipc:ipc_core", + "connected_tag_device_driver:connected_tag_client", + ] + } + + subsystem_name = "communication" + part_name = "nfc_connected_tag" +} diff --git a/services/connected_tag/src/hardware/include/connected_tag_hdi_adapter.h b/services/connected_tag/src/hardware/include/connected_tag_hdi_adapter.h new file mode 100755 index 0000000..72b728e --- /dev/null +++ b/services/connected_tag/src/hardware/include/connected_tag_hdi_adapter.h @@ -0,0 +1,35 @@ +/* + * 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 +namespace OHOS { +namespace ConnectedTag { +class NfcHdiAdapter { +public: + ~NfcHdiAdapter(); + static NfcHdiAdapter &GetInstance(); + + int32_t Init(); + + int32_t Uninit(); + + std::string ReadNdefTag(); + + int32_t WriteNdefTag(std::string data); +private: + NfcHdiAdapter(); +}; +} // namespace Nfc_Connected_Tag +} // namespace OHOS diff --git a/services/connected_tag/src/hardware/src/connected_tag_hdi_adapter.cpp b/services/connected_tag/src/hardware/src/connected_tag_hdi_adapter.cpp new file mode 100755 index 0000000..f2ad3c8 --- /dev/null +++ b/services/connected_tag/src/hardware/src/connected_tag_hdi_adapter.cpp @@ -0,0 +1,81 @@ +/* + * 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 "connected_tag_hdi_adapter.h" +#include "log.h" +#include "connected_tag_proxy.h" + +namespace OHOS { +namespace ConnectedTag { +static sptr g_iConnectedTagHdi; +NfcHdiAdapter::NfcHdiAdapter() +{ + HILOGI("NfcHdiAdapter: NfcHdiAdapter called."); + sptr nfcHdi = ohos::hardware::nfc::v1_0::IConnectedTagHdi::Get(); + if (nfcHdi == nullptr) + { + HILOGE("NfcHdiAdapter: IConnectedTagHdi::Get failed."); + } + g_iConnectedTagHdi = nfcHdi; +} + +NfcHdiAdapter::~NfcHdiAdapter() +{ + HILOGI("NfcHdiAdapter: ~NfcHdiAdapter called."); +} +NfcHdiAdapter &NfcHdiAdapter::GetInstance() +{ + static NfcHdiAdapter instance; + return instance; +} +int32_t NfcHdiAdapter::Init() +{ + HILOGI("NfcHdiAdapter::Init() starts"); + if (g_iConnectedTagHdi != nullptr) + { + g_iConnectedTagHdi->Init(); + } + return 0; +} +int32_t NfcHdiAdapter::Uninit() +{ + HILOGI("NfcHdiAdapter::Uninit() starts"); + if (g_iConnectedTagHdi != nullptr) + { + g_iConnectedTagHdi->Uninit(); + } + return 0; +} +std::string NfcHdiAdapter::ReadNdefTag() +{ + HILOGI("NfcHdiAdapter::ReadNdefTag() starts"); + std::string resp = ""; + if (g_iConnectedTagHdi != nullptr) + { + resp = g_iConnectedTagHdi->ReadNdefTag(); + HILOGI("NfcHdiAdapter::ReadNdefTag() resp = %{public}s", resp.c_str()); + } + return resp; +} +int32_t NfcHdiAdapter::WriteNdefTag(std::string data) +{ + HILOGI("NfcHdiAdapter::WriteNdefTag() starts data = %{public}s", data.c_str()); + if (g_iConnectedTagHdi != nullptr) + { + g_iConnectedTagHdi->WriteNdefTag(data); + } + return 0; +} +} // namespace ConnectedTag +} // namespace OHOS \ No newline at end of file