• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 <sstream>
17 
18 #include "distributed_service.h"
19 
20 #include "notification_helper.h"
21 #include "distributed_client.h"
22 #include "request_box.h"
23 #include "state_box.h"
24 #include "in_process_call_wrapper.h"
25 #include "distributed_observer_service.h"
26 #include "notification_subscribe_info.h"
27 #include "distributed_liveview_all_scenarios_extension_wrapper.h"
28 #include "distributed_preference.h"
29 #include "batch_remove_box.h"
30 #include "ans_inner_errors.h"
31 #include "remove_box.h"
32 #include "response_box.h"
33 
34 namespace OHOS {
35 namespace Notification {
36 
37 const std::string DISTRIBUTED_LABEL = "ans_distributed";
38 const int32_t DEFAULT_FILTER_TYPE = 1;
39 constexpr const int32_t PUBLISH_ERROR_EVENT_CODE = 0;
40 constexpr const int32_t DELETE_ERROR_EVENT_CODE = 5;
41 constexpr const int32_t MODIFY_ERROR_EVENT_CODE = 6;
42 constexpr const int32_t BRANCH3_ID = 3;
43 
SubscribeTransDeviceType(uint16_t deviceType)44 std::string SubscribeTransDeviceType(uint16_t deviceType)
45 {
46     switch (deviceType) {
47         case DistributedHardware::DmDeviceType::DEVICE_TYPE_WATCH: {
48             return "wearable";
49         }
50         case DistributedHardware::DmDeviceType::DEVICE_TYPE_PAD: {
51             return "Pad";
52         }
53         default:
54             return "";
55     }
56 }
57 
SubscribeNotifictaion(const DistributedDeviceInfo peerDevice)58 void DistributedService::SubscribeNotifictaion(const DistributedDeviceInfo peerDevice)
59 {
60     if (peerDevice_.find(peerDevice.deviceId_) == peerDevice_.end()) {
61         ANS_LOGI("Local device no %{public}s %{public}d.", StringAnonymous(peerDevice.deviceId_).c_str(),
62             peerDevice.deviceType_);
63         return;
64     }
65 
66     int32_t userId = GetCurrentActiveUserId();
67     std::shared_ptr<DistribuedSubscriber> subscriber = std::make_shared<DistribuedSubscriber>();
68     subscriber->SetLocalDevice(localDevice_);
69     subscriber->SetPeerDevice(peerDevice);
70     sptr<NotificationSubscribeInfo> subscribeInfo = new NotificationSubscribeInfo();
71     std::vector<NotificationConstant::SlotType> slotTypes;
72     slotTypes.push_back(NotificationConstant::SlotType::LIVE_VIEW);
73     slotTypes.push_back(NotificationConstant::SlotType::SOCIAL_COMMUNICATION);
74     subscribeInfo->SetSlotTypes(slotTypes);
75     subscribeInfo->SetFilterType(DEFAULT_FILTER_TYPE);
76     subscribeInfo->AddDeviceType(SubscribeTransDeviceType(peerDevice.deviceType_));
77     subscribeInfo->AddAppUserId(userId);
78     subscribeInfo->SetNeedNotifyApplication(true);
79     subscribeInfo->SetNeedNotifyResponse(true);
80     int result = NotificationHelper::SubscribeNotification(subscriber, subscribeInfo);
81     if (result == 0) {
82         auto iter = subscriberMap_.find(peerDevice.deviceId_);
83         if (iter != subscriberMap_.end()) {
84             NotificationHelper::UnSubscribeNotification(iter->second);
85         }
86         subscriberMap_[peerDevice.deviceId_] = subscriber;
87         peerDevice_[peerDevice.deviceId_].peerState_ = DeviceState::STATE_ONLINE;
88         if (haCallback_ != nullptr) {
89             std::string reason = "deviceType: " + std::to_string(localDevice_.deviceType_) +
90                                  " ; deviceId: " + AnonymousProcessing(localDevice_.deviceId_);
91             haCallback_(PUBLISH_ERROR_EVENT_CODE, 0, BRANCH3_ID, reason);
92         }
93     }
94     ANS_LOGI("Subscribe notification %{public}s %{public}d %{public}d %{public}d.",
95         StringAnonymous(peerDevice.deviceId_).c_str(), peerDevice.deviceType_, userId, result);
96 }
97 
UnSubscribeNotifictaion(const std::string & deviceId,uint16_t deviceType)98 void DistributedService::UnSubscribeNotifictaion(const std::string &deviceId, uint16_t deviceType)
99 {
100     if (serviceQueue_ == nullptr) {
101         ANS_LOGE("Check handler is null.");
102         return;
103     }
104     std::function<void()> subscribeTask = std::bind([&, deviceId, deviceType]() {
105         auto deviceIter = peerDevice_.find(deviceId);
106         if (deviceIter != peerDevice_.end()) {
107             ANS_LOGI("UnSubscribe device %{public}s %{public}d.", StringAnonymous(deviceId).c_str(), deviceType);
108             peerDevice_.erase(deviceId);
109         }
110 
111         auto iter = subscriberMap_.find(deviceId);
112         if (iter == subscriberMap_.end()) {
113             ANS_LOGI("UnSubscribe invalid %{public}s %{public}d.", StringAnonymous(deviceId).c_str(), deviceType);
114             return;
115         }
116 
117         if (NotificationHelper::UnSubscribeNotification(iter->second) == 0) {
118             subscriberMap_.erase(deviceId);
119         }
120         ANS_LOGI("UnSubscribe notification %{public}s %{public}d.", StringAnonymous(deviceId).c_str(), deviceType);
121     });
122     serviceQueue_->submit(subscribeTask);
123 }
124 
SetNotificationContent(const std::shared_ptr<NotificationContent> & content,NotificationContent::Type type,NotifticationRequestBox & requestBox)125 void DistributedService::SetNotificationContent(const std::shared_ptr<NotificationContent> &content,
126     NotificationContent::Type type, NotifticationRequestBox &requestBox)
127 {
128     if (content == nullptr || content->GetNotificationContent() == nullptr) {
129         return;
130     }
131 
132     ANS_LOGI("Set Notification notification content %{public}d.", type);
133     switch (type) {
134         case NotificationContent::Type::PICTURE: {
135             auto picture = std::static_pointer_cast<NotificationPictureContent>(content->GetNotificationContent());
136             requestBox.SetNotificationTitle(picture->GetTitle());
137             requestBox.SetNotificationText(picture->GetText());
138             requestBox.SetNotificationAdditionalText(picture->GetAdditionalText());
139             requestBox.SetNotificationExpandedTitle(picture->GetExpandedTitle());
140             requestBox.SetNotificationBriefText(picture->GetBriefText());
141             requestBox.SetNotificationBigPicture(picture->GetBigPicture());
142             break;
143         }
144         case NotificationContent::Type::MULTILINE: {
145             auto multiline = std::static_pointer_cast<NotificationMultiLineContent>(content->GetNotificationContent());
146             requestBox.SetNotificationTitle(multiline->GetTitle());
147             requestBox.SetNotificationText(multiline->GetText());
148             requestBox.SetNotificationAdditionalText(multiline->GetAdditionalText());
149             requestBox.SetNotificationExpandedTitle(multiline->GetExpandedTitle());
150             requestBox.SetNotificationBriefText(multiline->GetBriefText());
151             requestBox.SetNotificationAllLines(multiline->GetAllLines());
152             break;
153         }
154         case NotificationContent::Type::LONG_TEXT: {
155             std::shared_ptr<NotificationLongTextContent> contentLong =
156                 std::static_pointer_cast<NotificationLongTextContent>(content->GetNotificationContent());
157             requestBox.SetNotificationTitle(contentLong->GetTitle());
158             requestBox.SetNotificationText(contentLong->GetText());
159             requestBox.SetNotificationAdditionalText(contentLong->GetAdditionalText());
160             requestBox.SetNotificationExpandedTitle(contentLong->GetExpandedTitle());
161             requestBox.SetNotificationBriefText(contentLong->GetBriefText());
162             requestBox.SetNotificationLongText(contentLong->GetLongText());
163             break;
164         }
165         case NotificationContent::Type::LIVE_VIEW:
166         case NotificationContent::Type::LOCAL_LIVE_VIEW:
167         case NotificationContent::Type::BASIC_TEXT:
168         default: {
169             std::shared_ptr<NotificationBasicContent> contentBasic =
170                 std::static_pointer_cast<NotificationBasicContent>(content->GetNotificationContent());
171             requestBox.SetNotificationTitle(contentBasic->GetTitle());
172             requestBox.SetNotificationText(contentBasic->GetText());
173             requestBox.SetNotificationAdditionalText(contentBasic->GetAdditionalText());
174             break;
175         }
176     }
177 }
178 
SetNotificationButtons(const sptr<NotificationRequest> notificationRequest,NotificationConstant::SlotType slotType,NotifticationRequestBox & requestBox)179 void DistributedService::SetNotificationButtons(const sptr<NotificationRequest> notificationRequest,
180     NotificationConstant::SlotType slotType, NotifticationRequestBox &requestBox)
181 {
182     if (notificationRequest == nullptr) {
183         return;
184     }
185     if (slotType == NotificationConstant::SlotType::SOCIAL_COMMUNICATION) {
186         auto actionButtons = notificationRequest->GetActionButtons();
187         if (actionButtons.empty()) {
188             ANS_LOGE("Check actionButtons is null.");
189             return;
190         }
191 
192         std::shared_ptr<NotificationActionButton> button = nullptr;
193         for (std::shared_ptr<NotificationActionButton> buttonItem : actionButtons) {
194             if (buttonItem != nullptr && buttonItem->GetUserInput() != nullptr &&
195                 !buttonItem->GetUserInput()->GetInputKey().empty()) {
196                 button = buttonItem;
197                 break;
198             }
199         }
200         if (button != nullptr && button->GetUserInput() != nullptr) {
201             requestBox.SetNotificationActionName(button->GetTitle());
202             requestBox.SetNotificationUserInput(button->GetUserInput()->GetInputKey());
203         }
204     }
205 }
206 
SendNotifictionRequest(const std::shared_ptr<Notification> request,const DistributedDeviceInfo & peerDevice,bool isSyncNotification)207 void DistributedService::SendNotifictionRequest(const std::shared_ptr<Notification> request,
208     const DistributedDeviceInfo& peerDevice, bool isSyncNotification)
209 {
210     NotifticationRequestBox requestBox;
211     if (request == nullptr || request->GetNotificationRequestPoint() == nullptr) {
212         return;
213     }
214 
215     auto requestPoint = request->GetNotificationRequestPoint();
216     ANS_LOGI("Dans OnConsumed %{public}s", requestPoint->Dump().c_str());
217     requestBox.SetAutoDeleteTime(requestPoint->GetAutoDeletedTime());
218     requestBox.SetFinishTime(requestPoint->GetFinishDeadLine());
219     requestBox.SetNotificationHashCode(request->GetKey());
220     requestBox.SetSlotType(static_cast<int32_t>(requestPoint->GetSlotType()));
221     requestBox.SetContentType(static_cast<int32_t>(requestPoint->GetNotificationType()));
222     if (isSyncNotification) {
223         requestBox.SetReminderFlag(0);
224     } else {
225         requestBox.SetReminderFlag(requestPoint->GetFlags()->GetReminderFlags());
226     }
227     if (request->GetBundleName().empty()) {
228         requestBox.SetCreatorBundleName(request->GetCreateBundle());
229     } else {
230         requestBox.SetCreatorBundleName(request->GetBundleName());
231     }
232     if (requestPoint->GetBigIcon() != nullptr) {
233         requestBox.SetBigIcon(requestPoint->GetBigIcon());
234     }
235     if (requestPoint->GetOverlayIcon() != nullptr) {
236         requestBox.SetOverlayIcon(requestPoint->GetOverlayIcon());
237     }
238     if (requestPoint->IsCommonLiveView()) {
239         std::vector<uint8_t> buffer;
240         DISTRIBUTED_LIVEVIEW_ALL_SCENARIOS_EXTENTION_WRAPPER->UpdateLiveviewEncodeContent(requestPoint, buffer);
241         requestBox.SetCommonLiveView(buffer);
242     }
243     SetNotificationButtons(requestPoint, requestPoint->GetSlotType(), requestBox);
244     SetNotificationContent(request->GetNotificationRequestPoint()->GetContent(),
245         requestPoint->GetNotificationType(), requestBox);
246     if (!requestBox.Serialize()) {
247         ANS_LOGW("Dans OnConsumed serialize failed.");
248         if (haCallback_ != nullptr) {
249             haCallback_(PUBLISH_ERROR_EVENT_CODE, -1, BRANCH3_ID, "serialization failed");
250         }
251         return;
252     }
253     this->code_ = PUBLISH_ERROR_EVENT_CODE;
254     DistributedClient::GetInstance().SendMessage(requestBox.GetByteBuffer(), requestBox.GetByteLength(),
255         TransDataType::DATA_TYPE_BYTES, peerDevice.deviceId_, peerDevice.deviceType_);
256 }
257 
OnConsumed(const std::shared_ptr<Notification> & request,const DistributedDeviceInfo & peerDevice)258 void DistributedService::OnConsumed(const std::shared_ptr<Notification> &request,
259     const DistributedDeviceInfo& peerDevice)
260 {
261     if (serviceQueue_ == nullptr) {
262         ANS_LOGE("Check handler is null.");
263         return;
264     }
265     std::function<void()> task = std::bind([&, peerDevice, request]() {
266         SendNotifictionRequest(request, peerDevice);
267     });
268     serviceQueue_->submit(task);
269 }
270 
OnBatchCanceled(const std::vector<std::shared_ptr<Notification>> & notifications,const DistributedDeviceInfo & peerDevice)271 void DistributedService::OnBatchCanceled(const std::vector<std::shared_ptr<Notification>>& notifications,
272     const DistributedDeviceInfo& peerDevice)
273 {
274     if (serviceQueue_ == nullptr) {
275         ANS_LOGE("check handler is null.");
276         return;
277     }
278     code_ = DELETE_ERROR_EVENT_CODE;
279     std::ostringstream keysStream;
280     std::ostringstream slotTypesStream;
281     for (auto notification : notifications) {
282         if (notification == nullptr || notification->GetNotificationRequestPoint() == nullptr) {
283             ANS_LOGE("notification or GetNotificationRequestPoint is nullptr");
284             continue;
285         }
286         ANS_LOGI("dans OnBatchCanceled %{public}s", notification->Dump().c_str());
287         keysStream << GetNotificationKey(notification) << ' ';
288         slotTypesStream << std::to_string(notification->GetNotificationRequestPoint()->GetSlotType()) << ' ';
289     }
290     std::string notificationKeys = keysStream.str();
291     std::string slotTypes = slotTypesStream.str();
292 
293     std::function<void()> task = std::bind([peerDevice, notifications, notificationKeys, slotTypes]() {
294         BatchRemoveNotificationBox batchRemoveBox;
295         if (!notificationKeys.empty()) {
296             batchRemoveBox.SetNotificationHashCode(notificationKeys);
297         }
298         batchRemoveBox.SetNotificationSlotTypes(slotTypes);
299 
300         if (!batchRemoveBox.Serialize()) {
301             ANS_LOGW("dans OnCanceled serialize failed");
302             return;
303         }
304         DistributedClient::GetInstance().SendMessage(batchRemoveBox.GetByteBuffer(), batchRemoveBox.GetByteLength(),
305             TransDataType::DATA_TYPE_MESSAGE, peerDevice.deviceId_, peerDevice.deviceType_);
306     });
307     serviceQueue_->submit(task);
308 }
309 
OnCanceled(const std::shared_ptr<Notification> & notification,const DistributedDeviceInfo & peerDevice)310 void DistributedService::OnCanceled(const std::shared_ptr<Notification>& notification,
311     const DistributedDeviceInfo& peerDevice)
312 {
313     if (serviceQueue_ == nullptr) {
314         ANS_LOGE("check handler is null");
315         return;
316     }
317     if (notification == nullptr || notification->GetNotificationRequestPoint() == nullptr) {
318         ANS_LOGE("notification or GetNotificationRequestPoint is nullptr");
319         return;
320     }
321     code_ = DELETE_ERROR_EVENT_CODE;
322     std::string notificationKey = GetNotificationKey(notification);
323     std::function<void()> task = std::bind([peerDevice, notification, notificationKey]() {
324         NotificationRemoveBox removeBox;
325         ANS_LOGI("dans OnCanceled %{public}s", notification->Dump().c_str());
326         removeBox.SetNotificationHashCode(notificationKey);
327         removeBox.setNotificationSlotType(notification->GetNotificationRequestPoint()->GetSlotType());
328         if (!removeBox.Serialize()) {
329             ANS_LOGW("dans OnCanceled serialize failed");
330             return;
331         }
332         DistributedClient::GetInstance().SendMessage(removeBox.GetByteBuffer(), removeBox.GetByteLength(),
333             TransDataType::DATA_TYPE_MESSAGE, peerDevice.deviceId_, peerDevice.deviceType_);
334     });
335     serviceQueue_->submit(task);
336 }
337 
GetNotificationKey(const std::shared_ptr<Notification> & notification)338 std::string DistributedService::GetNotificationKey(const std::shared_ptr<Notification>& notification)
339 {
340     if (notification == nullptr || notification->GetNotificationRequestPoint() == nullptr) {
341         ANS_LOGE("notification or GetNotificationRequestPoint is nullptr");
342         return "";
343     }
344     std::string notificationKey = notification->GetKey();
345     if (notification->GetNotificationRequestPoint()->GetDistributedCollaborate()) {
346         size_t pos = notificationKey.find(DISTRIBUTED_LABEL);
347         if (pos != std::string::npos) {
348             notificationKey.erase(pos, DISTRIBUTED_LABEL.length());
349         }
350     } else {
351         notificationKey = DISTRIBUTED_LABEL + notificationKey;
352     }
353     return notificationKey;
354 }
355 
OnResponse(const std::shared_ptr<NotificationOperationInfo> & operationInfo,const DistributedDeviceInfo & device)356 ErrCode DistributedService::OnResponse(
357     const std::shared_ptr<NotificationOperationInfo> & operationInfo, const DistributedDeviceInfo& device)
358 {
359     this->code_ = MODIFY_ERROR_EVENT_CODE;
360     NotificationResponseBox responseBox;
361     ANS_LOGI("dans OnResponse %{public}s", operationInfo->Dump().c_str());
362     if (operationInfo == nullptr) {
363         return ERR_ANS_INVALID_PARAM;
364     }
365     auto hashCode = operationInfo->GetHashCode();
366     if (hashCode.find(DISTRIBUTED_LABEL) == 0) {
367         hashCode.erase(0, DISTRIBUTED_LABEL.length());
368     }
369 
370     OperationType type = operationInfo->GetOperationType();
371     if (type == OperationType::DISTRIBUTE_OPERATION_REPLY) {
372         if (!responseBox.SetMessageType(NOTIFICATION_RESPONSE_REPLY_SYNC)) {
373             ANS_LOGW("dans OnResponse SetMessageType failed");
374             return ERR_ANS_TASK_ERR;
375         }
376         responseBox.SetActionName(operationInfo->GetActionName());
377         responseBox.SetUserInput(operationInfo->GetUserInput());
378     }
379 
380     responseBox.SetMatchType(MatchType::MATCH_SYN);
381     responseBox.SetOperationType(static_cast<int32_t>(type));
382     responseBox.SetNotificationHashCode(hashCode);
383     responseBox.SetOperationEventId(operationInfo->GetEventId());
384     responseBox.SetLocalDeviceId(localDevice_.deviceId_);
385     if (!responseBox.Serialize()) {
386         ANS_LOGW("dans OnResponse serialize failed");
387         return ERR_ANS_TASK_ERR;
388     }
389 
390     auto result = DistributedClient::GetInstance().SendMessage(responseBox.GetByteBuffer(), responseBox.GetByteLength(),
391         TransDataType::DATA_TYPE_MESSAGE, device.deviceId_, device.deviceType_);
392     if (result != ERR_OK) {
393         ANS_LOGE("dans OnResponse send message failed result: %{public}d", result);
394         result = ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
395     }
396     return result;
397 }
398 }
399 }
400