• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * WITHstrNum 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 "net_stats_notification.h"
17 #include "net_stats_service.h"
18 
19 #include <string>
20 #include <map>
21 #include <vector>
22 #include <sstream>
23 #include <iomanip>
24 
25 #include "cJSON.h"
26 #include "file_ex.h"
27 #include "locale_config.h"
28 #include "locale_info.h"
29 #include "locale_matcher.h"
30 #include "securec.h"
31 #include "want_agent_helper.h"
32 #include "want_agent_info.h"
33 
34 #include "image_source.h"
35 #include "pixel_map.h"
36 #include "notification_normal_content.h"
37 #include "net_mgr_log_wrapper.h"
38 #include "net_stats_utils.h"
39 #include "core_service_client.h"
40 
41 namespace OHOS {
42 namespace NetManagerStandard {
43 
44 static const int NTF_AUTO_DELETE_TIME = 10000;
45 
46 // static const int COMM_NETSYS_NATIVE_SYS_ABILITY_ID = 1158
47 
48 static const int32_t SLOT_ID_00 = 0;
49 static const int32_t CARD_ID_01 = 1;
50 static const int32_t CARD_ID_02 = 2;
51 
52 static const int32_t UNIT_CONVERT_1024 = 1024;
53 static const int32_t TWO_PRECISION = 2;
54 
55 static const int32_t TWO_CHAR = 2;
56 
57 // keys in json file
58 static constexpr const char *KEY_STRING = "string";
59 static constexpr const char *KEY_NAME = "name";
60 static constexpr const char *KEY_VALUE = "value";
61 static constexpr const char *KEY_NETWORK_MONTH_LIMIT_SINGLE_TITLE = "netstats_excess_monthlimit_notofication_title";
62 static constexpr const char *KEY_NETWORK_MONTH_MARK_SINGLE_TITLE = "netstats_excess_monthmark_notofication_title";
63 static constexpr const char *KEY_NETWORK_DAY_MARK_SINGLE_TITLE = "netstats_excess_daymark_notofication_title";
64 
65 static constexpr const char *KEY_NETWORK_MONTH_LIMIT_DUAL_TITLE = "netstats_excess_monthlimit_notofication_title_sub";
66 static constexpr const char *KEY_NETWORK_MONTH_MARK_DUAL_TITLE = "netstats_excess_monthmark_notofication_title_sub";
67 static constexpr const char *KEY_NETWORK_DAY_MARK_DUAL_TITLE = "netstats_excess_daymark_notofication_title_sub";
68 
69 static constexpr const char *KEY_MONTH_LIMIT_TEXT = "netstats_month_limit_message";
70 static constexpr const char *KEY_MONTH_NOTIFY_TEXT = "netstats_month_notify_message";
71 static constexpr const char *KEY_DAILY_NOTIFY_TEXT = "netstats_daily_notify_message";
72 
73 // NOTE: icon and json path must be absolute path
74 // all locales are listed at: global_i18n-master\global_i18n-master\frameworks\intl\etc\supported_locales.xml
75 static constexpr const char *NETWORK_ICON_PATH = "//system/etc/netmanager_base/resources/network_ic.png";
76 static constexpr const char *DEFAULT_LANGUAGE_NAME_EN = "base";
77 static constexpr const char *LOCALE_TO_RESOURCE_PATH =
78     "//system/etc/netmanager_base/resources/locale_to_resourcePath.json";
79 static constexpr const char *LANGUAGE_RESOURCE_PARENT_PATH =
80     "//system/etc/netmanager_base/resources/";
81 static constexpr const char *LANGUAGE_RESOURCE_CHILD_PATH = "/element/string.json";
82 
83 static std::mutex g_callbackMutex {};
84 static NetMgrStatsLimitNtfCallback g_NetMgrStatsLimitNtfCallback = nullptr;
85 
ParseJSONFile(const std::string & filePath,std::map<std::string,std::string> & container)86 void NetMgrNetStatsLimitNotification::ParseJSONFile(
87     const std::string& filePath, std::map<std::string, std::string>& container)
88 {
89     std::string content;
90     LoadStringFromFile(filePath, content);
91 
92     cJSON *json = cJSON_Parse(content.c_str());
93     if (json == nullptr) {
94         NETMGR_LOG_I("ParseJSONFile: json null. filepath = %{public}s", filePath.c_str());
95         return;
96     }
97 
98     cJSON *resJson = cJSON_GetObjectItemCaseSensitive(json, KEY_STRING);
99 
100     if (resJson == nullptr) {
101         NETMGR_LOG_I("ParseJSONFile: resJson null. filepath = %{public}s", filePath.c_str());
102     } else {
103         container.clear();
104         cJSON *resJsonEach = nullptr;
105         cJSON_ArrayForEach(resJsonEach, resJson) {
106             cJSON *key = cJSON_GetObjectItemCaseSensitive(resJsonEach, KEY_NAME);
107             cJSON *value = cJSON_GetObjectItemCaseSensitive(resJsonEach, KEY_VALUE);
108             container.insert(std::pair<std::string, std::string>(key->valuestring, value->valuestring));
109         }
110     }
111 
112     cJSON_Delete(json);
113 }
114 
UpdateResourceMap()115 void NetMgrNetStatsLimitNotification::UpdateResourceMap()
116 {
117     OHOS::Global::I18n::LocaleInfo locale(Global::I18n::LocaleConfig::GetSystemLocale());
118     std::string curBaseName = locale.GetBaseName();
119     if (localeBaseName == curBaseName) {
120         return;
121     }
122 
123     NETMGR_LOG_I("UpdateResourceMap: change from %{public}s to %{public}s",
124         localeBaseName.c_str(), curBaseName.c_str());
125     localeBaseName = curBaseName;
126 
127     std::string languagePath = DEFAULT_LANGUAGE_NAME_EN;
128     if (languageMap.find(localeBaseName) != languageMap.end()) {
129         languagePath = languageMap[localeBaseName];
130     } else {
131         for (auto& eachPair : languageMap) {
132             OHOS::Global::I18n::LocaleInfo eachLocale(eachPair.first);
133             if (OHOS::Global::I18n::LocaleMatcher::Match(&locale, &eachLocale)) {
134                 languagePath = eachPair.second;
135                 break;
136             }
137         }
138     }
139 
140     std::string resourcePath = LANGUAGE_RESOURCE_PARENT_PATH + languagePath + LANGUAGE_RESOURCE_CHILD_PATH;
141     char tmpPath[PATH_MAX] = { 0 };
142     if (!realpath(resourcePath.c_str(), tmpPath)) {
143         NETMGR_LOG_E("file name is illegal");
144         return;
145     }
146     resourcePath = tmpPath;
147     NETMGR_LOG_I("UpdateResourceMap: resourcePath = %{public}s", resourcePath.c_str());
148     if (!std::filesystem::exists(resourcePath)) {
149         NETMGR_LOG_E("resource path not exist: %{public}s", resourcePath.c_str());
150         return;
151     }
152     /* 从resourcePath中拿到resourceMap */
153     ParseJSONFile(resourcePath, resourceMap);
154 }
155 
GetDayNotificationText()156 std::string NetMgrNetStatsLimitNotification::GetDayNotificationText()
157 {
158     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification::GetDayNotificationText, simId:%{public}d", simId_);
159     if (resourceMap.find(KEY_DAILY_NOTIFY_TEXT) == resourceMap.end() ||
160         resourceMap[KEY_DAILY_NOTIFY_TEXT].find("%s") == std::string::npos) {
161         NETMGR_LOG_E("GetDayNotificationText error");
162         return "";
163     }
164 
165     std::string outText = resourceMap[KEY_DAILY_NOTIFY_TEXT];
166     int32_t simId = simId_;
167     uint64_t traffic = 0;
168     uint16_t dayPercent = 0;
169     bool ret = DelayedSingleton<NetStatsService>::GetInstance()->GetdailyMarkBySimId(simId, dayPercent);
170     DelayedSingleton<NetStatsService>::GetInstance()->GetMonthlyLimitBySimId(simId, traffic);
171     if (!ret) {
172         NETMGR_LOG_E("simId does not exist:: simId %{public}d", simId);
173         return "";
174     }
175 
176     double dailyTraffic = static_cast<double>(traffic) / 100 * dayPercent;
177     std::string num = GetTrafficNum(dailyTraffic);
178     outText = outText.replace(outText.find("%s"), TWO_CHAR, num);
179     NETMGR_LOG_I("NetMgrNetStatsLimitNotification::outText [%{public}s]", outText.c_str());
180     return outText;
181 }
182 
GetMonthNotificationText()183 std::string NetMgrNetStatsLimitNotification::GetMonthNotificationText()
184 {
185     if (resourceMap.find(KEY_MONTH_NOTIFY_TEXT) == resourceMap.end() ||
186         resourceMap[KEY_MONTH_NOTIFY_TEXT].find("%s") == std::string::npos) {
187         NETMGR_LOG_E("GetMonthNotificationText error");
188         return "";
189     }
190     std::string outText = resourceMap[KEY_MONTH_NOTIFY_TEXT];
191 
192     int32_t simId = simId_;
193     uint16_t monUsedPercent = 0;
194     bool ret = DelayedSingleton<NetStatsService>::GetInstance()->GetMonthlyMarkBySimId(simId, monUsedPercent);
195     if (!ret) {
196         NETMGR_LOG_E("simId does not exist:: simId %{public}d", simId);
197         return "";
198     }
199     std::string percent = "‪" + std::to_string(monUsedPercent) + "%" + "‬";
200     outText = outText.replace(outText.find("%s"), TWO_CHAR, percent);
201     NETMGR_LOG_I("GetMonthNotificationText outText [%{public}s]", outText.c_str());
202     return outText;
203 }
204 
GetMonthAlertText()205 std::string NetMgrNetStatsLimitNotification::GetMonthAlertText()
206 {
207     if (resourceMap.find(KEY_MONTH_LIMIT_TEXT) == resourceMap.end() ||
208         resourceMap[KEY_MONTH_LIMIT_TEXT].find("%s") == std::string::npos) {
209         NETMGR_LOG_E("GetMonthAlertText error");
210         return "";
211     }
212 
213     std::string outText = resourceMap[KEY_MONTH_LIMIT_TEXT];
214     int32_t simId = simId_;
215     uint64_t traffic = 0;
216     bool ret = DelayedSingleton<NetStatsService>::GetInstance()->GetMonthlyLimitBySimId(simId, traffic);
217     NETMGR_LOG_I("GetMonthAlertText trafficLimit:%{public}" PRIu64 "", traffic);
218     if (!ret) {
219         return "";
220     }
221     std::string num = GetTrafficNum(static_cast<double>(traffic));
222     outText = outText.replace(outText.find("%s"), TWO_CHAR, num);
223     NETMGR_LOG_I("GetMonthAlertText::outText [%{public}s]", outText.c_str());
224     return outText;
225 }
226 
GetNotificationTitle(std::string & notificationType)227 std::string NetMgrNetStatsLimitNotification::GetNotificationTitle(std::string &notificationType)
228 {
229     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification::GetNotificationTitle");
230     std::string outText = resourceMap[notificationType];
231     if (outText.find("%d") == std::string::npos) {
232         NETMGR_LOG_I("incorrect format %{public}s", outText.c_str());
233         return "";
234     }
235 
236     int32_t simId = simId_;
237     int32_t slotId = Telephony::CoreServiceClient::GetInstance().GetSlotId(simId);
238     NETMGR_LOG_I("GetNotificationTitle. simId:%{public}d, slotId:%{public}d", simId, slotId);
239     outText = outText.replace(outText.find("%d"), TWO_CHAR, std::to_string(slotId + 1));
240     return outText;
241 }
242 
SetTitleAndText(int notificationId,std::shared_ptr<Notification::NotificationNormalContent> content,bool isDualCard)243 bool NetMgrNetStatsLimitNotification::SetTitleAndText(
244     int notificationId,
245     std::shared_ptr<Notification::NotificationNormalContent> content,
246     bool isDualCard)
247 {
248     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification::SetTitleAndText");
249     if (content == nullptr) {
250         NETMGR_LOG_E("content is null");
251         return false;
252     }
253 
254     std::string title = "";
255     if (isDualCard) {
256         title = (notificationId == NETMGR_STATS_LIMIT_DAY) ? KEY_NETWORK_DAY_MARK_DUAL_TITLE : title;
257         title = (notificationId == NETMGR_STATS_LIMIT_MONTH) ? KEY_NETWORK_MONTH_MARK_DUAL_TITLE : title;
258         title = (notificationId == NETMGR_STATS_ALERT_MONTH) ? KEY_NETWORK_MONTH_LIMIT_DUAL_TITLE : title;
259     } else {
260         title = (notificationId == NETMGR_STATS_LIMIT_DAY) ? KEY_NETWORK_DAY_MARK_SINGLE_TITLE : title;
261         title = (notificationId == NETMGR_STATS_LIMIT_MONTH) ? KEY_NETWORK_MONTH_MARK_SINGLE_TITLE : title;
262         title = (notificationId == NETMGR_STATS_ALERT_MONTH) ? KEY_NETWORK_MONTH_LIMIT_SINGLE_TITLE : title;
263     }
264 
265     if (resourceMap.find(title) == resourceMap.end()) {
266         NETMGR_LOG_E("cannot get title from resources");
267         return false;
268     }
269     std::string strTitle;
270     if (isDualCard) {
271         strTitle = GetNotificationTitle(title);
272     } else {
273         strTitle = resourceMap[title];
274     }
275     NETMGR_LOG_I("NetMgrNetStatsLimitNotification: strTitle = %{public}s", strTitle.c_str());
276 
277     std::string strText;
278     switch (notificationId) {
279         case NETMGR_STATS_LIMIT_DAY:
280             strText = GetDayNotificationText();
281             break;
282         case NETMGR_STATS_LIMIT_MONTH:
283             strText = GetMonthNotificationText();
284             break;
285         case NETMGR_STATS_ALERT_MONTH:
286             strText = GetMonthAlertText();
287             break;
288         default:
289             NETMGR_LOG_I("unknown notification ID");
290             return false;
291     }
292     content->SetText(strText);
293     content->SetTitle(strTitle);
294     NETMGR_LOG_I("end NetMgrNetStatsLimitNotification::SetTitleAndText");
295     return true;
296 }
297 
GetPixelMap()298 void NetMgrNetStatsLimitNotification::GetPixelMap()
299 {
300     if (netmgrStatsLimitIconPixelMap_ != nullptr) {
301         return;
302     }
303 
304     if (!std::filesystem::exists(NETWORK_ICON_PATH)) {
305         return;
306     }
307 
308     uint32_t errorCode = 0;
309     Media::SourceOptions opts;
310     opts.formatHint = "image/png";
311     auto imageSource = Media::ImageSource::CreateImageSource(NETWORK_ICON_PATH, opts, errorCode);
312     if (imageSource == nullptr) {
313         NETMGR_LOG_I("CreateImageSource null");
314         return;
315     }
316     Media::DecodeOptions decodeOpts;
317     std::unique_ptr<Media::PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
318     netmgrStatsLimitIconPixelMap_ = std::move(pixelMap);
319 }
320 
GetInstance()321 NetMgrNetStatsLimitNotification& NetMgrNetStatsLimitNotification::GetInstance()
322 {
323     static NetMgrNetStatsLimitNotification instance;
324     return instance;
325 }
326 
NetMgrNetStatsLimitNotification()327 NetMgrNetStatsLimitNotification::NetMgrNetStatsLimitNotification()
328 {
329     std::lock_guard<std::mutex> lock(mutex_);
330     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification");
331     ParseJSONFile(LOCALE_TO_RESOURCE_PATH, languageMap);
332     UpdateResourceMap();
333     GetPixelMap();
334     NETMGR_LOG_I("end NetMgrNetStatsLimitNotification");
335 }
336 
~NetMgrNetStatsLimitNotification()337 NetMgrNetStatsLimitNotification::~NetMgrNetStatsLimitNotification()
338 {
339     NETMGR_LOG_I("NetMgr Notification destructor enter.");
340 }
341 
PublishNetStatsLimitNotification(int notificationId,int simId,bool isDualCard)342 void NetMgrNetStatsLimitNotification::PublishNetStatsLimitNotification(int notificationId, int simId, bool isDualCard)
343 {
344     std::lock_guard<std::mutex> lock(mutex_);
345     simId_ = simId;
346     NETMGR_LOG_I("PublishNetMgrNetStatsLimitNotification: id = %{public}d", notificationId);
347     UpdateResourceMap();
348     std::shared_ptr<Notification::NotificationNormalContent> notificationContent =
349         std::make_shared<Notification::NotificationNormalContent>();
350     if (notificationContent == nullptr) {
351         NETMGR_LOG_E("get notification content nullptr");
352         return;
353     }
354     if (!SetTitleAndText(notificationId, notificationContent, isDualCard)) {
355         NETMGR_LOG_E("error setting title and text");
356         return;
357     }
358 
359     std::shared_ptr<Notification::NotificationContent> content =
360         std::make_shared<Notification::NotificationContent>(notificationContent);
361     if (content == nullptr) {
362         NETMGR_LOG_E("get notification content nullptr");
363         return;
364     }
365 
366     Notification::NotificationRequest request;
367     request.SetNotificationId(static_cast<int32_t>(notificationId));
368     request.SetContent(content);
369     request.SetCreatorUid(COMM_NETSYS_NATIVE_SYS_ABILITY_ID);
370     request.SetAutoDeletedTime(NTF_AUTO_DELETE_TIME);
371     request.SetTapDismissed(true);
372     request.SetSlotType(OHOS::Notification::NotificationConstant::SlotType::SOCIAL_COMMUNICATION);
373     request.SetNotificationControlFlags(NETMGR_TRAFFIC_NTF_CONTROL_FLAG);
374     request.SetLittleIcon(netmgrStatsLimitIconPixelMap_);
375     int ret = Notification::NotificationHelper::PublishNotification(request);
376     NETMGR_LOG_I("publish notification result = %{public}d", ret);
377 }
378 
RegNotificationCallback(NetMgrStatsLimitNtfCallback callback)379 void NetMgrNetStatsLimitNotification::RegNotificationCallback(NetMgrStatsLimitNtfCallback callback)
380 {
381     std::lock_guard<std::mutex> lock(g_callbackMutex);
382     g_NetMgrStatsLimitNtfCallback = callback;
383 }
384 
GetTrafficNum(double traffic)385 std::string NetMgrNetStatsLimitNotification::GetTrafficNum(double traffic)
386 {
387     const char* units[] = {"B", "KB", "MB", "GB", "TB"};
388     int record = 0;
389     while (traffic >= UNIT_CONVERT_1024 && record < 4) { // 4: units array max index
390         traffic /= UNIT_CONVERT_1024;
391         record++;
392     }
393 
394     std::ostringstream oss;
395     oss << std::fixed << std::setprecision(2) << traffic << " " << units[record]; // 2: 保留两位小数
396     std::string systemLocalStr = Global::I18n::LocaleConfig::GetSystemLocale();
397     auto ret = Global::I18n::LocaleConfig::IsRTL(systemLocalStr);
398     if (ret) {
399         return "‪" + oss.str() + "‬";
400     }
401     return oss.str();
402 }
403 }  // namespace NetManagerStandard
404 }  // namespace OHOS
405