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