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 #include "notification_content.h"
17 #include "ans_log_wrapper.h"
18 #include "notification_local_live_view_content.h"
19 
20 namespace OHOS {
21 namespace Notification {
22 std::map<std::string, NotificationContent::Type> NotificationContent::convertStrToContentType_;
23 
NotificationContent(const std::shared_ptr<NotificationNormalContent> & normalContent)24 NotificationContent::NotificationContent(const std::shared_ptr<NotificationNormalContent> &normalContent)
25 {
26     if (!normalContent) {
27         ANS_LOGE("NotificationNormalContent can not be null");
28         return;
29     }
30 
31     contentType_ = NotificationContent::Type::BASIC_TEXT;
32     content_ = normalContent;
33 }
34 
NotificationContent(const std::shared_ptr<NotificationLongTextContent> & longTextContent)35 NotificationContent::NotificationContent(const std::shared_ptr<NotificationLongTextContent> &longTextContent)
36 {
37     if (!longTextContent) {
38         ANS_LOGE("NotificationLongTextContent can not be null");
39         return;
40     }
41 
42     contentType_ = NotificationContent::Type::LONG_TEXT;
43     content_ = longTextContent;
44 }
45 
NotificationContent(const std::shared_ptr<NotificationPictureContent> & pictureContent)46 NotificationContent::NotificationContent(const std::shared_ptr<NotificationPictureContent> &pictureContent)
47 {
48     if (!pictureContent) {
49         ANS_LOGE("NotificationPictureContent can not be null");
50         return;
51     }
52 
53     contentType_ = NotificationContent::Type::PICTURE;
54     content_ = pictureContent;
55 }
56 
NotificationContent(const std::shared_ptr<NotificationConversationalContent> & conversationContent)57 NotificationContent::NotificationContent(const std::shared_ptr<NotificationConversationalContent> &conversationContent)
58 {
59     if (!conversationContent) {
60         ANS_LOGE("NotificationConversationalContent can not be null");
61         return;
62     }
63 
64     contentType_ = NotificationContent::Type::CONVERSATION;
65     content_ = conversationContent;
66 }
67 
NotificationContent(const std::shared_ptr<NotificationMultiLineContent> & multiLineContent)68 NotificationContent::NotificationContent(const std::shared_ptr<NotificationMultiLineContent> &multiLineContent)
69 {
70     if (!multiLineContent) {
71         ANS_LOGE("NotificationMultiLineContent can not be null");
72         return;
73     }
74 
75     contentType_ = NotificationContent::Type::MULTILINE;
76     content_ = multiLineContent;
77 }
78 
NotificationContent(const std::shared_ptr<NotificationMediaContent> & mediaContent)79 NotificationContent::NotificationContent(const std::shared_ptr<NotificationMediaContent> &mediaContent)
80 {
81     if (!mediaContent) {
82         ANS_LOGE("NotificationMediaContent can not be null");
83         return;
84     }
85 
86     contentType_ = NotificationContent::Type::MEDIA;
87     content_ = mediaContent;
88 }
89 
NotificationContent(const std::shared_ptr<NotificationLocalLiveViewContent> & localLiveViewContent)90 NotificationContent::NotificationContent(const std::shared_ptr<NotificationLocalLiveViewContent> &localLiveViewContent)
91 {
92     if (!localLiveViewContent) {
93         ANS_LOGE("NotificationLocalLiveViewContent can not be null");
94         return;
95     }
96 
97     contentType_ = NotificationContent::Type::LOCAL_LIVE_VIEW;
98     content_ = localLiveViewContent;
99     content_->SetContentType(static_cast<int32_t>(NotificationContent::Type::LOCAL_LIVE_VIEW));
100 }
101 
NotificationContent(const std::shared_ptr<NotificationLiveViewContent> & liveViewContent)102 NotificationContent::NotificationContent(const std::shared_ptr<NotificationLiveViewContent> &liveViewContent)
103 {
104     if (!liveViewContent) {
105         ANS_LOGE("NotificationLiveViewContent can not be null");
106         return;
107     }
108 
109     contentType_ = NotificationContent::Type::LIVE_VIEW;
110     content_ = liveViewContent;
111 }
112 
~NotificationContent()113 NotificationContent::~NotificationContent()
114 {}
115 
GetContentType() const116 NotificationContent::Type NotificationContent::GetContentType() const
117 {
118     return contentType_;
119 }
120 
GetNotificationContent() const121 std::shared_ptr<NotificationBasicContent> NotificationContent::GetNotificationContent() const
122 {
123     return content_;
124 }
125 
Dump()126 std::string NotificationContent::Dump()
127 {
128     std::string contentTypeStr =   (contentType_ == NotificationContent::Type::BASIC_TEXT)          ? "BASIC_TEXT"
129                                  : (contentType_ == NotificationContent::Type::CONVERSATION)        ? "CONVERSATION"
130                                  : (contentType_ == NotificationContent::Type::LONG_TEXT)           ? "LONG_TEXT"
131                                  : (contentType_ == NotificationContent::Type::MEDIA)               ? "MEDIA"
132                                  : (contentType_ == NotificationContent::Type::MULTILINE)           ? "MULTILINE"
133                                  : (contentType_ == NotificationContent::Type::PICTURE)             ? "PICTURE"
134                                  : (contentType_ == NotificationContent::Type::LOCAL_LIVE_VIEW)     ? "LOCAL_LIVE_VIEW"
135                                  : (contentType_ == NotificationContent::Type::LIVE_VIEW)           ? "LIVE_VIEW"
136                                  : "NONE";
137     return "NotificationContent{ "
138             "contentType = " + contentTypeStr +
139             ", content = " + (content_ ? content_->Dump() : "null") +
140             " }";
141 }
142 
ToJson(nlohmann::json & jsonObject) const143 bool NotificationContent::ToJson(nlohmann::json &jsonObject) const
144 {
145     jsonObject["contentType"] = static_cast<int32_t>(contentType_);
146     jsonObject["notificationContentType"] = static_cast<int32_t>(contentType_);
147 
148     if (!content_) {
149         ANS_LOGE("Invalid content. Cannot convert to JSON.");
150         return false;
151     }
152 
153     nlohmann::json contentObj;
154     if (!NotificationJsonConverter::ConvertToJson(content_.get(), contentObj)) {
155         ANS_LOGE("Cannot convert content to JSON");
156         return false;
157     }
158     jsonObject["content"] = contentObj;
159 
160     return true;
161 }
162 
FromJson(const nlohmann::json & jsonObject)163 NotificationContent *NotificationContent::FromJson(const nlohmann::json &jsonObject)
164 {
165     if (jsonObject.is_null() or !jsonObject.is_object()) {
166         ANS_LOGE("Invalid JSON object");
167         return nullptr;
168     }
169     const auto &jsonEnd = jsonObject.cend();
170     if ((jsonObject.find("contentType") == jsonEnd) || (jsonObject.find("content") == jsonEnd)) {
171         ANS_LOGE("Incomplete NotificationContent json object. Cannot convert content from JSON.");
172         return nullptr;
173     }
174 
175     auto pContent = new (std::nothrow) NotificationContent();
176     if (pContent == nullptr) {
177         ANS_LOGE("Failed to create NotificationContent instance");
178         return nullptr;
179     }
180 
181     if (!ConvertJsonToContent(pContent, jsonObject)) {
182         delete pContent;
183         pContent = nullptr;
184         return nullptr;
185     }
186 
187     return pContent;
188 }
189 
Marshalling(Parcel & parcel) const190 bool NotificationContent::Marshalling(Parcel &parcel) const
191 {
192     if (!parcel.WriteInt32(static_cast<int32_t>(contentType_))) {
193         ANS_LOGE("Failed to write contentType");
194         return false;
195     }
196 
197     auto valid = content_ ? true : false;
198     if (!parcel.WriteBool(valid)) {
199         ANS_LOGE("Failed to write the flag which indicate whether content is null");
200         return false;
201     }
202 
203     if (valid) {
204         if (!parcel.WriteParcelable(content_.get())) {
205             ANS_LOGE("Failed to write content");
206             return false;
207         }
208     }
209 
210     return true;
211 }
212 
Unmarshalling(Parcel & parcel)213 NotificationContent *NotificationContent::Unmarshalling(Parcel &parcel)
214 {
215     auto pContent = new (std::nothrow) NotificationContent();
216     if ((pContent != nullptr) && !pContent->ReadFromParcel(parcel)) {
217         delete pContent;
218         pContent = nullptr;
219     }
220 
221     return pContent;
222 }
223 
ReadFromParcel(Parcel & parcel)224 bool NotificationContent::ReadFromParcel(Parcel &parcel)
225 {
226     contentType_ = static_cast<NotificationContent::Type>(parcel.ReadInt32());
227 
228     if (!parcel.ReadBool()) {
229         return true;
230     }
231 
232     switch (contentType_) {
233         case NotificationContent::Type::BASIC_TEXT:
234             content_ = std::static_pointer_cast<NotificationBasicContent>(
235                 std::shared_ptr<NotificationNormalContent>(parcel.ReadParcelable<NotificationNormalContent>()));
236             break;
237         case NotificationContent::Type::CONVERSATION:
238             content_ =
239                 std::static_pointer_cast<NotificationBasicContent>(std::shared_ptr<NotificationConversationalContent>(
240                     parcel.ReadParcelable<NotificationConversationalContent>()));
241             break;
242         case NotificationContent::Type::LONG_TEXT:
243             content_ = std::static_pointer_cast<NotificationBasicContent>(
244                 std::shared_ptr<NotificationLongTextContent>(parcel.ReadParcelable<NotificationLongTextContent>()));
245             break;
246         case NotificationContent::Type::MEDIA:
247             content_ = std::static_pointer_cast<NotificationBasicContent>(
248                 std::shared_ptr<NotificationMediaContent>(parcel.ReadParcelable<NotificationMediaContent>()));
249             break;
250         case NotificationContent::Type::MULTILINE:
251             content_ = std::static_pointer_cast<NotificationBasicContent>(
252                 std::shared_ptr<NotificationMultiLineContent>(parcel.ReadParcelable<NotificationMultiLineContent>()));
253             break;
254         case NotificationContent::Type::PICTURE:
255             content_ = std::static_pointer_cast<NotificationBasicContent>(
256                 std::shared_ptr<NotificationPictureContent>(parcel.ReadParcelable<NotificationPictureContent>()));
257             break;
258         case NotificationContent::Type::LOCAL_LIVE_VIEW:
259             content_ = std::static_pointer_cast<NotificationBasicContent>(
260                 std::shared_ptr<NotificationLocalLiveViewContent>(
261                     parcel.ReadParcelable<NotificationLocalLiveViewContent>()));
262             break;
263         case NotificationContent::Type::LIVE_VIEW:
264             content_ = std::static_pointer_cast<NotificationBasicContent>(
265                 std::shared_ptr<NotificationLiveViewContent>(parcel.ReadParcelable<NotificationLiveViewContent>()));
266             break;
267         default:
268             ANS_LOGE("Invalid contentType");
269             return false;
270     }
271     if (!content_) {
272         ANS_LOGE("Failed to read content");
273         return false;
274     }
275 
276     return true;
277 }
278 
ConvertJsonToContent(NotificationContent * target,const nlohmann::json & jsonObject)279 bool NotificationContent::ConvertJsonToContent(NotificationContent *target, const nlohmann::json &jsonObject)
280 {
281     if (target == nullptr) {
282         ANS_LOGE("Invalid input parameter");
283         return false;
284     }
285 
286     auto contentType  = jsonObject.at("contentType");
287     if (!contentType.is_number_integer()) {
288         ANS_LOGE("ContentType is not integer");
289         return false;
290     }
291     target->contentType_   = static_cast<NotificationContent::Type>(contentType.get<int32_t>());
292 
293     auto contentObj = jsonObject.at("content");
294     if (contentObj.is_null()) {
295         ANS_LOGE("Invalid json object. Cannot convert content from JSON.");
296         return false;
297     }
298 
299     NotificationBasicContent *pBasicContent {nullptr};
300     switch (target->contentType_) {
301         case NotificationContent::Type::BASIC_TEXT:
302             pBasicContent = NotificationJsonConverter::ConvertFromJson<NotificationNormalContent>(contentObj);
303             break;
304         case NotificationContent::Type::CONVERSATION:
305             pBasicContent = NotificationJsonConverter::ConvertFromJson<NotificationConversationalContent>(contentObj);
306             break;
307         case NotificationContent::Type::LONG_TEXT:
308             pBasicContent = NotificationJsonConverter::ConvertFromJson<NotificationLongTextContent>(contentObj);
309             break;
310         case NotificationContent::Type::MULTILINE:
311             pBasicContent = NotificationJsonConverter::ConvertFromJson<NotificationMultiLineContent>(contentObj);
312             break;
313         case NotificationContent::Type::PICTURE:
314             pBasicContent = NotificationJsonConverter::ConvertFromJson<NotificationPictureContent>(contentObj);
315             break;
316         case NotificationContent::Type::LOCAL_LIVE_VIEW:
317             pBasicContent = NotificationJsonConverter::ConvertFromJson<NotificationLocalLiveViewContent>(contentObj);
318             break;
319         case NotificationContent::Type::LIVE_VIEW:
320             pBasicContent = NotificationJsonConverter::ConvertFromJson<NotificationLiveViewContent>(contentObj);
321             break;
322         default:
323             ANS_LOGE("Invalid contentType");
324             break;
325     }
326     if (pBasicContent == nullptr) {
327         ANS_LOGE("Parse content error!");
328         return false;
329     }
330     target->content_ = std::shared_ptr<NotificationBasicContent>(pBasicContent);
331 
332     return true;
333 }
334 
GetContentTypeByString(const std::string & strContentType,NotificationContent::Type & contentType)335 bool NotificationContent::GetContentTypeByString(
336     const std::string &strContentType, NotificationContent::Type &contentType)
337 {
338     if (convertStrToContentType_.size() <= 0) {
339         convertStrToContentType_[CONTENT_TYPE_NONE] = NotificationContent::Type::NONE;
340         convertStrToContentType_[CONTENT_TYPE_BASIC_TEXT] = NotificationContent::Type::BASIC_TEXT;
341         convertStrToContentType_[CONTENT_TYPE_CONVERSATION] = NotificationContent::Type::CONVERSATION;
342         convertStrToContentType_[CONTENT_TYPE_LONG_TEXT] = NotificationContent::Type::LONG_TEXT;
343         convertStrToContentType_[CONTENT_TYPE_MEDIA] = NotificationContent::Type::MEDIA;
344         convertStrToContentType_[CONTENT_TYPE_MULTILINE] = NotificationContent::Type::MULTILINE;
345         convertStrToContentType_[CONTENT_TYPE_PICTURE] = NotificationContent::Type::PICTURE;
346         convertStrToContentType_[CONTENT_TYPE_LOCAL_LIVE_VIEW] = NotificationContent::Type::LOCAL_LIVE_VIEW;
347         convertStrToContentType_[CONTENT_TYPE_LIVE_VIEW] = NotificationContent::Type::LIVE_VIEW;
348     }
349     auto iterContentType = convertStrToContentType_.find(strContentType);
350     if (iterContentType != convertStrToContentType_.end()) {
351         contentType = iterContentType->second;
352         return true;
353     }
354     ANS_LOGE("GetContentTypeByString failed as Invalid strContentType.");
355     return false;
356 }
357 }  // namespace Notification
358 }  // namespace OHOS
359