1 /*
2 * Copyright (c) 2023-2025 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 "notification_dialog_manager.h"
17
18 #include "common_event_manager.h"
19 #include "matching_skills.h"
20
21 #include "advanced_notification_service.h"
22 #include "ans_const_define.h"
23 #include "ans_log_wrapper.h"
24 #include "notification_bundle_option.h"
25 #include "notification_dialog.h"
26 #include "notification_preferences.h"
27 #ifdef ENABLE_ANS_PRIVILEGED_MESSAGE_EXT_WRAPPER
28 #include "os_account_manager_helper.h"
29 #include "notification_extension_wrapper.h"
30 #endif
31 #include <cstdlib>
32 #include <string>
33
34 namespace OHOS::Notification {
35 using DialogInfo = NotificationDialogManager::DialogInfo;
36
Create(NotificationDialogManager & dialogManager)37 std::shared_ptr<NotificationDialogEventSubscriber> NotificationDialogEventSubscriber::Create(
38 NotificationDialogManager& dialogManager)
39 {
40 ANS_LOGD("enter");
41 EventFwk::MatchingSkills matchingSkills;
42 matchingSkills.AddEvent(NotificationDialogEventSubscriber::EVENT_NAME);
43 EventFwk::CommonEventSubscribeInfo subscriberInfo(matchingSkills);
44 subscriberInfo.SetPublisherBundleName(NotificationDialogManager::NOTIFICATION_DIALOG_SERVICE_BUNDLE);
45 return std::make_shared<NotificationDialogEventSubscriber>(dialogManager, subscriberInfo);
46 }
47
NotificationDialogEventSubscriber(NotificationDialogManager & dialogManager,const EventFwk::CommonEventSubscribeInfo & subscribeInfo)48 NotificationDialogEventSubscriber::NotificationDialogEventSubscriber(
49 NotificationDialogManager& dialogManager, const EventFwk::CommonEventSubscribeInfo& subscribeInfo)
50 : EventFwk::CommonEventSubscriber(subscribeInfo), dialogManager_(dialogManager)
51 { }
52
OnReceiveEvent(const EventFwk::CommonEventData & data)53 void NotificationDialogEventSubscriber::OnReceiveEvent(const EventFwk::CommonEventData& data)
54 {
55 int32_t code = data.GetCode();
56 std::string bundleName = data.GetWant().GetStringParam("bundleName");
57 int32_t bundleUid = std::atoi(data.GetWant().GetStringParam("bundleUid").c_str());
58 ANS_LOGI("NotificationDialogEventSubscriber Get Data %{public}d %{public}s %{public}d", code,
59 bundleName.c_str(), bundleUid);
60 dialogManager_.OnBundleEnabledStatusChanged(static_cast<DialogStatus>(code), bundleName, bundleUid);
61 }
62
~NotificationDialogEventSubscriber()63 NotificationDialogEventSubscriber::~NotificationDialogEventSubscriber()
64 {
65 ANS_LOGD("enter");
66 }
67
NotificationDialogManager(AdvancedNotificationService & ans)68 NotificationDialogManager::NotificationDialogManager(AdvancedNotificationService& ans)
69 : ans_(ans)
70 {
71 ANS_LOGD("enter");
72 }
73
~NotificationDialogManager()74 NotificationDialogManager::~NotificationDialogManager()
75 {
76 ANS_LOGD("enter");
77 }
78
Init()79 bool NotificationDialogManager::Init()
80 {
81 ANS_LOGD("enter");
82
83 dialogEventSubscriber = NotificationDialogEventSubscriber::Create(*this);
84 if (!EventFwk::CommonEventManager::SubscribeCommonEvent(dialogEventSubscriber)) {
85 ANS_LOGE("SubscribeCommonEvent Failed.");
86 dialogEventSubscriber = nullptr;
87 return false;
88 }
89 return true;
90 }
91
RequestEnableNotificationDailog(const sptr<NotificationBundleOption> & bundle,const sptr<IAnsDialogCallback> & callback,const sptr<IRemoteObject> & callerToken,const bool innerLake,const bool easyAbroad)92 ErrCode NotificationDialogManager::RequestEnableNotificationDailog(
93 const sptr<NotificationBundleOption>& bundle,
94 const sptr<IAnsDialogCallback>& callback,
95 const sptr<IRemoteObject>& callerToken,
96 const bool innerLake,
97 const bool easyAbroad)
98 {
99 if (!AddDialogInfoIfNotExist(bundle, callback)) {
100 ANS_LOGE("Dialog already exists. bundle = %{public}s",
101 bundle->GetBundleName().c_str());
102 return ERR_ANS_DIALOG_IS_POPPING;
103 }
104 ErrCode result = NotificationDialog::StartEnableNotificationDialogAbility(
105 NotificationDialogManager::NOTIFICATION_DIALOG_SERVICE_BUNDLE,
106 NotificationDialogManager::NOTIFICATION_DIALOG_SERVICE_ABILITY,
107 bundle->GetUid(),
108 bundle->GetBundleName(),
109 callerToken,
110 innerLake,
111 easyAbroad);
112 if (result != ERR_OK) {
113 ANS_LOGE("Start failed, result=%{public}d", result);
114 std::unique_ptr<NotificationDialogManager::DialogInfo> dialogInfoRemoved = nullptr;
115 RemoveDialogInfoByBundleOption(bundle, dialogInfoRemoved);
116 }
117 return result;
118 }
119
OnBundleEnabledStatusChanged(DialogStatus status,const std::string & bundleName,const int32_t & uid)120 ErrCode NotificationDialogManager::OnBundleEnabledStatusChanged(
121 DialogStatus status, const std::string& bundleName, const int32_t& uid)
122 {
123 ANS_LOGD("enter");
124 bool result = false;
125 switch (status) {
126 case DialogStatus::ALLOW_CLICKED:
127 result = OnDialogButtonClicked(bundleName, uid, true);
128 break;
129 case DialogStatus::DENY_CLICKED:
130 result = OnDialogButtonClicked(bundleName, uid, false);
131 break;
132 case DialogStatus::DIALOG_CRASHED:
133 result = OnDialogCrashed(bundleName, uid);
134 break;
135 case DialogStatus::DIALOG_SERVICE_DESTROYED:
136 result = OnDialogServiceDestroyed();
137 break;
138 case DialogStatus::REMOVE_BUNDLE:
139 result = onRemoveBundle(bundleName, uid);
140 break;
141 default:
142 result = false;
143 }
144 if (!result) {
145 ANS_LOGE("OnBundleEnabledStatusChanged failed");
146 return ERROR_INTERNAL_ERROR;
147 }
148 return ERR_OK;
149 }
150
AddDialogInfo(const sptr<NotificationBundleOption> & bundle,const sptr<IAnsDialogCallback> & callback)151 ErrCode NotificationDialogManager::AddDialogInfo(const sptr<NotificationBundleOption>& bundle,
152 const sptr<IAnsDialogCallback>& callback)
153 {
154 if (!AddDialogInfoIfNotExist(bundle, callback)) {
155 return ERR_ANS_DIALOG_IS_POPPING;
156 }
157 return ERR_OK;
158 }
159
AddDialogInfoIfNotExist(const sptr<NotificationBundleOption> & bundle,const sptr<IAnsDialogCallback> & callback)160 bool NotificationDialogManager::AddDialogInfoIfNotExist(
161 const sptr<NotificationBundleOption>& bundle,
162 const sptr<IAnsDialogCallback>& callback)
163 {
164 std::lock_guard<ffrt::mutex> lock(dialogsMutex_);
165 std::string name = bundle->GetBundleName();
166 int32_t uid = bundle->GetUid();
167 auto dialogIter = std::find_if(dialogsOpening_.begin(), dialogsOpening_.end(),
168 [&](const std::unique_ptr<DialogInfo>& dialogInfo) {
169 return dialogInfo->bundleOption->GetBundleName() == name && dialogInfo->bundleOption->GetUid() == uid;
170 });
171 if (dialogIter != dialogsOpening_.end()) {
172 return false;
173 }
174 auto dialogInfo = std::make_unique<DialogInfo>();
175 dialogInfo->bundleOption = bundle;
176 dialogInfo->callback = callback;
177 dialogsOpening_.push_back(std::move(dialogInfo));
178 return true;
179 }
180
GetBundleOptionByBundleName(const std::string & bundleName,const int32_t & uid)181 sptr<NotificationBundleOption> NotificationDialogManager::GetBundleOptionByBundleName(
182 const std::string& bundleName, const int32_t& uid)
183 {
184 std::lock_guard<ffrt::mutex> lock(dialogsMutex_);
185 auto dialogIter = std::find_if(dialogsOpening_.begin(), dialogsOpening_.end(),
186 [&](const std::unique_ptr<DialogInfo>& dialogInfo) {
187 return dialogInfo->bundleOption->GetBundleName() == bundleName && dialogInfo->bundleOption->GetUid() == uid;
188 });
189 if (dialogIter == dialogsOpening_.end()) {
190 return nullptr;
191 }
192 auto result = sptr<NotificationBundleOption>::MakeSptr(*((*dialogIter)->bundleOption));
193 return result;
194 };
195
RemoveDialogInfoByBundleOption(const sptr<NotificationBundleOption> & bundle,std::unique_ptr<DialogInfo> & dialogInfoRemoved)196 void NotificationDialogManager::RemoveDialogInfoByBundleOption(const sptr<NotificationBundleOption>& bundle,
197 std::unique_ptr<DialogInfo>& dialogInfoRemoved)
198 {
199 std::lock_guard<ffrt::mutex> lock(dialogsMutex_);
200 std::string name = bundle->GetBundleName();
201 int32_t uid = bundle->GetUid();
202 auto dialogIter = std::find_if(dialogsOpening_.begin(), dialogsOpening_.end(),
203 [&](const std::unique_ptr<DialogInfo>& dialogInfo) {
204 return dialogInfo->bundleOption->GetBundleName() == name && dialogInfo->bundleOption->GetUid() == uid;
205 });
206 if (dialogIter == dialogsOpening_.end()) {
207 dialogInfoRemoved = nullptr;
208 return;
209 }
210 dialogInfoRemoved = std::move(*dialogIter);
211 dialogsOpening_.erase(dialogIter);
212 }
213
RemoveAllDialogInfos(std::list<std::unique_ptr<DialogInfo>> & dialogInfosRemoved)214 void NotificationDialogManager::RemoveAllDialogInfos(std::list<std::unique_ptr<DialogInfo>>& dialogInfosRemoved)
215 {
216 std::lock_guard<ffrt::mutex> lock(dialogsMutex_);
217 for (auto& dialogInfo : dialogsOpening_) {
218 dialogInfosRemoved.push_back(std::move(dialogInfo));
219 }
220 dialogsOpening_.clear();
221 }
222
SetHasPoppedDialog(const sptr<NotificationBundleOption> & bundleOption,bool hasPopped)223 bool NotificationDialogManager::SetHasPoppedDialog(
224 const sptr<NotificationBundleOption>& bundleOption, bool hasPopped)
225 {
226 ANS_LOGD("enter");
227 if (bundleOption == nullptr) {
228 return false;
229 }
230 ErrCode result = NotificationPreferences::GetInstance()->SetHasPoppedDialog(bundleOption, hasPopped);
231 return result == ERR_OK;
232 }
233
OnDialogButtonClicked(const std::string & bundleName,const int32_t & uid,bool enabled)234 bool NotificationDialogManager::OnDialogButtonClicked(const std::string& bundleName, const int32_t& uid, bool enabled)
235 {
236 ANS_LOGD("enter");
237 auto bundleOption = GetBundleOptionByBundleName(bundleName, uid);
238 if (bundleOption == nullptr) {
239 return false;
240 }
241
242 NotificationDialogManager::SetHasPoppedDialog(bundleOption, true);
243
244 ErrCode result = ans_.SetNotificationsEnabledForSpecialBundle(
245 NotificationDialogManager::DEFAULT_DEVICE_ID,
246 bundleOption, enabled);
247 #ifdef ENABLE_ANS_PRIVILEGED_MESSAGE_EXT_WRAPPER
248 if (!enabled) {
249 SetDialogPoppedTimeInterVal(bundleOption);
250 }
251 #endif
252 if (result != ERR_OK) {
253 ANS_LOGE("SetNotificationsEnabledForSpecialBundle Failed, code is %{public}d", result);
254 // Do not return here, need to clear the data
255 }
256 EnabledDialogStatus status = enabled ? EnabledDialogStatus::ALLOW_CLICKED : EnabledDialogStatus::DENY_CLICKED;
257 return HandleOneDialogClosed(bundleOption, status);
258 }
259
OnDialogCrashed(const std::string & bundleName,const int32_t & uid)260 bool NotificationDialogManager::OnDialogCrashed(const std::string& bundleName, const int32_t& uid)
261 {
262 ANS_LOGD("enter");
263 auto bundleOption = GetBundleOptionByBundleName(bundleName, uid);
264 if (bundleOption == nullptr) {
265 return false;
266 }
267
268 ErrCode result = ans_.SetNotificationsSystemEnabledForSpecialBundle(
269 NotificationDialogManager::DEFAULT_DEVICE_ID,
270 bundleOption, false, false);
271 if (result != ERR_OK) {
272 ANS_LOGE("SetNotificationsSystemEnabledForSpecialBundle Failed, code is %{public}d", result);
273 // Do not return here, need to clear the data
274 }
275 return HandleOneDialogClosed(bundleOption, EnabledDialogStatus::CRASHED);
276 }
277
OnDialogServiceDestroyed()278 bool NotificationDialogManager::OnDialogServiceDestroyed()
279 {
280 ANS_LOGD("enter");
281 return HandleAllDialogsClosed();
282 }
283
onRemoveBundle(const std::string bundleName,const int32_t & uid)284 bool NotificationDialogManager::onRemoveBundle(const std::string bundleName, const int32_t& uid)
285 {
286 auto bundleOption = GetBundleOptionByBundleName(bundleName, uid);
287 if (bundleOption == nullptr) {
288 ANS_LOGE("onRemoveBundle bundle is null. bundleName = %{public}s", bundleName.c_str());
289 return false;
290 }
291 std::unique_ptr<NotificationDialogManager::DialogInfo> dialogInfoRemoved = nullptr;
292 RemoveDialogInfoByBundleOption(bundleOption, dialogInfoRemoved);
293 return true;
294 }
295
HandleOneDialogClosed(sptr<NotificationBundleOption> bundleOption,EnabledDialogStatus status)296 bool NotificationDialogManager::HandleOneDialogClosed(
297 sptr<NotificationBundleOption> bundleOption,
298 EnabledDialogStatus status)
299 {
300 if (bundleOption == nullptr) {
301 return false;
302 }
303 std::unique_ptr<DialogInfo> dialogInfoRemoved = nullptr;
304 RemoveDialogInfoByBundleOption(bundleOption, dialogInfoRemoved);
305 if (dialogInfoRemoved != nullptr && dialogInfoRemoved->callback != nullptr) {
306 DialogStatusData statusData(status);
307 dialogInfoRemoved->callback->OnDialogStatusChanged(statusData);
308 }
309 return true;
310 }
311
HandleAllDialogsClosed()312 bool NotificationDialogManager::HandleAllDialogsClosed()
313 {
314 std::list<std::unique_ptr<DialogInfo>> dialogInfosRemoved;
315 RemoveAllDialogInfos(dialogInfosRemoved);
316 for (auto& dialogInfoSP : dialogInfosRemoved) {
317 if (dialogInfoSP != nullptr && dialogInfoSP->callback != nullptr) {
318 DialogStatusData statusData(EnabledDialogStatus::CRASHED);
319 dialogInfoSP->callback->OnDialogStatusChanged(statusData);
320 }
321 }
322 return true;
323 }
324
325 #ifdef ENABLE_ANS_PRIVILEGED_MESSAGE_EXT_WRAPPER
SetDialogPoppedTimeInterVal(const sptr<NotificationBundleOption> & bundleOption)326 void NotificationDialogManager::SetDialogPoppedTimeInterVal(const sptr<NotificationBundleOption> &bundleOption)
327 {
328 ANS_LOGD("SetDialogPoppedTimeInterVal called.");
329 int32_t userId = SUBSCRIBE_USER_INIT;
330 OsAccountManagerHelper::GetInstance().GetOsAccountLocalIdFromUid(bundleOption->GetUid(), userId);
331 EXTENTION_WRAPPER->SetDialogOpenSuccessTimeInterval(bundleOption, userId);
332 ANS_LOGD("SetDialogPoppedTimeInterVal end.");
333 }
334 #endif
335 } // namespace OHOS::Notification
336