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 #ifdef DISTRIBUTED_FEATURE_MASTER
17 #include "distributed_unlock_listener_oper_service.h"
18
19 #include "ans_inner_errors.h"
20 #include "ans_log_wrapper.h"
21 #include "distributed_liveview_all_scenarios_extension_wrapper.h"
22 #include "notification_constant.h"
23 #include "notification_helper.h"
24 #include "time_service_client.h"
25 #include "analytics_util.h"
26 #include "distributed_data_define.h"
27
28 namespace OHOS {
29 namespace Notification {
30 namespace {
31 static const int64_t OPERATION_TIMEOUT = 30 * 1000;
32 }
OnTrigger()33 void UnlockListenerTimerInfo::OnTrigger()
34 {
35 UnlockListenerOperService::GetInstance().HandleOperationTimeOut(timerHashCode_);
36 }
37
GetInstance()38 UnlockListenerOperService& UnlockListenerOperService::GetInstance()
39 {
40 static UnlockListenerOperService unlockListenerOperService;
41 return unlockListenerOperService;
42 }
43
UnlockListenerOperService()44 UnlockListenerOperService::UnlockListenerOperService()
45 {
46 operationQueue_ = std::make_shared<ffrt::queue>("ans_operation");
47 if (operationQueue_ == nullptr) {
48 ANS_LOGE("ffrt create failed!");
49 return;
50 }
51 ANS_LOGI("Operation service init successfully.");
52 }
53
AddDelayTask(const std::string & hashCode,const int32_t jumpType,const int32_t deviceType,const int32_t btnIndex)54 void UnlockListenerOperService::AddDelayTask(const std::string& hashCode, const int32_t jumpType,
55 const int32_t deviceType, const int32_t btnIndex)
56 {
57 int32_t timeout = OPERATION_TIMEOUT;
58 int64_t expiredTime = GetCurrentTime() + timeout;
59 std::shared_ptr<UnlockListenerTimerInfo> timerInfo = std::make_shared<UnlockListenerTimerInfo>(hashCode);
60 sptr<MiscServices::TimeServiceClient> timer = MiscServices::TimeServiceClient::GetInstance();
61 if (timer == nullptr) {
62 ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
63 return;
64 }
65 uint64_t timerId = timer->CreateTimer(timerInfo);
66 timer->StartTimer(timerId, expiredTime);
67 std::lock_guard<ffrt::mutex> lock(mapLock_);
68 auto iterDelayTask = delayTaskMap_.find(hashCode);
69 if (iterDelayTask != delayTaskMap_.end()) {
70 ANS_LOGW("Operation delayTask has same key %{public}s.", hashCode.c_str());
71 delayTaskMap_.erase(iterDelayTask);
72 }
73 NotifictionJumpInfo jumpInfo = NotifictionJumpInfo(jumpType, btnIndex, deviceType, GetCurrentTime());
74 delayTaskMap_.insert_or_assign(hashCode, jumpInfo);
75
76 auto iterTimer = timerMap_.find(hashCode);
77 if (iterTimer != timerMap_.end()) {
78 ANS_LOGW("Operation timer has same key %{public}s.", hashCode.c_str());
79 if (iterTimer->second == NotificationConstant::INVALID_TIMER_ID) {
80 return;
81 }
82 MiscServices::TimeServiceClient::GetInstance()->StopTimer(iterTimer->second);
83 MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(iterTimer->second);
84 timerMap_.erase(iterTimer);
85 }
86 timerMap_.insert_or_assign(hashCode, timerId);
87 auto iterOder = std::find(hashCodeOrder_.begin(), hashCodeOrder_.end(), hashCode);
88 if (iterOder != hashCodeOrder_.end()) {
89 hashCodeOrder_.erase(iterOder);
90 }
91 hashCodeOrder_.push_back(hashCode);
92 ANS_LOGI("Operation add key %{public}s.", hashCode.c_str());
93 }
94
RemoveOperationResponse(const std::string & hashCode)95 void UnlockListenerOperService::RemoveOperationResponse(const std::string& hashCode)
96 {
97 std::lock_guard<ffrt::mutex> lock(mapLock_);
98 auto iterDelayTask = delayTaskMap_.find(hashCode);
99 if (iterDelayTask != delayTaskMap_.end()) {
100 delayTaskMap_.erase(iterDelayTask);
101 ANS_LOGI("Operation wantAgent erase %{public}s", hashCode.c_str());
102 }
103
104 auto iterTimer = timerMap_.find(hashCode);
105 if (iterTimer != timerMap_.end()) {
106 if (iterTimer->second == NotificationConstant::INVALID_TIMER_ID) {
107 return;
108 }
109 ANS_LOGI("Operation timer erase %{public}s %{public}" PRIu64, hashCode.c_str(), iterTimer->second);
110 MiscServices::TimeServiceClient::GetInstance()->StopTimer(iterTimer->second);
111 MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(iterTimer->second);
112 timerMap_.erase(iterTimer);
113 }
114 auto iterOder = std::find(hashCodeOrder_.begin(), hashCodeOrder_.end(), hashCode);
115 if (iterOder != hashCodeOrder_.end()) {
116 hashCodeOrder_.erase(iterOder);
117 }
118 }
119
ReplyOperationResponse()120 void UnlockListenerOperService::ReplyOperationResponse()
121 {
122 std::lock_guard<ffrt::mutex> lock(mapLock_);
123 ANS_LOGI("hashCodeOrder size %{public}zu", hashCodeOrder_.size());
124 for (std::string hashCode : hashCodeOrder_) {
125 auto iterDelayTask = delayTaskMap_.find(hashCode);
126 if (iterDelayTask != delayTaskMap_.end()) {
127 if (iterDelayTask->second.timeStamp + OPERATION_TIMEOUT > GetCurrentTime()) {
128 TriggerByJumpType(hashCode, iterDelayTask->second.jumpType,
129 iterDelayTask->second.deviceTypeId, iterDelayTask->second.btnIndex);
130 }
131 delayTaskMap_.erase(iterDelayTask);
132 }
133
134 auto iterTimer = timerMap_.find(hashCode);
135 if (iterTimer != timerMap_.end()) {
136 if (iterTimer->second == NotificationConstant::INVALID_TIMER_ID) {
137 return;
138 }
139 MiscServices::TimeServiceClient::GetInstance()->StopTimer(iterTimer->second);
140 MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(iterTimer->second);
141 timerMap_.erase(iterTimer);
142 }
143 }
144 hashCodeOrder_.clear();
145 }
146
HandleOperationTimeOut(const std::string & hashCode)147 void UnlockListenerOperService::HandleOperationTimeOut(const std::string& hashCode)
148 {
149 if (operationQueue_ == nullptr) {
150 ANS_LOGE("Operation queue is invalid.");
151 return;
152 }
153
154 ANS_LOGI("HandleOperationTimeOut hashCode: %{public}s", hashCode.c_str());
155 operationQueue_->submit_h([&, hashCode]() {
156 RemoveOperationResponse(hashCode);
157 });
158 }
159
TriggerByJumpType(const std::string & hashCode,const int32_t jumpType,const int32_t deviceType,const int32_t btnIndex)160 void UnlockListenerOperService::TriggerByJumpType(const std::string& hashCode, const int32_t jumpType,
161 const int32_t deviceType, const int32_t btnIndex)
162 {
163 sptr<NotificationRequest> notificationRequest = nullptr;
164 auto result = NotificationHelper::GetNotificationRequestByHashCode(hashCode, notificationRequest);
165 if (result != ERR_OK || notificationRequest == nullptr) {
166 ANS_LOGE("Check notificationRequest is null.");
167 return;
168 }
169 NotificationConstant::SlotType slotType = notificationRequest->GetSlotType();
170 std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> wantAgentPtr = nullptr;
171 if (jumpType >= NotificationConstant::DISTRIBUTE_JUMP_BY_LIVE_VIEW) {
172 if (!notificationRequest->IsCommonLiveView()) {
173 ANS_LOGE("jumpType for liveView but notification not liveView.");
174 return;
175 }
176 ErrCode res = DISTRIBUTED_LIVEVIEW_ALL_SCENARIOS_EXTENTION_WRAPPER->DistributedLiveViewOperation(
177 notificationRequest, jumpType, btnIndex);
178 AnalyticsUtil::GetInstance().OperationalReporting(deviceType, HaOperationType::COLLABORATE_JUMP, slotType);
179 ANS_LOGI("DistributedLiveViewOperation res: %{public}d.", static_cast<int32_t>(res));
180 return;
181 }
182 bool triggerWantInner;
183 if (DISTRIBUTED_LIVEVIEW_ALL_SCENARIOS_EXTENTION_WRAPPER->DistributedAncoNotificationClick(
184 notificationRequest, triggerWantInner) != ERR_OK) {
185 return;
186 }
187 if (triggerWantInner) {
188 std::vector<std::string> hashcodes;
189 hashcodes.push_back(hashCode);
190 NotificationHelper::RemoveNotifications(
191 hashcodes, NotificationConstant::DISTRIBUTED_COLLABORATIVE_CLICK_DELETE);
192 AnalyticsUtil::GetInstance().OperationalReporting(deviceType, HaOperationType::COLLABORATE_JUMP, slotType);
193 return;
194 }
195 if (jumpType == NotificationConstant::DISTRIBUTE_JUMP_BY_NTF) {
196 wantAgentPtr = GetNtfWantAgentPtr(hashCode);
197 } else if (jumpType == NotificationConstant::DISTRIBUTE_JUMP_BY_BTN) {
198 GetNtfBtnWantAgentPtr(hashCode, btnIndex, wantAgentPtr);
199 }
200
201 if (wantAgentPtr == nullptr) {
202 ANS_LOGE("DealMultiScreenSyncOper fail cause wantAgentPtr is null.");
203 return;
204 }
205 if (LaunchWantAgent(wantAgentPtr) == ERR_OK) {
206 AnalyticsUtil::GetInstance().OperationalReporting(deviceType, HaOperationType::COLLABORATE_JUMP, slotType);
207 std::vector<std::string> hashcodes;
208 hashcodes.push_back(hashCode);
209 NotificationHelper::RemoveNotifications(
210 hashcodes, NotificationConstant::DISTRIBUTED_COLLABORATIVE_CLICK_DELETE);
211 }
212 }
213
GetNtfBtnWantAgentPtr(const std::string & hashCode,const int32_t btnIndex,std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> & wantAgentPtr)214 ErrCode UnlockListenerOperService::GetNtfBtnWantAgentPtr(const std::string& hashCode,
215 const int32_t btnIndex, std::shared_ptr<AbilityRuntime::WantAgent::WantAgent>& wantAgentPtr)
216 {
217 sptr<NotificationRequest> notificationRequest = nullptr;
218 auto result = NotificationHelper::GetNotificationRequestByHashCode(hashCode, notificationRequest);
219 if (result != ERR_OK || notificationRequest == nullptr) {
220 ANS_LOGE("Check notificationRequest is null.");
221 return ERR_ANS_NOTIFICATION_NOT_EXISTS;
222 }
223
224 auto actionButtons = notificationRequest->GetActionButtons();
225 if (actionButtons.empty() || actionButtons.size() <= static_cast<unsigned long>(btnIndex) || btnIndex < 0) {
226 ANS_LOGE("Check actionButtons is null.");
227 return ERR_ANS_INVALID_PARAM;
228 }
229
230 std::shared_ptr<NotificationActionButton> clickedBtn;
231 int32_t replyBtnNum = 0;
232 for (int i = 0; i < static_cast<int32_t>(actionButtons.size()) &&
233 btnIndex + replyBtnNum < static_cast<int32_t>(actionButtons.size()); i++) {
234 if (actionButtons[i] == nullptr) {
235 ANS_LOGE("NotificationRequest button is invalid, button index: %{public}d.", i);
236 return ERR_ANS_INVALID_PARAM;
237 }
238 if (actionButtons[i]->GetUserInput() != nullptr) {
239 replyBtnNum++;
240 continue;
241 }
242 if (btnIndex + replyBtnNum == i) {
243 clickedBtn = actionButtons[i];
244 }
245 }
246 if (clickedBtn == nullptr) {
247 ANS_LOGE("NotificationRequest btnIndex is invalid.");
248 return ERR_ANS_INVALID_PARAM;
249 }
250 wantAgentPtr = clickedBtn->GetWantAgent();
251 if (wantAgentPtr == nullptr) {
252 ANS_LOGE("Check wantAgentPtr is null.");
253 return ERR_ANS_INVALID_PARAM;
254 }
255 return ERR_OK;
256 }
257
GetNtfWantAgentPtr(const std::string & hashCode)258 std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> UnlockListenerOperService::GetNtfWantAgentPtr(
259 const std::string& hashCode)
260 {
261 sptr<NotificationRequest> notificationRequest = nullptr;
262 auto result = NotificationHelper::GetNotificationRequestByHashCode(hashCode, notificationRequest);
263 if (result != ERR_OK || notificationRequest == nullptr) {
264 ANS_LOGE("Check notificationRequest is null.");
265 return nullptr;
266 }
267 return notificationRequest->GetWantAgent();
268 }
269
LaunchWantAgent(const std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> wantAgentPtr)270 ErrCode UnlockListenerOperService::LaunchWantAgent(
271 const std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> wantAgentPtr)
272 {
273 std::shared_ptr<AAFwk::Want> want = std::make_shared<AAFwk::Want>();
274 OHOS::AbilityRuntime::WantAgent::TriggerInfo triggerInfo("", nullptr, want, 0);
275 sptr<AbilityRuntime::WantAgent::CompletedDispatcher> data;
276 ErrCode res =
277 AbilityRuntime::WantAgent::WantAgentHelper::TriggerWantAgent(wantAgentPtr, nullptr, triggerInfo, data, nullptr);
278 ANS_LOGI("LaunchWantAgent result: %{public}d.", static_cast<int32_t>(res));
279 return res;
280 }
281
GetCurrentTime()282 int64_t UnlockListenerOperService::GetCurrentTime()
283 {
284 auto now = std::chrono::system_clock::now();
285 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
286 return duration.count();
287 }
288 }
289 }
290 #endif
291