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