1 /*
2  * Copyright (C) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "tag_dispatcher.h"
16 
17 #include <functional>
18 
19 #include "app_data_parser.h"
20 #include "external_deps_proxy.h"
21 #include "loghelper.h"
22 #include "ndef_har_data_parser.h"
23 #include "ndef_har_dispatch.h"
24 #include "ndef_message.h"
25 #include "nfc_hisysevent.h"
26 #include "nfc_sdk_common.h"
27 #include "tag_ability_dispatcher.h"
28 
29 #ifdef NDEF_WIFI_ENABLED
30 #include "ndef_wifi_data_parser.h"
31 #include "wifi_connection_manager.h"
32 #endif
33 
34 #ifdef NDEF_BT_ENABLED
35 #include "ndef_bt_data_parser.h"
36 #include "bt_connection_manager.h"
37 #endif
38 
39 namespace OHOS {
40 namespace NFC {
41 namespace TAG {
42 #define NDEF_TYPE_NORMAL  1
43 #define NDEF_TYPE_BT      2
44 #define NDEF_TYPE_WIFI    3
45 
46 using OHOS::NFC::KITS::TagTechnology;
47 
TagDispatcher(std::shared_ptr<NFC::NfcService> nfcService)48 TagDispatcher::TagDispatcher(std::shared_ptr<NFC::NfcService> nfcService)
49     : nfcService_(nfcService),
50     lastNdefMsg_(""),
51     ndefCb_(nullptr)
52 {
53     if (nfcService_) {
54         nciTagProxy_ = nfcService_->GetNciTagProxy();
55         if (!nciTagProxy_.expired()) {
56             isodepCardHandler_ = std::make_shared<IsodepCardHandler>(nciTagProxy_);
57             ndefHarDataParser_ = std::make_shared<NdefHarDataParser>(nciTagProxy_);
58         }
59     }
60 }
61 
~TagDispatcher()62 TagDispatcher::~TagDispatcher()
63 {
64 }
65 
RegNdefMsgCb(const sptr<INdefMsgCallback> & callback)66 void TagDispatcher::RegNdefMsgCb(const sptr<INdefMsgCallback> &callback)
67 {
68     ndefCb_ = callback;
69 }
70 
HandleNdefDispatch(uint32_t tagDiscId,std::string & msg)71 bool TagDispatcher::HandleNdefDispatch(uint32_t tagDiscId, std::string &msg)
72 {
73     if (nciTagProxy_.expired()) {
74         ErrorLog("HandleNdefDispatch, nciTagProxy_ expired");
75         return false;
76     }
77     std::string tagUid = nciTagProxy_.lock()->GetTagUid(tagDiscId);
78     int msgType = NDEF_TYPE_NORMAL;
79     std::string ndef = msg;
80     if (ndefCb_ != nullptr) {
81         ndefCbRes_ = ndefCb_->OnNdefMsgDiscovered(tagUid, ndef, msgType);
82     }
83     if (ndefCbRes_) {
84         InfoLog("HandleNdefDispatch, is dispatched by ndefMsg callback");
85         return true;
86     }
87 #ifdef NDEF_BT_ENABLED
88     std::shared_ptr<BtData> btData = NdefBtDataParser::CheckBtRecord(msg);
89     if (btData && btData->isValid_) {
90         msgType = NDEF_TYPE_BT;
91         if (!btData->vendorPayload_.empty() && NdefBtDataParser::IsVendorPayloadValid(btData->vendorPayload_)) {
92             // Bt msg for NdefMsg Callback: bt payload len | bt payload | mac addr | dev name
93             ndef = NfcSdkCommon::IntToHexString(btData->vendorPayload_.length() / HEX_BYTE_LEN);
94             ndef.append(btData->vendorPayload_);
95             ndef.append(btData->macAddrOrg_);
96             ndef.append(NfcSdkCommon::StringToHexString(btData->name_));
97         } else {
98             InfoLog("BT vendor payload invalid");
99             ndef = "";
100         }
101     }
102 #endif
103 #ifdef NDEF_WIFI_ENABLED
104     std::shared_ptr<WifiData> wifiData;
105     if (msgType == NDEF_TYPE_NORMAL) {
106         wifiData = NdefWifiDataParser::CheckWifiRecord(msg);
107         if (wifiData && wifiData->isValid_) {
108             msgType = NDEF_TYPE_WIFI;
109             ndef = wifiData->vendorPayload_;
110         }
111     }
112 #endif
113     InfoLog("HandleNdefDispatch, tagUid = %{public}s, msgType = %{public}d",
114         KITS::NfcSdkCommon::CodeMiddlePart(tagUid).c_str(), msgType);
115     if (ndefCb_ != nullptr) {
116         ndefCbRes_ = ndefCb_->OnNdefMsgDiscovered(tagUid, ndef, msgType);
117     }
118     if (ndefCbRes_) {
119         InfoLog("HandleNdefDispatch, is dispatched by ndefMsg callback");
120         return true;
121     }
122     if (msg.empty()) {
123         ErrorLog("HandleNdefDispatch, ndef msg is empty");
124         return false;
125     }
126 #ifdef NDEF_BT_ENABLED
127     if (msgType == NDEF_TYPE_BT) {
128         BtConnectionManager::GetInstance().Initialize(nfcService_);
129         BtConnectionManager::GetInstance().TryPairBt(btData);
130         return true;
131     }
132 #endif
133 #ifdef NDEF_WIFI_ENABLED
134     if (msgType == NDEF_TYPE_WIFI) {
135         WifiConnectionManager::GetInstance().Initialize(nfcService_);
136         WifiConnectionManager::GetInstance().TryConnectWifi(wifiData);
137         return true;
138     }
139 #endif
140     std::shared_ptr<KITS::TagInfo> tagInfo = GetTagInfoFromTag(tagDiscId);
141     if (ndefHarDataParser_ != nullptr && ndefHarDataParser_->TryNdef(msg, tagInfo)) {
142         return true;
143     }
144     return false;
145 }
146 
HandleTagFound(uint32_t tagDiscId)147 void TagDispatcher::HandleTagFound(uint32_t tagDiscId)
148 {
149     if (nfcService_ == nullptr || nciTagProxy_.expired() || nfcService_->GetNfcPollingManager().expired()) {
150         ErrorLog("HandleTagFound, invalid state.");
151         return;
152     }
153 
154     bool isIsoDep = false;
155     int fieldOnCheckInterval_ = DEFAULT_FIELD_ON_CHECK_DURATION;
156     if (static_cast<int>(nciTagProxy_.lock()->GetConnectedTech(tagDiscId)) ==
157         static_cast<int>(TagTechnology::NFC_ISODEP_TECH)) {
158         fieldOnCheckInterval_ = DEFAULT_ISO_DEP_FIELD_ON_CHECK_DURATION;
159         isIsoDep = true;
160     }
161     DebugLog("HandleTagFound fieldOnCheckInterval_ = %{public}d", fieldOnCheckInterval_);
162 
163     ndefCbRes_ = false;
164     std::string ndefMsg = nciTagProxy_.lock()->FindNdefTech(tagDiscId);
165     std::shared_ptr<KITS::NdefMessage> ndefMessage = KITS::NdefMessage::GetNdefMessage(ndefMsg);
166     KITS::TagInfoParcelable* tagInfo = nullptr;
167     do {
168         if (ndefMessage == nullptr) {
169             if (!nciTagProxy_.lock()->Reconnect(tagDiscId)) {
170                 nciTagProxy_.lock()->Disconnect(tagDiscId);
171                 ErrorLog("HandleTagFound bad connection, tag disconnected");
172                 break;
173             }
174         }
175         lastNdefMsg_ = ndefMsg;
176         nciTagProxy_.lock()->StartFieldOnChecking(tagDiscId, fieldOnCheckInterval_);
177         tagInfo = GetTagInfoParcelableFromTag(tagDiscId);
178         if (nfcService_->GetNfcPollingManager().lock()->IsReaderModeEnabled()) {
179             nfcService_->GetNfcPollingManager().lock()->SendTagToReaderApp(tagInfo);
180             break;
181         }
182         if (nfcService_->GetNfcPollingManager().lock()->IsForegroundEnabled()) {
183             nfcService_->GetNfcPollingManager().lock()->SendTagToForeground(tagInfo);
184             break;
185         }
186         ExternalDepsProxy::GetInstance().RegNotificationCallback(nfcService_);
187         if (HandleNdefDispatch(tagDiscId, ndefMsg)) {
188             break;
189         }
190         PublishTagNotification(tagDiscId, isIsoDep);
191         DispatchTag(tagDiscId);
192         break;
193     } while (0);
194     if (tagInfo != nullptr) {
195         delete tagInfo;
196         tagInfo = nullptr;
197     }
198     StartVibratorOnce();
199 }
200 
StartVibratorOnce()201 void TagDispatcher::StartVibratorOnce()
202 {
203     if (!ndefCbRes_) {
204         ExternalDepsProxy::GetInstance().StartVibratorOnce();
205     }
206 }
HandleTagLost(uint32_t tagDiscId)207 void TagDispatcher::HandleTagLost(uint32_t tagDiscId)
208 {
209     InfoLog("HandleTagLost, tagDiscId: %{public}d", tagDiscId);
210 }
211 
GetTagInfoFromTag(uint32_t tagDiscId)212 std::shared_ptr<KITS::TagInfo> TagDispatcher::GetTagInfoFromTag(uint32_t tagDiscId)
213 {
214     std::vector<int> techList = nciTagProxy_.lock()->GetTechList(tagDiscId);
215     std::string tagUid = nciTagProxy_.lock()->GetTagUid(tagDiscId);
216     std::vector<AppExecFwk::PacMap> tagTechExtras = nciTagProxy_.lock()->GetTechExtrasData(tagDiscId);
217     DebugLog("GetTagInfoFromTag: tag uid = %{public}s, techListLen = %{public}zu, extrasLen = %{public}zu,"
218         "rfID = %{public}d", KITS::NfcSdkCommon::CodeMiddlePart(tagUid).c_str(),
219         techList.size(), tagTechExtras.size(), tagDiscId);
220     return std::make_shared<KITS::TagInfo>(techList, tagTechExtras, tagUid, tagDiscId,
221         nfcService_->GetTagServiceIface());
222 }
223 
GetTagInfoParcelableFromTag(uint32_t tagDiscId)224 KITS::TagInfoParcelable* TagDispatcher::GetTagInfoParcelableFromTag(uint32_t tagDiscId)
225 {
226     std::vector<int> techList = nciTagProxy_.lock()->GetTechList(tagDiscId);
227     std::string tagUid = nciTagProxy_.lock()->GetTagUid(tagDiscId);
228     std::vector<AppExecFwk::PacMap> tagTechExtras = nciTagProxy_.lock()->GetTechExtrasData(tagDiscId);
229     DebugLog("GetTagInfoParcelableFromTag: tag uid = %{public}s, techListLen = %{public}zu, extrasLen = %{public}zu,"
230         "rfID = %{public}d", KITS::NfcSdkCommon::CodeMiddlePart(tagUid).c_str(),
231         techList.size(), tagTechExtras.size(), tagDiscId);
232 
233     // tagInfo should be deleted at where it is used (HandleTagFound)
234     KITS::TagInfoParcelable* tagInfo = new (std::nothrow) KITS::TagInfoParcelable(techList, tagTechExtras,
235         tagUid, tagDiscId, nfcService_->GetTagServiceIface());
236     return tagInfo;
237 }
238 
DispatchTag(uint32_t tagDiscId)239 void TagDispatcher::DispatchTag(uint32_t tagDiscId)
240 {
241     tagInfo_ = GetTagInfoFromTag(tagDiscId);
242     if (tagInfo_ == nullptr) {
243         ErrorLog("DispatchTag: taginfo is null");
244         return;
245     }
246 
247     // select the matched applications, try start ability
248     std::vector<int> techList = nciTagProxy_.lock()->GetTechList(tagDiscId);
249     // Record types of read tags.
250     ExternalDepsProxy::GetInstance().WriteTagFoundHiSysEvent(techList);
251 }
252 
HandleTagDebounce()253 void TagDispatcher::HandleTagDebounce()
254 {
255     DebugLog("HandleTagDebounce, unimplemented...");
256 }
257 
OnNotificationButtonClicked(int notificationId)258 void TagDispatcher::OnNotificationButtonClicked(int notificationId)
259 {
260     InfoLog("notificationId[%{public}d]", notificationId);
261     switch (notificationId) {
262         case NFC_TRANSPORT_CARD_NOTIFICATION_ID: {
263             // start application ability for tag found.
264             if (nfcService_) {
265                 ExternalDepsProxy::GetInstance().DispatchTagAbility(tagInfo_, nfcService_->GetTagServiceIface());
266                 nfcService_->NotifyMessageToVendor(KITS::TAG_DISPATCH_KEY, "");
267             }
268             break;
269         }
270         case NFC_WIFI_NOTIFICATION_ID: {
271 #ifdef NDEF_WIFI_ENABLED
272             if (nfcService_ && nfcService_->eventHandler_) {
273                 nfcService_->eventHandler_->SendEvent(static_cast<uint32_t>(NfcCommonEvent::MSG_WIFI_NTF_CLICKED));
274             }
275 #endif
276             break;
277         }
278         case NFC_BT_NOTIFICATION_ID: {
279 #ifdef NDEF_BT_ENABLED
280             if (nfcService_ && nfcService_->eventHandler_) {
281                 nfcService_->eventHandler_->SendEvent(static_cast<uint32_t>(NfcCommonEvent::MSG_BT_NTF_CLICKED));
282             }
283 #endif
284             break;
285         }
286         case NFC_TAG_DEFAULT_NOTIFICATION_ID:
287             // start application ability for tag found.
288             if (nfcService_) {
289                 ExternalDepsProxy::GetInstance().DispatchTagAbility(tagInfo_, nfcService_->GetTagServiceIface());
290                 nfcService_->NotifyMessageToVendor(KITS::TAG_DISPATCH_KEY, "");
291             }
292             break;
293         case NFC_BROWSER_NOTIFICATION_ID:
294             NdefHarDispatch::GetInstance().OnBrowserOpenLink();
295             break;
296         case NFC_NO_HAP_SUPPORTED_NOTIFICATION_ID:
297             // start AppGallery
298             if (!nciTagProxy_.expired() && nfcService_) {
299                 std::string appGalleryBundleName = nciTagProxy_.lock()->GetVendorAppGalleryBundleName();
300                 ExternalDepsProxy::GetInstance().DispatchAppGallery(nfcService_->GetTagServiceIface(),
301                                                                     appGalleryBundleName);
302             }
303             break;
304         default:
305             WarnLog("unknown notification Id");
306             break;
307     }
308 }
309 
PublishTagNotification(uint32_t tagDiscId,bool isIsoDep)310 void TagDispatcher::PublishTagNotification(uint32_t tagDiscId, bool isIsoDep)
311 {
312     NfcNotificationId notificationId = NFC_TAG_DEFAULT_NOTIFICATION_ID;
313     std::string cardName = "";
314     uint8_t cardIndex = INVALID_CARD_INDEX;
315     int balance = INVALID_BALANCE;
316     if (isIsoDep && isodepCardHandler_ != nullptr) {
317         isodepCardHandler_->InitTransportCardInfo();
318         if (isodepCardHandler_->IsSupportedTransportCard(tagDiscId, cardIndex)) {
319             isodepCardHandler_->GetBalance(tagDiscId, cardIndex, balance);
320             if (balance < 0) {
321                 WarnLog("failed to get card balance.");
322             } else {
323                 isodepCardHandler_->GetCardName(cardIndex, cardName);
324                 notificationId = NFC_TRANSPORT_CARD_NOTIFICATION_ID;
325             }
326         }
327     }
328     ExternalDepsProxy::GetInstance().PublishNfcNotification(notificationId, cardName, balance);
329 }
330 }  // namespace TAG
331 }  // namespace NFC
332 }  // namespace OHOS
333