1 /*
2 * Copyright (c) 2024-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 #ifdef NOTIFICATION_SMART_REMINDER_SUPPORTED
17 #include "smart_reminder_center.h"
18
19 #include "ans_log_wrapper.h"
20 #include "ipc_skeleton.h"
21 #include "notification_bundle_option.h"
22 #include "notification_local_live_view_content.h"
23 #include "notification_preferences.h"
24 #include "os_account_manager.h"
25 #include "screenlock_manager.h"
26 #include "string_utils.h"
27
28 namespace OHOS {
29 namespace Notification {
30 using namespace std;
SmartReminderCenter()31 SmartReminderCenter::SmartReminderCenter()
32 {
33 if (!DelayedSingleton<NotificationConfigParse>::GetInstance()->GetCurrentSlotReminder(currentReminderMethods_)) {
34 return;
35 }
36 GetMultiDeviceReminder();
37 }
38
GetMultiDeviceReminder()39 void SmartReminderCenter::GetMultiDeviceReminder()
40 {
41 nlohmann::json root;
42 string multiJsonPoint = "/";
43 multiJsonPoint.append(NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE);
44 multiJsonPoint.append("/");
45 multiJsonPoint.append(MULTI_DEVICE_REMINDER);
46 if (!DelayedSingleton<NotificationConfigParse>::GetInstance()->GetConfigJson(multiJsonPoint, root)) {
47 ANS_LOGW("Failed to get multiDeviceReminder CCM config file.");
48 return;
49 }
50
51 if (root.find(NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE) == root.end()) {
52 ANS_LOGW("GetMultiDeviceReminder failed as can not find notificationService.");
53 return;
54 }
55
56 nlohmann::json multiDeviceRemindJson =
57 root[NotificationConfigParse::CFG_KEY_NOTIFICATION_SERVICE][MULTI_DEVICE_REMINDER];
58 if (multiDeviceRemindJson.is_null() || !multiDeviceRemindJson.is_array() || multiDeviceRemindJson.empty()) {
59 ANS_LOGW("GetMultiDeviceReminder failed as invalid multiDeviceReminder json.");
60 return;
61 }
62
63 reminderMethods_.clear();
64 for (auto &singleDeviceRemindJson : multiDeviceRemindJson) {
65 if (singleDeviceRemindJson.is_null() || !singleDeviceRemindJson.is_object()) {
66 continue;
67 }
68
69 if (singleDeviceRemindJson.find(ReminderAffected::DEVICE_TYPE) == singleDeviceRemindJson.end() ||
70 singleDeviceRemindJson[ReminderAffected::DEVICE_TYPE].is_null() ||
71 !singleDeviceRemindJson[ReminderAffected::DEVICE_TYPE].is_string()) {
72 continue;
73 }
74
75 if (singleDeviceRemindJson.find(REMINDER_FILTER_DEVICE) == singleDeviceRemindJson.end() ||
76 singleDeviceRemindJson[REMINDER_FILTER_DEVICE].is_null() ||
77 !singleDeviceRemindJson[REMINDER_FILTER_DEVICE].is_array() ||
78 singleDeviceRemindJson[REMINDER_FILTER_DEVICE].empty()) {
79 continue;
80 }
81 ParseReminderFilterDevice(singleDeviceRemindJson[REMINDER_FILTER_DEVICE],
82 singleDeviceRemindJson[ReminderAffected::DEVICE_TYPE].get<string>());
83 }
84
85 if (reminderMethods_.size() <= 0) {
86 ANS_LOGW("GetMultiDeviceReminder failed as Invalid reminderMethods size.");
87 }
88 }
89
ParseReminderFilterDevice(const nlohmann::json & root,const string & deviceType)90 void SmartReminderCenter::ParseReminderFilterDevice(const nlohmann::json &root, const string &deviceType)
91 {
92 map<string, vector<shared_ptr<ReminderAffected>>> reminderFilterDevice;
93 for (auto &reminderFilterDeviceJson : root) {
94 NotificationConstant::SlotType slotType;
95 if (reminderFilterDeviceJson.find(SLOT_TYPE) == reminderFilterDeviceJson.end() ||
96 reminderFilterDeviceJson[SLOT_TYPE].is_null() ||
97 !reminderFilterDeviceJson[SLOT_TYPE].is_string()) {
98 continue;
99 }
100
101 if (reminderFilterDeviceJson.find(REMINDER_FILTER_SLOT) == reminderFilterDeviceJson.end() ||
102 reminderFilterDeviceJson[REMINDER_FILTER_SLOT].is_null() ||
103 !reminderFilterDeviceJson[REMINDER_FILTER_SLOT].is_array() ||
104 reminderFilterDeviceJson[REMINDER_FILTER_SLOT].empty()) {
105 continue;
106 }
107
108 std::string slotTypes = reminderFilterDeviceJson[SLOT_TYPE].get<std::string>();
109 std::vector<std::string> slotTypeVector;
110 StringUtils::Split(slotTypes, SPLIT_FLAG, slotTypeVector);
111
112 for (std::string slotTypeStr : slotTypeVector) {
113 if (!NotificationSlot::GetSlotTypeByString(slotTypeStr, slotType)) {
114 continue;
115 }
116 ParseReminderFilterSlot(reminderFilterDeviceJson[REMINDER_FILTER_SLOT],
117 to_string(static_cast<int32_t>(slotType)), reminderFilterDevice);
118 }
119 }
120 if (reminderFilterDevice.size() > 0) {
121 reminderMethods_[deviceType] = move(reminderFilterDevice);
122 } else {
123 ANS_LOGI("ParseReminderFilterDevice failed as Invalid reminderFilterDevice size. deviceType = %{public}s.",
124 deviceType.c_str());
125 }
126 }
127
ParseReminderFilterSlot(const nlohmann::json & root,const string & notificationType,map<string,vector<shared_ptr<ReminderAffected>>> & reminderFilterDevice) const128 void SmartReminderCenter::ParseReminderFilterSlot(
129 const nlohmann::json &root,
130 const string ¬ificationType,
131 map<string, vector<shared_ptr<ReminderAffected>>> &reminderFilterDevice) const
132 {
133 vector<shared_ptr<ReminderAffected>> reminderFilterSlot;
134 for (auto &reminderFilterSlotJson : root) {
135 NotificationContent::Type contentType;
136 bool validContentType = true;
137
138 if (reminderFilterSlotJson.find(CONTENT_TYPE) == reminderFilterSlotJson.end() ||
139 reminderFilterSlotJson[CONTENT_TYPE].is_null() ||
140 !reminderFilterSlotJson[CONTENT_TYPE].is_string() ||
141 !NotificationContent::GetContentTypeByString(
142 reminderFilterSlotJson[CONTENT_TYPE].get<std::string>(), contentType)) {
143 validContentType = false;
144 }
145
146 if (reminderFilterSlotJson.find(REMINDER_FILTER_CONTENT) == reminderFilterSlotJson.end() ||
147 reminderFilterSlotJson[REMINDER_FILTER_CONTENT].is_null() ||
148 !reminderFilterSlotJson[REMINDER_FILTER_CONTENT].is_array() ||
149 reminderFilterSlotJson[REMINDER_FILTER_CONTENT].empty()) {
150 validContentType = false;
151 }
152
153 if (validContentType) {
154 string localNotificationType = notificationType;
155 localNotificationType.append("#");
156 localNotificationType.append(to_string(static_cast<int32_t>(contentType)));
157 ParseReminderFilterContent(
158 reminderFilterSlotJson[REMINDER_FILTER_CONTENT], localNotificationType, reminderFilterDevice);
159 continue;
160 }
161 shared_ptr<ReminderAffected> reminderAffected = make_shared<ReminderAffected>();
162 if (reminderAffected->FromJson(reminderFilterSlotJson)) {
163 reminderFilterSlot.push_back(reminderAffected);
164 }
165 }
166 if (reminderFilterSlot.size() > 0) {
167 reminderFilterDevice[notificationType] = move(reminderFilterSlot);
168 }
169 }
170
ParseReminderFilterContent(const nlohmann::json & root,const string & notificationType,map<string,vector<shared_ptr<ReminderAffected>>> & reminderFilterDevice) const171 void SmartReminderCenter::ParseReminderFilterContent(
172 const nlohmann::json &root,
173 const string ¬ificationType,
174 map<string, vector<shared_ptr<ReminderAffected>>> &reminderFilterDevice) const
175 {
176 vector<shared_ptr<ReminderAffected>> reminderFilterContent;
177 for (auto &reminderFilterContentJson : root) {
178 bool validTypeCode = true;
179 if (reminderFilterContentJson.find(TYPE_CODE) == reminderFilterContentJson.end() ||
180 reminderFilterContentJson[TYPE_CODE].is_null() ||
181 !reminderFilterContentJson[TYPE_CODE].is_number()) {
182 validTypeCode = false;
183 }
184
185 if (reminderFilterContentJson.find(REMINDER_FILTER_CODE) == reminderFilterContentJson.end() ||
186 reminderFilterContentJson[REMINDER_FILTER_CODE].is_null() ||
187 !reminderFilterContentJson[REMINDER_FILTER_CODE].is_array() ||
188 reminderFilterContentJson[REMINDER_FILTER_CODE].empty()) {
189 validTypeCode = false;
190 }
191
192 if (validTypeCode) {
193 int32_t typeCode = reminderFilterContentJson[TYPE_CODE].get<int32_t>();
194 string localNotificationType = notificationType;
195 localNotificationType.append("#");
196 localNotificationType.append(to_string(typeCode));
197 ParseReminderFilterCode(
198 reminderFilterContentJson[REMINDER_FILTER_CODE], localNotificationType, reminderFilterDevice);
199 continue;
200 }
201 shared_ptr<ReminderAffected> reminderAffected = make_shared<ReminderAffected>();
202 if (reminderAffected->FromJson(reminderFilterContentJson)) {
203 reminderFilterContent.push_back(reminderAffected);
204 }
205 }
206 if (reminderFilterContent.size() > 0) {
207 reminderFilterDevice[notificationType] = move(reminderFilterContent);
208 }
209 }
210
ParseReminderFilterCode(const nlohmann::json & root,const string & notificationType,map<string,vector<shared_ptr<ReminderAffected>>> & reminderFilterDevice) const211 void SmartReminderCenter::ParseReminderFilterCode(
212 const nlohmann::json &root,
213 const string ¬ificationType,
214 map<string, vector<shared_ptr<ReminderAffected>>> &reminderFilterDevice) const
215 {
216 vector<shared_ptr<ReminderAffected>> reminderFilterCode;
217 for (auto &reminderFilterCodeJson : root) {
218 shared_ptr<ReminderAffected> reminderAffected = make_shared<ReminderAffected>();
219 if (reminderAffected->FromJson(reminderFilterCodeJson)) {
220 reminderFilterCode.push_back(reminderAffected);
221 }
222 }
223 if (reminderFilterCode.size() > 0) {
224 reminderFilterDevice[notificationType] = move(reminderFilterCode);
225 }
226 }
227
ReminderDecisionProcess(const sptr<NotificationRequest> & request) const228 void SmartReminderCenter::ReminderDecisionProcess(const sptr<NotificationRequest> &request) const
229 {
230 shared_ptr<map<string, shared_ptr<NotificationFlags>>> notificationFlagsOfDevices =
231 make_shared<map<string, shared_ptr<NotificationFlags>>>();
232 NotificationConstant::SlotType slotType = request->GetSlotType();
233 auto iter = currentReminderMethods_.find(slotType);
234 if (iter != currentReminderMethods_.end()) {
235 // Only config file can set reminder open now. Otherwise, change iter->second to 11111
236 (*notificationFlagsOfDevices)[NotificationConstant::CURRENT_DEVICE_TYPE] = iter->second;
237 }
238
239 map<string, vector<shared_ptr<ReminderAffected>>> currentReminderMethod;
240 set<string> validDevices;
241 for (auto &reminderMethod : reminderMethods_) {
242 if (reminderMethod.first.compare(NotificationConstant::CURRENT_DEVICE_TYPE) == 0) {
243 currentReminderMethod = reminderMethod.second;
244 continue;
245 }
246 HandleReminderMethods(
247 reminderMethod.first, reminderMethod.second, request, validDevices, notificationFlagsOfDevices);
248 }
249 if (currentReminderMethod.size() > 0 && validDevices.size() > 0) {
250 HandleReminderMethods(NotificationConstant::CURRENT_DEVICE_TYPE,
251 currentReminderMethod, request, validDevices, notificationFlagsOfDevices);
252 }
253
254 request->SetDeviceFlags(notificationFlagsOfDevices);
255 }
256
HandleReminderMethods(const string & deviceType,const map<string,vector<shared_ptr<ReminderAffected>>> & reminderFilterDevice,const sptr<NotificationRequest> & request,set<string> & validDevices,shared_ptr<map<string,shared_ptr<NotificationFlags>>> notificationFlagsOfDevices) const257 void SmartReminderCenter::HandleReminderMethods(
258 const string &deviceType,
259 const map<string, vector<shared_ptr<ReminderAffected>>> &reminderFilterDevice,
260 const sptr<NotificationRequest> &request,
261 set<string> &validDevices,
262 shared_ptr<map<string, shared_ptr<NotificationFlags>>> notificationFlagsOfDevices) const
263 {
264 vector<shared_ptr<ReminderAffected>> reminderAffecteds;
265 GetReminderAffecteds(reminderFilterDevice, request, reminderAffecteds);
266 if (reminderAffecteds.size() <= 0) {
267 return;
268 }
269 bitset<DistributedDeviceStatus::STATUS_SIZE> bitStatus;
270 GetDeviceStatusByType(deviceType, bitStatus);
271 bool enabledAffectedBy = true;
272 if (deviceType.compare(NotificationConstant::CURRENT_DEVICE_TYPE) != 0) {
273 if (IsNeedSynergy(deviceType, request->GetOwnerBundleName(), request->GetOwnerUid())) {
274 validDevices.insert(deviceType);
275 } else {
276 enabledAffectedBy = false;
277 }
278 }
279 if (!NotificationSubscriberManager::GetInstance()->GetIsEnableEffectedRemind()) {
280 enabledAffectedBy = false;
281 }
282
283 for (auto &reminderAffected : reminderAffecteds) {
284 if (!CompareStatus(reminderAffected->status_, bitStatus)) {
285 continue;
286 }
287 if (reminderAffected->affectedBy_.size() <= 0) {
288 (*notificationFlagsOfDevices)[deviceType] = reminderAffected->reminderFlags_;
289 continue;
290 }
291 if (enabledAffectedBy &&
292 HandleAffectedReminder(deviceType, reminderAffected, validDevices, notificationFlagsOfDevices)) {
293 break;
294 }
295 }
296 }
297
IsNeedSynergy(const string & deviceType,const string & ownerBundleName,int32_t ownerUid) const298 bool SmartReminderCenter::IsNeedSynergy(const string &deviceType, const string &ownerBundleName, int32_t ownerUid) const
299 {
300 bool isEnable = true;
301 if (NotificationPreferences::GetInstance()->IsSmartReminderEnabled(deviceType, isEnable) != ERR_OK || !isEnable) {
302 return false;
303 }
304
305 sptr<NotificationBundleOption> bundleOption =
306 new (std::nothrow) NotificationBundleOption(ownerBundleName, ownerUid);
307 if (NotificationPreferences::GetInstance()->IsDistributedEnabledByBundle(
308 bundleOption, deviceType, isEnable) != ERR_OK || !isEnable) {
309 return false;
310 }
311 return true;
312 }
313
HandleAffectedReminder(const string & deviceType,const shared_ptr<ReminderAffected> & reminderAffected,const set<string> & validDevices,shared_ptr<map<string,shared_ptr<NotificationFlags>>> notificationFlagsOfDevices) const314 bool SmartReminderCenter::HandleAffectedReminder(
315 const string &deviceType,
316 const shared_ptr<ReminderAffected> &reminderAffected,
317 const set<string> &validDevices,
318 shared_ptr<map<string, shared_ptr<NotificationFlags>>> notificationFlagsOfDevices) const
319 {
320 bool ret = true;
321 for (auto &affectedBy : reminderAffected->affectedBy_) {
322 if (deviceType.compare(NotificationConstant::CURRENT_DEVICE_TYPE) == 0 &&
323 validDevices.find(affectedBy.first) == validDevices.end()) {
324 ret = false;
325 break;
326 }
327 bitset<DistributedDeviceStatus::STATUS_SIZE> bitStatus;
328 GetDeviceStatusByType(affectedBy.first, bitStatus);
329 if (!CompareStatus(affectedBy.second, bitStatus)) {
330 ret = false;
331 break;
332 }
333 }
334 if (ret) {
335 (*notificationFlagsOfDevices)[deviceType] = reminderAffected->reminderFlags_;
336 }
337 return ret;
338 }
339
CompareStatus(const string & status,const bitset<DistributedDeviceStatus::STATUS_SIZE> & bitStatus) const340 bool SmartReminderCenter::CompareStatus(
341 const string &status, const bitset<DistributedDeviceStatus::STATUS_SIZE> &bitStatus) const
342 {
343 if (status.size() <= 0) {
344 return true;
345 }
346 // bitset.to_string() and config is reverse, bit[0] is behind
347 string localStatus = status;
348 reverse(localStatus.begin(), localStatus.end());
349 for (int32_t seq = 0; seq < DistributedDeviceStatus::STATUS_SIZE; seq++) {
350 if (localStatus[seq] != ReminderAffected::STATUS_DEFAULT && bitStatus[seq] != localStatus[seq] - '0') {
351 return false;
352 }
353 }
354 return true;
355 }
356
GetReminderAffecteds(const map<string,vector<shared_ptr<ReminderAffected>>> & reminderFilterDevice,const sptr<NotificationRequest> & request,vector<shared_ptr<ReminderAffected>> & reminderAffecteds) const357 __attribute__((no_sanitize("cfi"))) void SmartReminderCenter::GetReminderAffecteds(
358 const map<string, vector<shared_ptr<ReminderAffected>>> &reminderFilterDevice,
359 const sptr<NotificationRequest> &request,
360 vector<shared_ptr<ReminderAffected>> &reminderAffecteds) const
361 {
362 string strSlotType = to_string(static_cast<int32_t>(request->GetSlotType()));
363 string contentTypeCombination = strSlotType;
364 contentTypeCombination.append("#");
365 if (request->GetContent() != nullptr) {
366 contentTypeCombination.append(to_string(static_cast<int32_t>(request->GetContent()->GetContentType())));
367 }
368 string typeCodeCombination = contentTypeCombination;
369 typeCodeCombination.append("#");
370 if (request->GetContent() != nullptr && request->GetContent()->GetNotificationContent() != nullptr) {
371 NotificationLocalLiveViewContent *localLiveView =
372 static_cast<NotificationLocalLiveViewContent *>(&(*(request->GetContent()->GetNotificationContent())));
373 typeCodeCombination.append(to_string(localLiveView->GetType()));
374 }
375 auto iter = reminderFilterDevice.find(typeCodeCombination);
376 if (iter != reminderFilterDevice.end()) {
377 reminderAffecteds = iter->second;
378 return;
379 }
380 iter = reminderFilterDevice.find(contentTypeCombination);
381 if (iter != reminderFilterDevice.end()) {
382 reminderAffecteds = iter->second;
383 return;
384 }
385 iter = reminderFilterDevice.find(strSlotType);
386 if (iter != reminderFilterDevice.end()) {
387 reminderAffecteds = iter->second;
388 return;
389 }
390 ANS_LOGD("GetReminderAffecteds fail as wrong notification_config.json possibly. TypeCombination = %{public}s.",
391 typeCodeCombination.c_str());
392 }
393
GetDeviceStatusByType(const string & deviceType,bitset<DistributedDeviceStatus::STATUS_SIZE> & bitStatus) const394 void SmartReminderCenter::GetDeviceStatusByType(
395 const string &deviceType, bitset<DistributedDeviceStatus::STATUS_SIZE> &bitStatus) const
396 {
397 u_int32_t status = DelayedSingleton<DistributedDeviceStatus>::GetInstance()->GetDeviceStatus(deviceType);
398 bitStatus = bitset<DistributedDeviceStatus::STATUS_SIZE>(status);
399 if (deviceType.compare(NotificationConstant::CURRENT_DEVICE_TYPE) == 0) {
400 bool screenLocked = true;
401 screenLocked = ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked();
402 bitStatus.set(DistributedDeviceStatus::LOCK_FLAG, !screenLocked);
403 }
404 ANS_LOGD("GetDeviceStatusByType deviceType: %{public}s, bitStatus: %{public}s.",
405 deviceType.c_str(), bitStatus.to_string().c_str());
406 }
407 } // namespace Notification
408 } // namespace OHOS
409 #endif
410