1 /*
2 * Copyright (C) 2024 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
16 #include "nfc_notification.h"
17
18 #include <map>
19
20 #include "cJSON.h"
21 #include "file_ex.h"
22 #include "locale_config.h"
23 #include "locale_info.h"
24 #include "loghelper.h"
25 #include "nfc_sdk_common.h"
26 #include "securec.h"
27 #include "want_agent_helper.h"
28 #include "want_agent_info.h"
29
30 #ifdef DEBUG
31 #undef DEBUG
32 #endif
33 #include "notification_helper.h"
34
35 namespace OHOS {
36 namespace NFC {
37 namespace TAG {
38 static std::string g_sysLanguage = "";
39 static std::map<std::string, std::string> g_resourceMap;
40 static std::mutex g_callbackMutex {};
41 static NfcNtfCallback g_ntfCallback = nullptr;
42
43 class NfcNotificationSubscriber : public Notification::NotificationSubscriber {
OnConnected()44 void OnConnected() {}
OnDisconnected()45 void OnDisconnected() {}
OnUpdate(const std::shared_ptr<Notification::NotificationSortingMap> & sortingMap)46 void OnUpdate(const std::shared_ptr<Notification::NotificationSortingMap> &sortingMap) {}
OnDoNotDisturbDateChange(const std::shared_ptr<Notification::NotificationDoNotDisturbDate> & date)47 void OnDoNotDisturbDateChange(const std::shared_ptr<Notification::NotificationDoNotDisturbDate> &date) {}
OnEnabledNotificationChanged(const std::shared_ptr<Notification::EnabledNotificationCallbackData> & callbackData)48 void OnEnabledNotificationChanged(
49 const std::shared_ptr<Notification::EnabledNotificationCallbackData> &callbackData) {}
OnDied()50 void OnDied() {}
OnCanceled(const std::shared_ptr<OHOS::Notification::Notification> & request,const std::shared_ptr<Notification::NotificationSortingMap> & sortingMap,int deleteReason)51 void OnCanceled(const std::shared_ptr<OHOS::Notification::Notification> &request,
52 const std::shared_ptr<Notification::NotificationSortingMap> &sortingMap, int deleteReason)
53 {
54 int creatorUid = request->GetUid();
55 int notificationId = request->GetId();
56 InfoLog("Oncanceled, creatorUid = %{public}d, notificationId = %{public}d, deleteReason = %{public}d",
57 creatorUid, notificationId, deleteReason);
58
59 std::lock_guard<std::mutex> lock(g_callbackMutex);
60 if (deleteReason == Notification::NotificationConstant::CLICK_REASON_DELETE && g_ntfCallback) {
61 g_ntfCallback(notificationId % OHOS::NFC::TAG::NTF_COUNT_CONSTANT);
62 }
63 }
OnConsumed(const std::shared_ptr<OHOS::Notification::Notification> & notification,const std::shared_ptr<Notification::NotificationSortingMap> & sortingMap)64 void OnConsumed(const std::shared_ptr<OHOS::Notification::Notification> ¬ification,
65 const std::shared_ptr<Notification::NotificationSortingMap> &sortingMap) {}
OnBadgeChanged(const std::shared_ptr<Notification::BadgeNumberCallbackData> & badgeData)66 void OnBadgeChanged(const std::shared_ptr<Notification::BadgeNumberCallbackData> &badgeData) {}
OnBadgeEnabledChanged(const sptr<Notification::EnabledNotificationCallbackData> & callbackData)67 void OnBadgeEnabledChanged(const sptr<Notification::EnabledNotificationCallbackData> &callbackData) {}
OnBatchCanceled(const std::vector<std::shared_ptr<OHOS::Notification::Notification>> & requestList,const std::shared_ptr<Notification::NotificationSortingMap> & sortingMap,int32_t deleteReason)68 void OnBatchCanceled(const std::vector<std::shared_ptr<OHOS::Notification::Notification>> &requestList,
69 const std::shared_ptr<Notification::NotificationSortingMap> &sortingMap, int32_t deleteReason) {}
70 };
71
72 static const auto NOTIFICATION_SUBSCRIBER = NfcNotificationSubscriber();
73
UpdateResourceMap(const std::string & resourcePath)74 static void UpdateResourceMap(const std::string &resourcePath)
75 {
76 InfoLog("Reading resource string from json config.");
77
78 std::string content;
79 LoadStringFromFile(resourcePath, content);
80 cJSON *json = cJSON_Parse(content.c_str());
81 if (json == nullptr) {
82 ErrorLog("json nullptr.");
83 return;
84 }
85
86 cJSON *resJson = cJSON_GetObjectItemCaseSensitive(json, KEY_STRING);
87 if (resJson == nullptr || cJSON_GetArraySize(resJson) > MAX_RES_VEC_LEN) {
88 ErrorLog("fail to parse res json");
89 cJSON_Delete(json);
90 return;
91 }
92
93 g_resourceMap.clear();
94 cJSON *resJsonEach = nullptr;
95 cJSON_ArrayForEach(resJsonEach, resJson) {
96 cJSON *key = cJSON_GetObjectItemCaseSensitive(resJsonEach, KEY_NAME);
97 if (key == nullptr || !cJSON_IsString(key)) {
98 ErrorLog("json param not string");
99 cJSON_Delete(json);
100 return;
101 }
102
103 cJSON *value = cJSON_GetObjectItemCaseSensitive(resJsonEach, KEY_VALUE);
104 if (value == nullptr || !cJSON_IsString(value)) {
105 ErrorLog("json param not string");
106 cJSON_Delete(json);
107 return;
108 }
109
110 g_resourceMap.insert(std::pair<std::string, std::string>(key->valuestring, value->valuestring));
111 }
112 cJSON_Delete(json);
113 }
114
UpdateResourceMapByLanguage()115 static void UpdateResourceMapByLanguage()
116 {
117 std::string curSysLanguage = "zh";
118 OHOS::Global::I18n::LocaleInfo locale(Global::I18n::LocaleConfig::GetSystemLocale());
119 curSysLanguage = locale.GetLanguage();
120 if (g_sysLanguage == curSysLanguage) {
121 DebugLog("same language environment, no need to update resource map.");
122 return;
123 }
124
125 InfoLog("current system language[%{public}s] changes, should update resource map", curSysLanguage.c_str());
126 g_sysLanguage = curSysLanguage;
127
128 if (g_sysLanguage == "en") {
129 UpdateResourceMap(NFC_RES_EN_JSON_FILEPATH);
130 } else {
131 UpdateResourceMap(NFC_RES_DEFAULT_JSON_FILEPATH);
132 }
133 }
134
GetTrafficCardNotificationText(const std::string & cardName,int balance)135 static std::string GetTrafficCardNotificationText(const std::string &cardName, int balance)
136 {
137 char buf[MAX_BUFF_LEN] = {0};
138 int ret = sprintf_s(buf, MAX_BUFF_LEN, g_resourceMap[KEY_TRANSPORT_CARD_NTF_TEXT].c_str(),
139 g_resourceMap[cardName].c_str(), static_cast<float>(balance) / NFC_UNIT_CHANGE_CONSTANT);
140 if (ret <= 0) {
141 ErrorLog("sprintf_s failed, ret[%{public}d]", ret);
142 return "";
143 }
144
145 return std::string(buf);
146 }
147
148 #ifdef NDEF_WIFI_ENABLED
GetWifiNotificationText(const std::string & ssid)149 static std::string GetWifiNotificationText(const std::string &ssid)
150 {
151 char buf[MAX_BUFF_LEN] = {0};
152 int ret = sprintf_s(buf, MAX_BUFF_LEN, g_resourceMap[KEY_NFC_WIFI_NTF_TEXT].c_str(), ssid.c_str());
153 if (ret <= 0) {
154 ErrorLog("sprintf_s failed, ret[%{public}d]", ret);
155 return "";
156 }
157
158 return std::string(buf);
159 }
160 #endif
161
162 #ifdef NDEF_BT_ENABLED
GetBtNotificationText(const std::string & name)163 static std::string GetBtNotificationText(const std::string &name)
164 {
165 char buf[MAX_BUFF_LEN] = {0};
166 int ret = sprintf_s(buf, MAX_BUFF_LEN, g_resourceMap[KEY_NFC_BT_NTF_TEXT].c_str(), name.c_str());
167 if (ret <= 0) {
168 ErrorLog("sprintf_s failed, ret[%{public}d]", ret);
169 return "";
170 }
171
172 return std::string(buf);
173 }
174 #endif
175
SetTitleAndTextForOtherNotificationId(int notificationId,std::shared_ptr<Notification::NotificationNormalContent> nfcContent,const std::string & name,int balance)176 static bool SetTitleAndTextForOtherNotificationId(int notificationId,
177 std::shared_ptr<Notification::NotificationNormalContent> nfcContent, const std::string &name, int balance)
178 {
179 switch (notificationId) {
180 case NFC_TAG_DEFAULT_NTF_ID:
181 if (g_resourceMap.find(KEY_TAG_DEFAULT_NTF_TITLE) != g_resourceMap.end() &&
182 g_resourceMap.find(KEY_TAG_DEFAULT_NTF_TEXT) != g_resourceMap.end()) {
183 nfcContent->SetTitle(g_resourceMap[KEY_TAG_DEFAULT_NTF_TITLE]);
184 nfcContent->SetText(g_resourceMap[KEY_TAG_DEFAULT_NTF_TEXT]);
185 }
186 break;
187 case NFC_BROWSER_NOTIFICATION_ID:
188 if (g_resourceMap.find(KEY_TAG_DEFAULT_NTF_TITLE) != g_resourceMap.end() &&
189 g_resourceMap.find(NFC_OPEN_LINK_TEXT_HEAD) != g_resourceMap.end()) {
190 nfcContent->SetTitle(g_resourceMap[KEY_TAG_DEFAULT_NTF_TITLE]);
191 nfcContent->SetText(g_resourceMap[NFC_OPEN_LINK_TEXT_HEAD] + name);
192 }
193 break;
194 case NFC_HCE_AID_CONFLICTED_ID:
195 if (g_resourceMap.find(KEY_HCE_AID_CONFLICTED_TITLE) != g_resourceMap.end() &&
196 g_resourceMap.find(KEY_HCE_AID_CONFLICTED_TEXT) != g_resourceMap.end()) {
197 nfcContent->SetTitle(g_resourceMap[KEY_HCE_AID_CONFLICTED_TITLE]);
198 nfcContent->SetText(g_resourceMap[KEY_HCE_AID_CONFLICTED_TEXT]);
199 }
200 break;
201 case NFC_NO_HAP_SUPPORTED_NOTIFICATION_ID:
202 if (g_resourceMap.find(KEY_NO_HAP_TITLE) != g_resourceMap.end() &&
203 g_resourceMap.find(KEY_NO_HAP_TEXT) != g_resourceMap.end()) {
204 nfcContent->SetTitle(g_resourceMap[KEY_NO_HAP_TITLE]);
205 nfcContent->SetText(g_resourceMap[KEY_NO_HAP_TEXT]);
206 }
207 break;
208 default:
209 WarnLog("unknown notification ID");
210 return false;
211 }
212 return true;
213 }
214
SetTitleAndText(int notificationId,std::shared_ptr<Notification::NotificationNormalContent> nfcContent,const std::string & name,int balance)215 static bool SetTitleAndText(int notificationId,
216 std::shared_ptr<Notification::NotificationNormalContent> nfcContent, const std::string &name, int balance)
217 {
218 if (nfcContent == nullptr) {
219 ErrorLog("notification normal content nullptr");
220 return false;
221 }
222 UpdateResourceMapByLanguage();
223
224 switch (notificationId) {
225 case NFC_TRANSPORT_CARD_NOTIFICATION_ID:
226 if (g_resourceMap.find(KEY_TRANSPORT_CARD_NTF_TITLE) != g_resourceMap.end() &&
227 g_resourceMap.find(KEY_TRANSPORT_CARD_NTF_TEXT) != g_resourceMap.end() &&
228 g_resourceMap.find(name) != g_resourceMap.end()) {
229 nfcContent->SetTitle(g_resourceMap[KEY_TRANSPORT_CARD_NTF_TITLE]);
230 nfcContent->SetText(GetTrafficCardNotificationText(name, balance));
231 }
232 break;
233 case NFC_WIFI_NOTIFICATION_ID:
234 #ifdef NDEF_WIFI_ENABLED
235 if (g_resourceMap.find(KEY_NFC_WIFI_NTF_TITLE) != g_resourceMap.end() &&
236 g_resourceMap.find(KEY_NFC_WIFI_NTF_TEXT) != g_resourceMap.end()) {
237 nfcContent->SetTitle(g_resourceMap[KEY_NFC_WIFI_NTF_TITLE]);
238 nfcContent->SetText(GetWifiNotificationText(name));
239 }
240 break;
241 #else
242 ErrorLog("nfc wifi notification not supported");
243 return false;
244 #endif
245 case NFC_BT_NOTIFICATION_ID:
246 #ifdef NDEF_BT_ENABLED
247 if (g_resourceMap.find(KEY_NFC_BT_NTF_TITLE) != g_resourceMap.end() &&
248 g_resourceMap.find(KEY_NFC_BT_NTF_TEXT) != g_resourceMap.end()) {
249 nfcContent->SetTitle(g_resourceMap[KEY_NFC_BT_NTF_TITLE]);
250 nfcContent->SetText(GetBtNotificationText(name));
251 }
252 break;
253 #else
254 ErrorLog("nfc bt notification not supported");
255 return false;
256 #endif
257 default:
258 return SetTitleAndTextForOtherNotificationId(notificationId, nfcContent, name, balance);
259 }
260 return true;
261 }
262
GetButtonName(int notificationId)263 static std::string GetButtonName(int notificationId)
264 {
265 switch (notificationId) {
266 case NFC_BT_NOTIFICATION_ID:
267 if (g_resourceMap.find(KEY_NFC_BT_BUTTON_NAME) != g_resourceMap.end()) {
268 return g_resourceMap[KEY_NFC_BT_BUTTON_NAME];
269 }
270 return "";
271 case NFC_WIFI_NOTIFICATION_ID:
272 if (g_resourceMap.find(KEY_NFC_WIFI_BUTTON_NAME) != g_resourceMap.end()) {
273 return g_resourceMap[KEY_NFC_WIFI_BUTTON_NAME];
274 }
275 return "";
276 case NFC_BROWSER_NOTIFICATION_ID:
277 if (g_resourceMap.find(NFC_OPEN_LINK_BUTTON_NAME) != g_resourceMap.end()) {
278 return g_resourceMap[NFC_OPEN_LINK_BUTTON_NAME];
279 }
280 return "";
281 case NFC_NO_HAP_SUPPORTED_NOTIFICATION_ID:
282 if (g_resourceMap.find(KEY_NO_HAP_BUTTON_NAME) != g_resourceMap.end()) {
283 return g_resourceMap[KEY_NO_HAP_BUTTON_NAME];
284 }
285 return "";
286 default:
287 if (g_resourceMap.find(KEY_ACTION_BUTTON_NAME) != g_resourceMap.end()) {
288 return g_resourceMap[KEY_ACTION_BUTTON_NAME];
289 }
290 return "";
291 }
292 }
293
SetActionButton(const std::string & buttonName,Notification::NotificationRequest & request)294 static void SetActionButton(const std::string& buttonName, Notification::NotificationRequest& request)
295 {
296 auto want = std::make_shared<AAFwk::Want>();
297 std::vector<std::shared_ptr<AAFwk::Want>> wants;
298 wants.push_back(want);
299 std::vector<AbilityRuntime::WantAgent::WantAgentConstant::Flags> flags;
300 flags.push_back(AbilityRuntime::WantAgent::WantAgentConstant::Flags::CONSTANT_FLAG);
301 AbilityRuntime::WantAgent::WantAgentInfo wantAgentInfo(
302 0, AbilityRuntime::WantAgent::WantAgentConstant::OperationType::UNKNOWN_TYPE,
303 flags, wants, nullptr
304 );
305 auto wantAgentDeal = AbilityRuntime::WantAgent::WantAgentHelper::GetWantAgent(wantAgentInfo);
306 std::shared_ptr<Notification::NotificationActionButton> actionButtonDeal =
307 Notification::NotificationActionButton::Create(nullptr, buttonName, wantAgentDeal);
308 if (actionButtonDeal == nullptr) {
309 ErrorLog("get notification actionButton nullptr");
310 return;
311 }
312 request.AddActionButton(actionButtonDeal);
313 }
314
GetAutoDeleteTime()315 static int64_t GetAutoDeleteTime()
316 {
317 auto now = std::chrono::system_clock::now();
318 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
319 return duration.count() + NTF_AUTO_DELETE_TIME;
320 }
321
SetBasicOption(Notification::NotificationRequest & request)322 static void SetBasicOption(Notification::NotificationRequest &request)
323 {
324 request.SetCreatorUid(KITS::NFC_MANAGER_SYS_ABILITY_ID);
325 request.SetCreatorBundleName(KITS::NFC_MANAGER_SYS_ABILITY_NAME);
326 request.SetAutoDeletedTime(GetAutoDeleteTime());
327 request.SetTapDismissed(true);
328 request.SetSlotType(OHOS::Notification::NotificationConstant::SlotType::SOCIAL_COMMUNICATION);
329 request.SetNotificationControlFlags(NFC_NTF_CONTROL_FLAG);
330 }
331
GetPixelMap(const std::string & path)332 void NfcNotification::GetPixelMap(const std::string &path)
333 {
334 if (nfcIconPixelMap_ != nullptr) {
335 InfoLog("nfc icon pixel map already exists.");
336 return;
337 }
338
339 if (!std::filesystem::exists(path)) {
340 ErrorLog("nfc icon file path not exists.");
341 nfcIconPixelMap_ = nullptr;
342 return;
343 }
344 uint32_t errorCode = 0;
345 Media::SourceOptions opts;
346 opts.formatHint = "image/png";
347 std::unique_ptr<Media::ImageSource> imageSource = Media::ImageSource::CreateImageSource(path, opts, errorCode);
348 if (imageSource == nullptr) {
349 ErrorLog("imageSource nullptr");
350 nfcIconPixelMap_ = nullptr;
351 return;
352 }
353 Media::DecodeOptions decodeOpts;
354 std::unique_ptr<Media::PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
355 nfcIconPixelMap_ = std::move(pixelMap);
356 }
357
GetInstance()358 NfcNotification& NfcNotification::GetInstance()
359 {
360 static NfcNotification instance;
361 return instance;
362 }
363
NfcNotification()364 NfcNotification::NfcNotification()
365 {
366 InfoLog("NfcNotification constructor enter.");
367 std::lock_guard<std::mutex> lock(mutex_);
368 // only need to subscribe notification once
369 int result = Notification::NotificationHelper::SubscribeNotification(NOTIFICATION_SUBSCRIBER);
370 if (result != ERR_OK) {
371 ErrorLog("fail to subscribe notification");
372 }
373 UpdateResourceMapByLanguage();
374 // initialize the vector with the length of (NFC_NTF_END - NFC_TAG_DEFAULT_NTF_ID)
375 tagNtfCountVec_.resize(NFC_NTF_END - NFC_TAG_DEFAULT_NTF_ID);
376 }
377
~NfcNotification()378 NfcNotification::~NfcNotification()
379 {
380 InfoLog("NfcNotification destructor enter.");
381 // no operation to unsubscribe notification
382 }
383
PublishNfcNotification(int notificationId,const std::string & name,int balance)384 void NfcNotification::PublishNfcNotification(int notificationId, const std::string &name, int balance)
385 {
386 if (notificationId >= NFC_NTF_END || notificationId < NFC_TAG_DEFAULT_NTF_ID) {
387 ErrorLog("invalid notification id.");
388 return;
389 }
390 std::shared_ptr<Notification::NotificationNormalContent> nfcContent =
391 std::make_shared<Notification::NotificationNormalContent>();
392 if (nfcContent == nullptr) {
393 ErrorLog("get notification normal content nullptr");
394 return;
395 }
396 std::lock_guard<std::mutex> lock(mutex_);
397 Notification::NotificationBundleOption bundle(KITS::NFC_MANAGER_SYS_ABILITY_NAME, KITS::NFC_MANAGER_SYS_ABILITY_ID);
398 int lastNtfId = (tagNtfCountVec_[notificationId - NFC_TAG_DEFAULT_NTF_ID]++) * NTF_COUNT_CONSTANT + notificationId;
399 if (tagNtfCountVec_[notificationId - NFC_TAG_DEFAULT_NTF_ID] >= NFC_MAX_NTF_COUNT) {
400 tagNtfCountVec_[notificationId - NFC_TAG_DEFAULT_NTF_ID] = 0;
401 }
402 int currentNtfId = (tagNtfCountVec_[notificationId - NFC_TAG_DEFAULT_NTF_ID]) * NTF_COUNT_CONSTANT + notificationId;
403 int ret = Notification::NotificationHelper::CancelAsBundle(bundle, lastNtfId);
404 // ret value 67108880 represents the notification does not exist
405 InfoLog("Cancel ntf result[%{public}d], last id[%{public}d], current id[%{public}d]", ret, lastNtfId, currentNtfId);
406
407 if (!SetTitleAndText(notificationId, nfcContent, name, balance)) {
408 ErrorLog("error setting title and text");
409 return;
410 }
411
412 std::shared_ptr<Notification::NotificationContent> content =
413 std::make_shared<Notification::NotificationContent>(nfcContent);
414 if (content == nullptr) {
415 ErrorLog("get notification content nullptr");
416 return;
417 }
418
419 Notification::NotificationRequest request;
420 SetBasicOption(request);
421 request.SetNotificationId(currentNtfId);
422 request.SetContent(content);
423
424 GetPixelMap(NFC_ICON_PATH);
425 if (nfcIconPixelMap_ != nullptr) {
426 request.SetLittleIcon(nfcIconPixelMap_);
427 request.SetBadgeIconStyle(Notification::NotificationRequest::BadgeStyle::LITTLE);
428 }
429
430 std::string buttonName = GetButtonName(notificationId);
431 if (!buttonName.empty()) {
432 SetActionButton(buttonName, request);
433 }
434
435 Notification::NotificationHelper::SetNotificationSlotFlagsAsBundle(bundle, NFC_SLOT_CONTROL_FLAG);
436 ret = Notification::NotificationHelper::PublishNotification(request);
437 InfoLog("NFC service publish notification result = %{public}d", ret);
438 }
439
RegNotificationCallback(NfcNtfCallback callback)440 void NfcNotification::RegNotificationCallback(NfcNtfCallback callback)
441 {
442 std::lock_guard<std::mutex> lock(g_callbackMutex);
443 g_ntfCallback = callback;
444 }
445 } // namespace TAG
446 } // namespace NFC
447 } // namespace OHOS
448
RegNotificationCallback(NfcNtfCallback callback)449 void RegNotificationCallback(NfcNtfCallback callback)
450 {
451 OHOS::NFC::TAG::NfcNotification::GetInstance().RegNotificationCallback(callback);
452 }
453
PublishNfcNotification(int notificationId,const std::string & name,int balance)454 void PublishNfcNotification(int notificationId, const std::string &name, int balance)
455 {
456 InfoLog("Publishing nfc tag notification, id [%{public}d]", notificationId);
457 OHOS::NFC::TAG::NfcNotification::GetInstance().PublishNfcNotification(notificationId, name, balance);
458 }