• 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_SIMGLE_TITLE = "netstats_excess_monthlimit_notofication_title";
62 static constexpr const char *KEY_NETWORK_MONTH_MARK_SIMGLE_TITLE = "netstats_excess_monthmark_notofication_title";
63 static constexpr const char *KEY_NETWORK_DAY_MARK_SIMGLE_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     NETMGR_LOG_I("UpdateResourceMap: resourcePath = %{public}s", resourcePath.c_str());
142     if (!std::filesystem::exists(resourcePath)) {
143         NETMGR_LOG_E("resource path not exist: %{public}s", resourcePath.c_str());
144         return;
145     }
146     /* 从resourcePath中拿到resourceMap */
147     ParseJSONFile(resourcePath, resourceMap);
148 }
149 
GetDayNotificationText()150 std::string NetMgrNetStatsLimitNotification::GetDayNotificationText()
151 {
152     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification::GetDayNotificationText");
153     int32_t simId = DelayedSingleton<NetStatsService>::GetInstance()->GetCurActiviteSimId();
154     auto settingsObserverMap_ = DelayedSingleton<NetStatsService>::GetInstance()->GetSettingsObserverMap();
155     if (settingsObserverMap_.find(simId) == settingsObserverMap_.end()) {
156         NETMGR_LOG_I("settingsObserverMap_ has no simId key:: simId %{public}d", simId);
157         return "";
158     }
159 
160     std::string outText = resourceMap[KEY_DAILY_NOTIFY_TEXT];
161     NETMGR_LOG_I("NetMgrNetStatsLimitNotification:: simId [%{public}d]", simId);
162     if (outText.find("%s") == std::string::npos) {
163         NETMGR_LOG_I("incorrect format [%{public}s]", outText.c_str());
164         return "";
165     }
166     uint64_t traffic = settingsObserverMap_[simId].second->monthlyLimit;
167     double dailyTraffic = traffic / 100.0 * settingsObserverMap_[simId].second->dailyMark;
168     std::string num = GetTrafficNum(dailyTraffic);
169     outText = outText.replace(outText.find("%s"), TWO_CHAR, num);
170     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification::outText [%{public}s]", outText.c_str());
171     return outText;
172 }
173 
GetMonthNotificationText()174 std::string NetMgrNetStatsLimitNotification::GetMonthNotificationText()
175 {
176     std::string outText;
177 
178     int32_t simId = DelayedSingleton<NetStatsService>::GetInstance()->GetCurActiviteSimId();
179 
180     auto settingsObserverMap_ = DelayedSingleton<NetStatsService>::GetInstance()->GetSettingsObserverMap();
181     if (settingsObserverMap_.find(simId) == settingsObserverMap_.end()) {
182         NETMGR_LOG_I("settingsObserverMap_ has no simId key:: simId %{public}d", simId);
183         return "";
184     }
185 
186     int32_t monUsedPercent = settingsObserverMap_[simId].second->monthlyMark;
187 
188     outText = resourceMap[KEY_MONTH_NOTIFY_TEXT];
189     if (outText.find("%s") == std::string::npos) {
190         NETMGR_LOG_I("incorrect format [%{public}s]", outText.c_str());
191         return "";
192     }
193     outText = outText.replace(outText.find("%s"), TWO_CHAR, std::to_string(monUsedPercent) + "%");
194     NETMGR_LOG_I("GetMonthNotificationText outText [%{public}s]", outText.c_str());
195     return outText;
196 }
197 
GetMonthAlertText()198 std::string NetMgrNetStatsLimitNotification::GetMonthAlertText()
199 {
200     std::string outText;
201 
202     int32_t simId = DelayedSingleton<NetStatsService>::GetInstance()->GetCurActiviteSimId();
203 
204     auto settingsObserverMap_ = DelayedSingleton<NetStatsService>::GetInstance()->GetSettingsObserverMap();
205     if (settingsObserverMap_.find(simId) == settingsObserverMap_.end()) {
206         NETMGR_LOG_I("settingsObserverMap_ has no simId key:: simId %{public}d", simId);
207         return "";
208     }
209 
210     // 检验simId是否合法
211     outText = resourceMap[KEY_MONTH_LIMIT_TEXT];
212     if (outText.find("%s") == std::string::npos) {
213         NETMGR_LOG_I("incorrect format [%{public}s]", outText.c_str());
214         return "";
215     }
216     std::string num = GetTrafficNum(settingsObserverMap_[simId].second->monthlyLimit);
217     outText = outText.replace(outText.find("%s"), TWO_CHAR, num);
218     return outText;
219 }
220 
GetNotificationTile(std::string & notificationType)221 std::string NetMgrNetStatsLimitNotification::GetNotificationTile(std::string &notificationType)
222 {
223     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification::GetNotificationTile");
224     std::string outText;
225     int32_t simId = DelayedSingleton<NetStatsService>::GetInstance()->GetCurActiviteSimId();
226 
227     outText = resourceMap[notificationType];
228 
229     if (outText.find("%d") == std::string::npos) {
230         NETMGR_LOG_I("incorrect format %{public}s", outText.c_str());
231         return "";
232     }
233     int32_t slotId = Telephony::CoreServiceClient::GetInstance().GetSlotId(simId);
234     NETMGR_LOG_I("GetNotificationTile. simId:%{public}d, slotId:%{public}d", simId, slotId);
235     outText = outText.replace(outText.find("%d"), TWO_CHAR, std::to_string(slotId + 1));
236     return outText;
237 }
238 
SetTitleAndText(int notificationId,std::shared_ptr<Notification::NotificationNormalContent> content,bool isDaulCard)239 bool NetMgrNetStatsLimitNotification::SetTitleAndText(
240     int notificationId,
241     std::shared_ptr<Notification::NotificationNormalContent> content,
242     bool isDaulCard)
243 {
244     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification::SetTitleAndText");
245     std::string strText;
246     if (content == nullptr) {
247         NETMGR_LOG_I("content is null");
248         return false;
249     }
250 
251     std::string title = "";
252     if (isDaulCard) {
253         title = (notificationId == NETMGR_STATS_LIMIT_DAY) ? KEY_NETWORK_DAY_MARK_DUAL_TITLE : title;
254         title = (notificationId == NETMGR_STATS_LIMIT_MONTH) ? KEY_NETWORK_MONTH_MARK_DUAL_TITLE : title;
255         title = (notificationId == NETMGR_STATS_ALERT_MONTH) ? KEY_NETWORK_MONTH_LIMIT_DUAL_TITLE : title;
256     } else {
257         title = (notificationId == NETMGR_STATS_LIMIT_DAY) ? KEY_NETWORK_DAY_MARK_SIMGLE_TITLE : title;
258         title = (notificationId == NETMGR_STATS_LIMIT_MONTH) ? KEY_NETWORK_MONTH_MARK_SIMGLE_TITLE : title;
259         title = (notificationId == NETMGR_STATS_ALERT_MONTH) ? KEY_NETWORK_MONTH_LIMIT_SIMGLE_TITLE : title;
260     }
261 
262     if (resourceMap.find(title) == resourceMap.end()) {
263         NETMGR_LOG_I("cannot get title from resources");
264         return false;
265     }
266     std::string strTitle;
267     if (isDaulCard) {
268         strTitle = GetNotificationTile(title);
269     } else {
270         strTitle = resourceMap[title];
271     }
272 
273     NETMGR_LOG_I("NetMgrNetStatsLimitNotification: strTitle = %{public}s", strTitle.c_str());
274 
275     switch (notificationId) {
276         case NETMGR_STATS_LIMIT_DAY:
277             strText = GetDayNotificationText();
278             break;
279         case NETMGR_STATS_LIMIT_MONTH:
280             strText = GetMonthNotificationText();
281             break;
282         case NETMGR_STATS_ALERT_MONTH:
283             strText = GetMonthAlertText();
284             break;
285         default:
286             NETMGR_LOG_I("unknown notification ID");
287             return false;
288     }
289     content->SetText(strText);
290     content->SetTitle(strTitle);
291     NETMGR_LOG_I("end NetMgrNetStatsLimitNotification::SetTitleAndText");
292     return true;
293 }
294 
GetPixelMap()295 void NetMgrNetStatsLimitNotification::GetPixelMap()
296 {
297     if (netmgrStatsLimitIconPixelMap_ != nullptr) {
298         return;
299     }
300 
301     if (!std::filesystem::exists(NETWORK_ICON_PATH)) {
302         return;
303     }
304 
305     uint32_t errorCode = 0;
306     Media::SourceOptions opts;
307     opts.formatHint = "image/png";
308     auto imageSource = Media::ImageSource::CreateImageSource(NETWORK_ICON_PATH, opts, errorCode);
309     if (imageSource == nullptr) {
310         NETMGR_LOG_I("CreateImageSource null");
311         return;
312     }
313     Media::DecodeOptions decodeOpts;
314     std::unique_ptr<Media::PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
315     netmgrStatsLimitIconPixelMap_ = std::move(pixelMap);
316 }
317 
GetInstance()318 NetMgrNetStatsLimitNotification& NetMgrNetStatsLimitNotification::GetInstance()
319 {
320     static NetMgrNetStatsLimitNotification instance;
321     return instance;
322 }
323 
NetMgrNetStatsLimitNotification()324 NetMgrNetStatsLimitNotification::NetMgrNetStatsLimitNotification()
325 {
326     std::lock_guard<std::mutex> lock(mutex_);
327     NETMGR_LOG_I("start NetMgrNetStatsLimitNotification");
328     ParseJSONFile(LOCALE_TO_RESOURCE_PATH, languageMap);
329     UpdateResourceMap();
330     GetPixelMap();
331     NETMGR_LOG_I("end NetMgrNetStatsLimitNotification");
332 }
333 
~NetMgrNetStatsLimitNotification()334 NetMgrNetStatsLimitNotification::~NetMgrNetStatsLimitNotification()
335 {
336     NETMGR_LOG_I("NetMgr Notification destructor enter.");
337 }
338 
PublishNetStatsLimitNotification(int notificationId,bool isDaulCard)339 void NetMgrNetStatsLimitNotification::PublishNetStatsLimitNotification(int notificationId, bool isDaulCard)
340 {
341     std::lock_guard<std::mutex> lock(mutex_);
342     NETMGR_LOG_I("PublishNetMgrNetStatsLimitNotification: id = %{public}d", notificationId);
343     UpdateResourceMap();
344     std::shared_ptr<Notification::NotificationNormalContent> notificationContent =
345         std::make_shared<Notification::NotificationNormalContent>();
346     if (notificationContent == nullptr) {
347         NETMGR_LOG_I("get notification content nullptr");
348         return;
349     }
350     if (!SetTitleAndText(notificationId, notificationContent, isDaulCard)) {
351         NETMGR_LOG_I("error setting title and text");
352         return;
353     }
354 
355     std::shared_ptr<Notification::NotificationContent> content =
356         std::make_shared<Notification::NotificationContent>(notificationContent);
357     if (content == nullptr) {
358         NETMGR_LOG_I("get notification content nullptr");
359         return;
360     }
361 
362     Notification::NotificationRequest request;
363     request.SetNotificationId(static_cast<int32_t>(notificationId));
364     request.SetContent(content);
365 
366     request.SetCreatorUid(COMM_NETSYS_NATIVE_SYS_ABILITY_ID);
367     request.SetAutoDeletedTime(NTF_AUTO_DELETE_TIME);
368     request.SetTapDismissed(true);
369     request.SetSlotType(OHOS::Notification::NotificationConstant::SlotType::SOCIAL_COMMUNICATION);
370     request.SetNotificationControlFlags(NETMGR_TRAFFIC_NTF_CONTROL_FLAG);
371 
372     request.SetLittleIcon(netmgrStatsLimitIconPixelMap_);
373 
374     int ret = Notification::NotificationHelper::PublishNotification(request);
375     NETMGR_LOG_I("publish notification result = %{public}d", ret);
376 
377     auto settingsObserverMap_ = DelayedSingleton<NetStatsService>::GetInstance()->GetSettingsObserverMap();
378 }
379 
RegNotificationCallback(NetMgrStatsLimitNtfCallback callback)380 void NetMgrNetStatsLimitNotification::RegNotificationCallback(NetMgrStatsLimitNtfCallback callback)
381 {
382     std::lock_guard<std::mutex> lock(g_callbackMutex);
383     g_NetMgrStatsLimitNtfCallback = callback;
384 }
385 
GetTrafficNum(double traffic)386 std::string NetMgrNetStatsLimitNotification::GetTrafficNum(double traffic)
387 {
388     const char* units[] = {"B", "KB", "MB", "GB", "TB"}; // 流量单位数组
389     int record = 0; // 记录单位索引
390 
391     // 确定应该使用的单位
392     while (traffic >= UNIT_CONVERT_1024 && record < 4) { // 4: 防止units数组越界
393         traffic /= UNIT_CONVERT_1024;
394         record++;
395     }
396 
397     std::ostringstream oss;
398     oss << std::fixed << std::setprecision(2) << traffic << " " << units[record];  // 2: 保留两位小数
399     // 返回格式化后的字符串
400     return oss.str();
401 }
402 }  // namespace NetManagerStandard
403 }  // namespace OHOS
404 
405