• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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