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_local_live_view_button.h"
17 
18 #include <cstdint>
19 #include <sstream>
20 #include <string>             // for basic_string, operator+, basic_string<>...
21 #include <memory>             // for shared_ptr, shared_ptr<>::element_type
22 #include <vector>
23 
24 #include "ans_image_util.h"
25 #include "ans_log_wrapper.h"
26 #include "nlohmann/json.hpp"  // for json, basic_json<>::object_t, basic_json
27 #include "notification_button_option.h"
28 #include "notification_json_convert.h"
29 #include "parcel.h"           // for Parcel
30 #include "pixel_map.h"        // for PixelMap
31 
32 namespace OHOS {
33 namespace Notification {
34 const uint32_t BUTTON_MAX_SIZE = 3;
35 const uint32_t BUTTON_RESOURCE_SIZE = 3;
36 const uint32_t RESOURCE_BUNDLENAME_INDEX = 0;
37 const uint32_t RESOURCE_MODULENAME_INDEX = 1;
38 const uint32_t RESOURCE_ID_INDEX = 2;
39 using ResourceVectorPtr = std::vector<std::shared_ptr<ResourceManager::Resource>>;
40 
GetAllButtonNames() const41 std::vector<std::string> NotificationLocalLiveViewButton::GetAllButtonNames() const
42 {
43     return buttonNames_;
44 }
45 
addSingleButtonName(const std::string & buttonName)46 void NotificationLocalLiveViewButton::addSingleButtonName(const std::string &buttonName)
47 {
48     if (buttonNames_.size() >= BUTTON_MAX_SIZE) {
49         ANS_LOGW("already added 3 buttonOption");
50         return;
51     }
52 
53     buttonNames_.emplace_back(buttonName);
54 }
55 
GetAllButtonIcons() const56 std::vector<std::shared_ptr<Media::PixelMap>> NotificationLocalLiveViewButton::GetAllButtonIcons() const
57 {
58     return buttonIcons_;
59 }
60 
addSingleButtonIcon(std::shared_ptr<Media::PixelMap> & icon)61 void NotificationLocalLiveViewButton::addSingleButtonIcon(std::shared_ptr<Media::PixelMap> &icon)
62 {
63     if (buttonIcons_.size() >= BUTTON_MAX_SIZE) {
64         ANS_LOGW("already added 3 buttonIcon");
65         return;
66     }
67 
68     buttonIcons_.emplace_back(icon);
69 }
70 
GetAllButtonIconResource() const71 ResourceVectorPtr NotificationLocalLiveViewButton::GetAllButtonIconResource() const
72 {
73     return buttonIconsResource_;
74 }
75 
addSingleButtonIconResource(std::shared_ptr<ResourceManager::Resource> & iconResource)76 void NotificationLocalLiveViewButton::addSingleButtonIconResource(
77     std::shared_ptr<ResourceManager::Resource> &iconResource)
78 {
79     if (buttonIcons_.size() >= BUTTON_MAX_SIZE) {
80         ANS_LOGW("already added 3 buttonIcon");
81         return;
82     }
83 
84     buttonIconsResource_.emplace_back(iconResource);
85 }
86 
Dump()87 std::string NotificationLocalLiveViewButton::Dump()
88 {
89     return "";
90 }
91 
ToJson(nlohmann::json & jsonObject) const92 bool NotificationLocalLiveViewButton::ToJson(nlohmann::json &jsonObject) const
93 {
94     nlohmann::json buttonsArr = nlohmann::json::array();
95 
96     jsonObject["names"] = nlohmann::json(buttonNames_);
97 
98     nlohmann::json iconsArr = nlohmann::json::array();
99     for (auto &btn : buttonIcons_) {
100         if (!btn) {
101             continue;
102         }
103         nlohmann::json btnObj = AnsImageUtil::PackImage(btn);
104         iconsArr.emplace_back(btnObj);
105     }
106     jsonObject["icons"] = iconsArr;
107 
108     nlohmann::json iconResourceArr = nlohmann::json::array();
109     for (const auto &resource : buttonIconsResource_) {
110         if (!resource) {
111             continue;
112         }
113         nlohmann::json resourceObj;
114         resourceObj["id"] = resource->id;
115         resourceObj["bundleName"] = resource->bundleName;
116         resourceObj["moduleName"] = resource->moduleName;
117         iconResourceArr.emplace_back(resourceObj);
118     }
119     jsonObject["iconResources"] = iconResourceArr;
120 
121     return true;
122 }
123 
ResourceFromJson(const nlohmann::json & resource,std::shared_ptr<ResourceManager::Resource> & resourceObj)124 bool NotificationLocalLiveViewButton::ResourceFromJson(const nlohmann::json &resource,
125     std::shared_ptr<ResourceManager::Resource>& resourceObj)
126 {
127     const auto &jsonEnd = resource.cend();
128     int resourceCount = BUTTON_RESOURCE_SIZE;
129     if (resource.find("bundleName") != jsonEnd && resource.at("bundleName").is_string()) {
130         resourceCount--;
131         resourceObj->bundleName = resource.at("bundleName").get<std::string>();
132     }
133     if (resource.find("moduleName") != jsonEnd && resource.at("moduleName").is_string()) {
134         resourceCount--;
135         resourceObj->moduleName = resource.at("moduleName").get<std::string>();
136     }
137     if (resource.find("id") != jsonEnd && resource.at("id").is_number_integer()) {
138         resourceCount--;
139         resourceObj->id = resource.at("id").get<int32_t>();
140     }
141     if (resourceCount == 0) {
142         return true;
143     }
144     ANS_LOGE("Resource from json failed.");
145     return false;
146 }
147 
FromJson(const nlohmann::json & jsonObject)148 NotificationLocalLiveViewButton *NotificationLocalLiveViewButton::FromJson(const nlohmann::json &jsonObject)
149 {
150     if (jsonObject.is_null() or !jsonObject.is_object()) {
151         ANS_LOGE("Invalid JSON object");
152         return nullptr;
153     }
154 
155     NotificationLocalLiveViewButton *button = new (std::nothrow) NotificationLocalLiveViewButton();
156     if (button == nullptr) {
157         ANS_LOGE("Failed to create capsule instance");
158         return nullptr;
159     }
160 
161     const auto &jsonEnd = jsonObject.cend();
162 
163     if (jsonObject.find("names") != jsonEnd && jsonObject.at("names").is_array()) {
164         button->buttonNames_ = jsonObject.at("names").get<std::vector<std::string>>();
165     }
166 
167     if (jsonObject.find("icons") != jsonEnd) {
168         auto iconArr = jsonObject.at("icons");
169         for (auto &iconObj : iconArr) {
170             if (!iconObj.is_string()) {
171                 continue;
172             }
173             auto pIcon = AnsImageUtil::UnPackImage(iconObj.get<std::string>());
174             if (pIcon == nullptr) {
175                 ANS_LOGE("Failed to parse button icon");
176                 delete button;
177                 return nullptr;
178             }
179             button->buttonIcons_.emplace_back(pIcon);
180         }
181     }
182 
183     if (jsonObject.find("iconResources") != jsonEnd) {
184         auto resourcesArr = jsonObject.at("iconResources");
185         for (auto &resource : resourcesArr) {
186             auto resourceObj = std::make_shared<Global::Resource::ResourceManager::Resource>();
187             if (ResourceFromJson(resource, resourceObj)) {
188                 button->buttonIconsResource_.emplace_back(resourceObj);
189             }
190         }
191     }
192 
193     return button;
194 }
195 
Marshalling(Parcel & parcel) const196 bool NotificationLocalLiveViewButton::Marshalling(Parcel &parcel) const
197 {
198     if (!parcel.WriteStringVector(buttonNames_)) {
199         ANS_LOGE("Failed to write buttonNames");
200         return false;
201     }
202 
203     if (!parcel.WriteUint64(buttonIcons_.size())) {
204         ANS_LOGE("Failed to write the size of buttonIcons");
205         return false;
206     }
207 
208     for (auto it = buttonIcons_.begin(); it != buttonIcons_.end(); ++it) {
209         if (!parcel.WriteParcelable(it->get())) {
210             ANS_LOGE("Failed to write buttonIcons");
211             return false;
212         }
213     }
214 
215     if (!parcel.WriteUint64(buttonIconsResource_.size())) {
216         ANS_LOGE("Failed to write the size of buttonIcons");
217         return false;
218     }
219 
220     for (auto it = buttonIconsResource_.begin(); it != buttonIconsResource_.end(); ++it) {
221         std::vector<std::string> iconsResource  = {};
222         // Insertion cannot be changed, Marshalling and Unmarshalling need to match
223         iconsResource.push_back((*it)->bundleName);
224         iconsResource.push_back((*it)->moduleName);
225         iconsResource.push_back(std::to_string((*it)->id));
226         if (!parcel.WriteStringVector(iconsResource)) {
227             ANS_LOGE("Failed to write button icon resource");
228             return false;
229         }
230     }
231 
232     return true;
233 }
234 
ReadFromParcel(Parcel & parcel)235 bool NotificationLocalLiveViewButton::ReadFromParcel(Parcel &parcel)
236 {
237     if (!parcel.ReadStringVector(&buttonNames_)) {
238         ANS_LOGE("Failed to read button names");
239         return false;
240     }
241 
242     auto vsize = parcel.ReadUint64();
243     vsize = (vsize < BUTTON_MAX_SIZE) ? vsize : BUTTON_MAX_SIZE;
244     for (uint64_t it = 0; it < vsize; ++it) {
245         auto member = std::shared_ptr<Media::PixelMap>(parcel.ReadParcelable<Media::PixelMap>());
246         if (member == nullptr) {
247             buttonIcons_.clear();
248             ANS_LOGE("Failed to read LocalLiveViewButton");
249             return false;
250         }
251 
252         buttonIcons_.emplace_back(member);
253     }
254 
255     vsize = parcel.ReadUint64();
256     for (uint64_t it = 0; it < vsize; ++it) {
257         std::vector<std::string> iconsResource  = {};
258         if (!parcel.ReadStringVector(&iconsResource)) {
259             ANS_LOGE("Failed to read button names");
260             return false;
261         }
262         if (iconsResource.size() < BUTTON_RESOURCE_SIZE) {
263             ANS_LOGE("Invalid input for button icons resource");
264             return false;
265         }
266         auto resource = std::make_shared<ResourceManager::Resource>();
267         resource->bundleName = iconsResource[RESOURCE_BUNDLENAME_INDEX];
268         resource->moduleName = iconsResource[RESOURCE_MODULENAME_INDEX];
269         std::stringstream sin(iconsResource[RESOURCE_ID_INDEX]);
270         int32_t checknum;
271         if (!(sin >> checknum)) {
272             ANS_LOGE("Invalid input for button icons resource");
273             return false;
274         }
275         resource->id = std::stoi(iconsResource[RESOURCE_ID_INDEX]);
276         buttonIconsResource_.emplace_back(resource);
277     }
278 
279     return true;
280 }
281 
Unmarshalling(Parcel & parcel)282 NotificationLocalLiveViewButton *NotificationLocalLiveViewButton::Unmarshalling(Parcel &parcel)
283 {
284     NotificationLocalLiveViewButton *button = new (std::nothrow) NotificationLocalLiveViewButton();
285 
286     if (button && !button->ReadFromParcel(parcel)) {
287         delete button;
288         button = nullptr;
289     }
290 
291     return button;
292 }
293 
ClearButtonIcons()294 void NotificationLocalLiveViewButton::ClearButtonIcons()
295 {
296     buttonIcons_.clear();
297 }
298 
ClearButtonIconsResource()299 void NotificationLocalLiveViewButton::ClearButtonIconsResource()
300 {
301     buttonIconsResource_.clear();
302 }
303 }  // namespace Notification
304 }  // namespace OHOS
305