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