• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 "distributed_operation_service.h"
17 
18 #include "response_box.h"
19 #include "match_box.h"
20 #include "ans_inner_errors.h"
21 #include "notification_helper.h"
22 #include "distributed_data_define.h"
23 #include "distributed_device_service.h"
24 #include "distributed_unlock_listener_oper_service.h"
25 #include "int_wrapper.h"
26 #include "string_wrapper.h"
27 #include "analytics_util.h"
28 #include "distributed_client.h"
29 #include "power_mgr_client.h"
30 #include "ans_inner_errors.h"
31 #include "distributed_operation_helper.h"
32 #include "ability_manager_helper.h"
33 #include "distributed_liveview_all_scenarios_extension_wrapper.h"
34 #ifdef SCREENLOCK_MGR_ENABLE
35 #include "screenlock_manager.h"
36 #endif
37 #include "distributed_send_adapter.h"
38 
39 namespace OHOS {
40 namespace Notification {
41 
42 static const std::string DISTRIBUTED_LABEL = "ans_distributed";
43 
GetInstance()44 DistributedOperationService& DistributedOperationService::GetInstance()
45 {
46     static DistributedOperationService distributedOperationService;
47     return distributedOperationService;
48 }
49 
HandleNotificationOperation(const std::shared_ptr<TlvBox> & boxMessage)50 void DistributedOperationService::HandleNotificationOperation(const std::shared_ptr<TlvBox>& boxMessage)
51 {
52     int32_t operationType = 0;
53     int32_t jumpType = 0;
54     int32_t matchType = 0;
55     int32_t peerDeviceType = DistributedHardware::DmDeviceType::DEVICE_TYPE_WATCH;
56     std::string hashCode;
57     NotificationResponseBox responseBox = NotificationResponseBox(boxMessage);
58     responseBox.GetOperationType(operationType);
59     responseBox.GetOperationJumpType(jumpType);
60     responseBox.GetMatchType(matchType);
61     responseBox.GetNotificationHashCode(hashCode);
62     ANS_LOGI("handle response, hashCode: %{public}s, operationType: %{public}d, matchType: %{public}d, \
63         jumpType: %{public}d.", hashCode.c_str(), operationType, matchType, jumpType);
64 #ifdef DISTRIBUTED_FEATURE_MASTER
65     if (matchType != MatchType::MATCH_SYN) {
66         return;
67     }
68     std::string deviceId;
69     DistributedDeviceInfo device;
70     if (responseBox.GetLocalDeviceId(deviceId)) {
71         if (DistributedDeviceService::GetInstance().GetDeviceInfo(deviceId, device)) {
72             peerDeviceType = device.deviceType_;
73         }
74     }
75     if (static_cast<OperationType>(operationType) == DISTRIBUTE_OPERATION_JUMP_BY_TYPE) {
76         int32_t btnIndex;
77         responseBox.GetOperationBtnIndex(btnIndex);
78 #ifdef SCREENLOCK_MGR_ENABLE
79         if (ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked()) {
80             UnlockListenerOperService::GetInstance().AddDelayTask(hashCode, jumpType, peerDeviceType, btnIndex);
81             return;
82         }
83 #endif
84         UnlockListenerOperService::GetInstance().TriggerByJumpType(hashCode, jumpType, peerDeviceType, btnIndex);
85         return;
86     }
87     TriggerByOperationType(hashCode, peerDeviceType, operationType, responseBox);
88 #else
89     if (matchType == MatchType::MATCH_ACK) {
90         ResponseOperationResult(hashCode, responseBox);
91     }
92 #endif
93 }
94 
95 #ifdef DISTRIBUTED_FEATURE_MASTER
GetCurrentTime()96 static int64_t GetCurrentTime()
97 {
98     auto now = std::chrono::system_clock::now();
99     auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
100     return duration.count();
101 }
102 
TriggerReplyWantAgent(const sptr<NotificationRequest> request,std::string actionName,int32_t errorCode,std::string desc)103 static void TriggerReplyWantAgent(const sptr<NotificationRequest> request,
104     std::string actionName, int32_t errorCode, std::string desc)
105 {
106     AAFwk::WantParams extraInfo;
107     extraInfo.SetParam("desc", AAFwk::String::Box(desc));
108     extraInfo.SetParam("errorCode", AAFwk::Integer::Box(errorCode));
109     extraInfo.SetParam("actionName", AAFwk::String::Box(actionName));
110     DISTRIBUTED_LIVEVIEW_ALL_SCENARIOS_EXTENTION_WRAPPER->TriggerPushWantAgent(request,
111         OperationType::DISTRIBUTE_OPERATION_REPLY, extraInfo);
112 }
113 
GetNotificationButtonWantPtr(const std::string & hashCode,const std::string & actionName,std::shared_ptr<AAFwk::Want> & wantPtr,sptr<NotificationRequest> & request,std::string & userInputKey)114 static ErrCode GetNotificationButtonWantPtr(const std::string& hashCode, const std::string& actionName,
115     std::shared_ptr<AAFwk::Want>& wantPtr, sptr<NotificationRequest>& request, std::string& userInputKey)
116 {
117     sptr<NotificationRequest> notificationRequest = nullptr;
118     auto result = NotificationHelper::GetNotificationRequestByHashCode(hashCode, notificationRequest);
119     if (result != ERR_OK || notificationRequest == nullptr) {
120         ANS_LOGE("Check notificationRequest is null.");
121         return ERR_ANS_NOTIFICATION_NOT_EXISTS;
122     }
123 
124     request = notificationRequest;
125     auto actionButtons = notificationRequest->GetActionButtons();
126     if (actionButtons.empty()) {
127         ANS_LOGE("Check actionButtons is null.");
128         return ERR_ANS_INVALID_PARAM;
129     }
130 
131     std::shared_ptr<NotificationActionButton> button = nullptr;
132     for (std::shared_ptr<NotificationActionButton> buttonItem : actionButtons) {
133         if (buttonItem != nullptr && buttonItem->GetUserInput() != nullptr &&
134             buttonItem->GetTitle() == actionName) {
135             button = buttonItem;
136             break;
137         }
138     }
139 
140     if (button == nullptr) {
141         ANS_LOGE("Check user input is null %{public}s.", actionName.c_str());
142         return ERR_ANS_INVALID_PARAM;
143     }
144     if (button->GetUserInput() != nullptr) {
145         userInputKey = button->GetUserInput()->GetInputKey();
146     }
147     if (userInputKey.empty()) {
148         ANS_LOGE("Check userInputKey is null.");
149         return ERR_ANS_INVALID_PARAM;
150     }
151     std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> wantAgentPtr = button->GetWantAgent();
152     if (wantAgentPtr == nullptr) {
153         ANS_LOGE("Check wantAgentPtr is null.");
154         return ERR_ANS_INVALID_PARAM;
155     }
156 
157     std::shared_ptr<AbilityRuntime::WantAgent::PendingWant> pendingWantPtr = wantAgentPtr->GetPendingWant();
158     if (pendingWantPtr == nullptr) {
159         ANS_LOGE("Check pendingWantPtr is null.");
160         return ERR_ANS_INVALID_PARAM;
161     }
162 
163     wantPtr = pendingWantPtr->GetWant(pendingWantPtr->GetTarget());
164     if (wantPtr == nullptr) {
165         ANS_LOGE("Check wantPtr is null.");
166         return ERR_ANS_INVALID_PARAM;
167     }
168     return ERR_OK;
169 }
170 
GetNotificationWantPtr(const std::string & hashCode)171 static std::shared_ptr<AAFwk::Want> GetNotificationWantPtr(const std::string& hashCode)
172 {
173     sptr<NotificationRequest> notificationRequest = nullptr;
174     auto result = NotificationHelper::GetNotificationRequestByHashCode(hashCode, notificationRequest);
175     if (result != ERR_OK || notificationRequest == nullptr) {
176         ANS_LOGE("Check notificationRequest is null.");
177         return nullptr;
178     }
179 
180     std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> wantAgentPtr = notificationRequest->GetWantAgent();
181     if (wantAgentPtr == nullptr) {
182         ANS_LOGE("Check wantAgentPtr is null.");
183         return nullptr;
184     }
185 
186     std::shared_ptr<AbilityRuntime::WantAgent::PendingWant> pendingWantPtr = wantAgentPtr->GetPendingWant();
187     if (pendingWantPtr == nullptr) {
188         ANS_LOGE("Check pendingWantPtr is null.");
189         return nullptr;
190     }
191 
192     return pendingWantPtr->GetWant(pendingWantPtr->GetTarget());
193 }
194 
ReplyOperationResponse(const std::string & hashCode,const NotificationResponseBox & responseBox,OperationType operationType,uint32_t result)195 void DistributedOperationService::ReplyOperationResponse(const std::string& hashCode,
196     const NotificationResponseBox& responseBox, OperationType operationType, uint32_t result)
197 {
198     std::string eventId;
199     std::string deviceId;
200     responseBox.GetOperationEventId(eventId);
201     responseBox.GetLocalDeviceId(deviceId);
202 
203     DistributedDeviceInfo device;
204     if (!DistributedDeviceService::GetInstance().GetDeviceInfo(deviceId, device)) {
205         ANS_LOGI("Dans get deviceId unknonw %{public}s.", StringAnonymous(deviceId).c_str());
206         return;
207     }
208 
209     std::shared_ptr<NotificationResponseBox> replyBox = std::make_shared<NotificationResponseBox>();
210     replyBox->SetResponseResult(result);
211     replyBox->SetNotificationHashCode(hashCode);
212     replyBox->SetOperationEventId(eventId);
213     replyBox->SetMatchType(MatchType::MATCH_ACK);
214     replyBox->SetOperationType(operationType);
215 
216     if (!replyBox->Serialize()) {
217         ANS_LOGW("dans OnResponse reply serialize failed");
218         return;
219     }
220 
221     auto packageInfo = std::make_shared<PackageInfo>(replyBox, device,
222         TransDataType::DATA_TYPE_MESSAGE, MODIFY_ERROR_EVENT_CODE);
223     DistributedSendAdapter::GetInstance().SendPackage(packageInfo);
224     ANS_LOGI("Dans reply operation %{public}s.", StringAnonymous(deviceId).c_str());
225 }
226 
TriggerReplyApplication(const std::string & hashCode,const int32_t deviceType,const NotificationResponseBox & responseBox)227 int32_t DistributedOperationService::TriggerReplyApplication(const std::string& hashCode,
228     const int32_t deviceType, const NotificationResponseBox& responseBox)
229 {
230     std::string actionName;
231     std::string userInput;
232     std::string userInputKey;
233     responseBox.GetActionName(actionName);
234     responseBox.GetUserInput(userInput);
235 
236     std::shared_ptr<AAFwk::Want> wantPtr = nullptr;
237     sptr<NotificationRequest> request = nullptr;
238     auto result = GetNotificationButtonWantPtr(hashCode, actionName, wantPtr, request, userInputKey);
239     if (result != ERR_OK || wantPtr == nullptr) {
240         AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, result,
241             BRANCH4_ID, "reply get button failed");
242         TriggerReplyWantAgent(request, actionName, result, "reply get button failed");
243         return result;
244     }
245 
246     if (wantPtr->GetBoolParam(AAFwk::Want::PARAM_RESV_CALL_TO_FOREGROUND, false)) {
247         ANS_LOGE("Not support foreground.");
248         AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, ERR_ANS_DISTRIBUTED_OPERATION_FAILED,
249             BRANCH4_ID, "reply foreground failed");
250         TriggerReplyWantAgent(request, actionName, ERR_ANS_DISTRIBUTED_OPERATION_FAILED, "reply foreground failed");
251         return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
252     }
253 
254     auto ret = AbilityManagerHelper::GetInstance().ConnectAbility(hashCode, *wantPtr, userInputKey, userInput);
255     ANS_LOGI("StartAbility result:%{public}d", ret);
256     if (ret == ERR_OK) {
257         TriggerReplyWantAgent(request, actionName, ERR_OK, "");
258         AnalyticsUtil::GetInstance().OperationalReporting(deviceType, HaOperationType::COLLABORATE_REPLY,
259             NotificationConstant::SlotType::SOCIAL_COMMUNICATION);
260     } else {
261         TriggerReplyWantAgent(request, actionName, ret, "ability reply failed");
262         AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, ret,
263             BRANCH4_ID, "ability reply failed");
264         return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
265     }
266     return ERR_OK;
267 }
268 
TriggerJumpApplication(const std::string & hashCode,const int32_t deviceType)269 void DistributedOperationService::TriggerJumpApplication(const std::string& hashCode, const int32_t deviceType)
270 {
271     auto wantPtr = GetNotificationWantPtr(hashCode);
272     if (wantPtr == nullptr) {
273         ANS_LOGE("Get pendingWantPtr is null.");
274         return;
275     }
276 
277     if (!PowerMgr::PowerMgrClient::GetInstance().IsScreenOn()) {
278         auto ret = PowerMgr::PowerMgrClient::GetInstance().WakeupDevice();
279         if (ret != PowerMgr::PowerErrors::ERR_OK) {
280             ANS_LOGW("Wake up device %{public}d", ret);
281             return;
282         }
283     }
284 
285 #ifdef SCREENLOCK_MGR_ENABLE
286     if (ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked()) {
287         OperationInfo info;
288         info.deviceTypeId = deviceType;
289         info.type = OperationType::DISTRIBUTE_OPERATION_JUMP;
290         info.eventId = std::to_string(GetCurrentTime());
291         sptr<UnlockScreenCallback> listener = new (std::nothrow) UnlockScreenCallback(info.eventId);
292         int32_t unlockResult =
293             ScreenLock::ScreenLockManager::GetInstance()->Unlock(ScreenLock::Action::UNLOCKSCREEN, listener);
294         ANS_LOGI("unlock result:%{public}d", unlockResult);
295         if (unlockResult != ERR_OK) {
296             AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, unlockResult,
297                 BRANCH6_ID, "unlock failed");
298         }
299         info.want = *wantPtr;
300         OperationService::GetInstance().AddOperation(info);
301         return;
302     }
303 #endif
304     auto ret = AAFwk::AbilityManagerClient::GetInstance()->StartAbility(*wantPtr);
305     ANS_LOGI("StartAbility result:%{public}d", ret);
306     if (ret == ERR_OK) {
307         AnalyticsUtil::GetInstance().OperationalReporting(deviceType, HaOperationType::COLLABORATE_JUMP,
308             NotificationConstant::SlotType::LIVE_VIEW);
309     } else {
310         AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, 0, ret, "pull up failed");
311     }
312     AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, ret, BRANCH9_ID, "pull up success");
313 }
314 
TriggerByOperationType(const std::string & hashCode,const int32_t deviceType,const int32_t operationType,const NotificationResponseBox & responseBox)315 void DistributedOperationService::TriggerByOperationType(const std::string& hashCode, const int32_t deviceType,
316     const int32_t operationType, const NotificationResponseBox& responseBox)
317 {
318     if (static_cast<OperationType>(operationType) == OperationType::DISTRIBUTE_OPERATION_JUMP) {
319         TriggerJumpApplication(hashCode, deviceType);
320     } else if (static_cast<OperationType>(operationType) == OperationType::DISTRIBUTE_OPERATION_REPLY) {
321         ErrCode result = TriggerReplyApplication(hashCode, deviceType, responseBox);
322         ReplyOperationResponse(hashCode, responseBox, OperationType::DISTRIBUTE_OPERATION_REPLY, result);
323     }
324 }
325 #else
326 
OnOperationResponse(const std::shared_ptr<NotificationOperationInfo> & operationInfo,const DistributedDeviceInfo & device)327 int32_t DistributedOperationService::OnOperationResponse(
328     const std::shared_ptr<NotificationOperationInfo>& operationInfo, const DistributedDeviceInfo& device)
329 {
330     std::shared_ptr<NotificationResponseBox> responseBox = std::make_shared<NotificationResponseBox>();
331     ANS_LOGI("dans OnResponse %{public}s", operationInfo->Dump().c_str());
332     if (operationInfo == nullptr) {
333         return ERR_ANS_INVALID_PARAM;
334     }
335     auto hashCode = operationInfo->GetHashCode();
336     if (hashCode.find(DISTRIBUTED_LABEL) == 0) {
337         hashCode.erase(0, DISTRIBUTED_LABEL.length());
338     }
339 
340     OperationType type = operationInfo->GetOperationType();
341     if (type == OperationType::DISTRIBUTE_OPERATION_REPLY) {
342         if (!responseBox->SetMessageType(NOTIFICATION_RESPONSE_REPLY_SYNC)) {
343             ANS_LOGW("dans OnResponse SetMessageType failed");
344             return ERR_ANS_TASK_ERR;
345         }
346         responseBox->SetActionName(operationInfo->GetActionName());
347         responseBox->SetUserInput(operationInfo->GetUserInput());
348     }
349 
350     if (type == OperationType::DISTRIBUTE_OPERATION_JUMP_BY_TYPE) {
351         responseBox->SetOperationJumpType(operationInfo->GetJumpType());
352         if (operationInfo->GetBtnIndex() >= 0 && operationInfo->GetBtnIndex() < NotificationConstant::MAX_BTN_NUM) {
353             responseBox->SetOperationBtnIndex(operationInfo->GetBtnIndex());
354         }
355     }
356     auto localDevice = DistributedDeviceService::GetInstance().GetLocalDevice();
357     responseBox->SetMatchType(MatchType::MATCH_SYN);
358     responseBox->SetOperationType(static_cast<int32_t>(type));
359     responseBox->SetNotificationHashCode(hashCode);
360     responseBox->SetOperationEventId(operationInfo->GetEventId());
361     responseBox->SetLocalDeviceId(localDevice.deviceId_);
362     if (!responseBox->Serialize()) {
363         ANS_LOGW("dans OnResponse serialize failed");
364         return ERR_ANS_TASK_ERR;
365     }
366 
367     LaunchProjectionApp(device, localDevice);
368     auto result = DistributedClient::GetInstance().SendMessage(responseBox, TransDataType::DATA_TYPE_MESSAGE,
369         device.deviceId_, MODIFY_ERROR_EVENT_CODE);
370     if (result != ERR_OK) {
371         ANS_LOGE("dans OnResponse send message failed result: %{public}d", result);
372         result = ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
373     }
374     return result;
375 }
376 
ResponseOperationResult(const std::string & hashCode,const NotificationResponseBox & responseBox)377 void DistributedOperationService::ResponseOperationResult(const std::string& hashCode,
378     const NotificationResponseBox& responseBox)
379 {
380     int32_t result = 0;
381     std::string eventId;
382     responseBox.GetOperationEventId(eventId);
383     responseBox.GetResponseResult(result);
384     auto ret = NotificationHelper::ReplyDistributeOperation(DISTRIBUTED_LABEL + hashCode + eventId, result);
385     ANS_LOGI("HandleOperationResponse hashcode %{public}s, result:%{public}d %{public}d",
386         hashCode.c_str(), result, ret);
387 }
388 
LaunchProjectionApp(const DistributedDeviceInfo & peerDevice,const DistributedDeviceInfo & localDevice)389 void DistributedOperationService::LaunchProjectionApp(
390     const DistributedDeviceInfo& peerDevice, const DistributedDeviceInfo& localDevice)
391 {
392     if ((localDevice.deviceType_ != DistributedHardware::DmDeviceType::DEVICE_TYPE_PAD &&
393         localDevice.deviceType_ != DistributedHardware::DmDeviceType::DEVICE_TYPE_PC) ||
394         peerDevice.deviceType_ != DistributedHardware::DmDeviceType::DEVICE_TYPE_PHONE) {
395         ANS_LOGI("Can not launch projectionApp");
396         return;
397     }
398     int32_t result =
399         DISTRIBUTED_LIVEVIEW_ALL_SCENARIOS_EXTENTION_WRAPPER->RestoreCollaborationWindow(peerDevice.networkId_);
400     ANS_LOGI("RestoreCollaborationWindow result: %{public}d, networkId: %{public}s",
401         result, StringAnonymous(peerDevice.networkId_).c_str());
402 }
403 #endif
404 }
405 }
406