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