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 "window_scene_config.h"
17 
18 #include "config_policy_utils.h"
19 #include "window_helper.h"
20 #include "window_manager_hilog.h"
21 
22 namespace OHOS {
23 namespace Rosen {
24 namespace {
25 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowSceneConfig"};
26 }
27 
28 WindowSceneConfig::ConfigItem WindowSceneConfig::config_;
29 const std::map<std::string, WindowSceneConfig::ValueType> WindowSceneConfig::configItemTypeMap_ = {
30     { "maxAppWindowNumber",                           WindowSceneConfig::ValueType::INTS },
31     { "modeChangeHotZones",                           WindowSceneConfig::ValueType::INTS },
32     { "duration",                                     WindowSceneConfig::ValueType::INTS },
33     { "defaultWindowMode",                            WindowSceneConfig::ValueType::INTS },
34     { "dragFrameGravity",                             WindowSceneConfig::ValueType::INTS },
35     { "floatingBottomPosY",                           WindowSceneConfig::ValueType::INTS },
36     { "defaultFloatingWindow",                        WindowSceneConfig::ValueType::INTS },
37     { "maxMainFloatingWindowNumber",                  WindowSceneConfig::ValueType::INTS },
38     { "maxFloatingWindowSize",                        WindowSceneConfig::ValueType::INTS },
39     { "defaultMaximizeMode",                          WindowSceneConfig::ValueType::INTS },
40     { "miniWidth",                                    WindowSceneConfig::ValueType::INTS },
41     { "miniHeight",                                   WindowSceneConfig::ValueType::INTS },
42     { "showInLandscapeMode",                          WindowSceneConfig::ValueType::INTS },
43     { "mainWindowSizeLimits",                         WindowSceneConfig::ValueType::MAP },
44     { "subWindowSizeLimits",                          WindowSceneConfig::ValueType::MAP },
45     { "windowAnimation",                              WindowSceneConfig::ValueType::MAP },
46     { "keyboardAnimation",                            WindowSceneConfig::ValueType::MAP },
47     { "animationIn",                                  WindowSceneConfig::ValueType::MAP },
48     { "animationOut",                                 WindowSceneConfig::ValueType::MAP },
49     { "timing",                                       WindowSceneConfig::ValueType::MAP },
50     { "windowEffect",                                 WindowSceneConfig::ValueType::MAP },
51     { "appWindows",                                   WindowSceneConfig::ValueType::MAP },
52     { "cornerRadius",                                 WindowSceneConfig::ValueType::MAP },
53     { "shadow",                                       WindowSceneConfig::ValueType::MAP },
54     { "focused",                                      WindowSceneConfig::ValueType::MAP },
55     { "unfocused",                                    WindowSceneConfig::ValueType::MAP },
56     { "decor",                                        WindowSceneConfig::ValueType::MAP },
57     { "startWindowTransitionAnimation",               WindowSceneConfig::ValueType::MAP },
58     { "systemUIStatusBar",                            WindowSceneConfig::ValueType::MAP },
59     { "curve",                                        WindowSceneConfig::ValueType::POSITIVE_FLOATS },
60     { "splitRatios",                                  WindowSceneConfig::ValueType::POSITIVE_FLOATS },
61     { "exitSplitRatios",                              WindowSceneConfig::ValueType::POSITIVE_FLOATS },
62     { "scale",                                        WindowSceneConfig::ValueType::POSITIVE_FLOATS },
63     { "opacity",                                      WindowSceneConfig::ValueType::POSITIVE_FLOATS },
64     { "opacityStart",                                 WindowSceneConfig::ValueType::POSITIVE_FLOATS },
65     { "opacityEnd",                                   WindowSceneConfig::ValueType::POSITIVE_FLOATS },
66     { "elevation",                                    WindowSceneConfig::ValueType::POSITIVE_FLOATS },
67     { "alpha",                                        WindowSceneConfig::ValueType::POSITIVE_FLOATS },
68     { "rotation",                                     WindowSceneConfig::ValueType::FLOATS },
69     { "translate",                                    WindowSceneConfig::ValueType::FLOATS },
70     { "offsetX",                                      WindowSceneConfig::ValueType::FLOATS },
71     { "offsetY",                                      WindowSceneConfig::ValueType::FLOATS },
72     { "radius",                                       WindowSceneConfig::ValueType::FLOATS },
73     { "snapshotScale",                                WindowSceneConfig::ValueType::FLOATS },
74     { "fullScreen",                                   WindowSceneConfig::ValueType::STRING },
75     { "split",                                        WindowSceneConfig::ValueType::STRING },
76     { "float",                                        WindowSceneConfig::ValueType::STRING },
77     { "color",                                        WindowSceneConfig::ValueType::STRING },
78     { "immersiveStatusBarBgColor",                    WindowSceneConfig::ValueType::STRING },
79     { "immersiveStatusBarContentColor",               WindowSceneConfig::ValueType::STRING },
80     { "supportedMode",                                WindowSceneConfig::ValueType::STRINGS },
81     { "minimizeByOther",                              WindowSceneConfig::ValueType::UNDIFINED },
82     { "stretchable",                                  WindowSceneConfig::ValueType::UNDIFINED },
83     { "remoteAnimation",                              WindowSceneConfig::ValueType::UNDIFINED },
84     { "configMainFloatingWindowAbove",                WindowSceneConfig::ValueType::UNDIFINED },
85     { "backgroundswitch",                             WindowSceneConfig::ValueType::INTS },
86     { "freeMultiWindow",                              WindowSceneConfig::ValueType::MAP },
87     { "uiType",                                       WindowSceneConfig::ValueType::STRING },
88     { "backgroundScreenLock",                         WindowSceneConfig::ValueType::STRING },
89     { "rotationMode",                                 WindowSceneConfig::ValueType::STRING },
90     { "immersive",                                    WindowSceneConfig::ValueType::MAP },
91     { "inDesktopStatusBarConfig",                     WindowSceneConfig::ValueType::MAP },
92     { "inSplitStatusBarConfig",                       WindowSceneConfig::ValueType::MAP },
93     { "upDownSplit",                                  WindowSceneConfig::ValueType::MAP },
94     { "leftRightSplit",                               WindowSceneConfig::ValueType::MAP },
95     { "showHide",                                     WindowSceneConfig::ValueType::STRING },
96     { "backgroundColor",                              WindowSceneConfig::ValueType::STRING },
97     { "contentColor",                                 WindowSceneConfig::ValueType::STRING },
98     { "supportTypeFloatWindow",                       WindowSceneConfig::ValueType::STRING },
99 };
100 
SplitNodeContent(const xmlNodePtr& node, const std::string& pattern)101 std::vector<std::string> WindowSceneConfig::SplitNodeContent(const xmlNodePtr& node, const std::string& pattern)
102 {
103     xmlChar* content = xmlNodeGetContent(node);
104     if (content == nullptr) {
105         WLOGFE("read xml node error: nodeName:(%{public}s)", node->name);
106         return std::vector<std::string>();
107     }
108 
109     std::string contentStr = reinterpret_cast<const char*>(content);
110     xmlFree(content);
111     if (contentStr.size() == 0) {
112         return std::vector<std::string>();
113     }
114     return WindowHelper::Split(contentStr, pattern);
115 }
116 
GetConfigPath(const std::string& configFileName)117 std::string WindowSceneConfig::GetConfigPath(const std::string& configFileName)
118 {
119     char buf[PATH_MAX + 1];
120     char* configPath = GetOneCfgFile(configFileName.c_str(), buf, PATH_MAX + 1);
121     char tmpPath[PATH_MAX + 1] = { 0 };
122     if (!configPath || strlen(configPath) == 0 || strlen(configPath) > PATH_MAX || !realpath(configPath, tmpPath)) {
123         WLOGI("can not get customization config file");
124         return "/system/" + configFileName;
125     }
126     return std::string(tmpPath);
127 }
128 
ReadConfig(const xmlNodePtr& rootPtr, std::map<std::string, ConfigItem>& mapValue)129 void WindowSceneConfig::ReadConfig(const xmlNodePtr& rootPtr, std::map<std::string, ConfigItem>& mapValue)
130 {
131     for (xmlNodePtr curNodePtr = rootPtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
132         if (!IsValidNode(*curNodePtr)) {
133             WLOGFE("[WmConfig]: invalid node!");
134             continue;
135         }
136         std::string nodeName = reinterpret_cast<const char*>(curNodePtr->name);
137         if (configItemTypeMap_.count(nodeName)) {
138             std::map<std::string, ConfigItem> p = ReadProperty(curNodePtr);
139             if (p.size() > 0) {
140                 mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetProperty(p);
141             }
142             switch (configItemTypeMap_.at(nodeName)) {
143                 case ValueType::INTS: {
144                     std::vector<int> v = ReadIntNumbersConfigInfo(curNodePtr);
145                     mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
146                     break;
147                 }
148                 case ValueType::POSITIVE_FLOATS: {
149                     std::vector<float> v = ReadFloatNumbersConfigInfo(curNodePtr, false);
150                     mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
151                     break;
152                 }
153                 case ValueType::FLOATS: {
154                     std::vector<float> v = ReadFloatNumbersConfigInfo(curNodePtr, true);
155                     mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
156                     break;
157                 }
158                 case ValueType::MAP: {
159                     std::map<std::string, ConfigItem> v;
160                     ReadConfig(curNodePtr, v);
161                     mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
162                     break;
163                 }
164                 case ValueType::STRING: {
165                     std::string v = ReadStringConfigInfo(curNodePtr);
166                     mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
167                     break;
168                 }
169                 case ValueType::STRINGS: {
170                     std::vector<std::string> v = ReadStringsConfigInfo(curNodePtr);
171                     mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
172                     break;
173                 }
174                 default:
175                     break;
176             }
177         }
178     }
179 }
180 
LoadConfigXml()181 bool WindowSceneConfig::LoadConfigXml()
182 {
183     auto configFilePath = GetConfigPath("etc/window/resources/window_manager_config.xml");
184     xmlDocPtr docPtr = nullptr;
185     {
186         std::lock_guard<std::recursive_mutex> lock(mutex_);
187         docPtr = xmlReadFile(configFilePath.c_str(), nullptr, XML_PARSE_NOBLANKS);
188     }
189     WLOGI("filePath: %{public}s", configFilePath.c_str());
190     if (docPtr == nullptr) {
191         WLOGFE("load xml error!");
192         return false;
193     }
194 
195     xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr);
196     if (rootPtr == nullptr || rootPtr->name == nullptr ||
197         xmlStrcmp(rootPtr->name, reinterpret_cast<const xmlChar*>("Configs"))) {
198         WLOGFE("get root element failed!");
199         xmlFreeDoc(docPtr);
200         return false;
201     }
202 
203     std::map<std::string, ConfigItem> configMap;
204     config_.SetValue(configMap);
205     ReadConfig(rootPtr, *config_.mapValue_);
206 
207     xmlFreeDoc(docPtr);
208     return true;
209 }
210 
IsValidNode(const xmlNode& currNode)211 bool WindowSceneConfig::IsValidNode(const xmlNode& currNode)
212 {
213     if (currNode.name == nullptr || currNode.type == XML_COMMENT_NODE) {
214         return false;
215     }
216     return true;
217 }
218 
ReadProperty(const xmlNodePtr& currNode)219 std::map<std::string, XmlConfigBase::ConfigItem> WindowSceneConfig::ReadProperty(const xmlNodePtr& currNode)
220 {
221     std::map<std::string, ConfigItem> property;
222     xmlChar* prop = xmlGetProp(currNode, reinterpret_cast<const xmlChar*>("enable"));
223     if (prop != nullptr) {
224         if (!xmlStrcmp(prop, reinterpret_cast<const xmlChar*>("true"))) {
225             property["enable"].SetValue(true);
226         } else if (!xmlStrcmp(prop, reinterpret_cast<const xmlChar*>("false"))) {
227             property["enable"].SetValue(false);
228         }
229         xmlFree(prop);
230     }
231 
232     prop = xmlGetProp(currNode, reinterpret_cast<const xmlChar*>("name"));
233     if (prop != nullptr) {
234         property["name"].SetValue(std::string(reinterpret_cast<const char*>(prop)));
235         xmlFree(prop);
236     }
237 
238     return property;
239 }
240 
ReadIntNumbersConfigInfo(const xmlNodePtr& currNode)241 std::vector<int> WindowSceneConfig::ReadIntNumbersConfigInfo(const xmlNodePtr& currNode)
242 {
243     std::vector<int> intsValue;
244     auto numbers = SplitNodeContent(currNode);
245     for (auto& num : numbers) {
246         if (!WindowHelper::IsNumber(num)) {
247             WLOGFE("read int number error: nodeName:(%{public}s)", currNode->name);
248             return {};
249         }
250         intsValue.push_back(std::stoi(num));
251     }
252     return intsValue;
253 }
254 
ReadStringsConfigInfo(const xmlNodePtr& currNode)255 std::vector<std::string> WindowSceneConfig::ReadStringsConfigInfo(const xmlNodePtr& currNode)
256 {
257     return SplitNodeContent(currNode);
258 }
259 
ReadFloatNumbersConfigInfo(const xmlNodePtr& currNode, bool allowNeg)260 std::vector<float> WindowSceneConfig::ReadFloatNumbersConfigInfo(const xmlNodePtr& currNode, bool allowNeg)
261 {
262     std::vector<float> floatsValue;
263     auto numbers = SplitNodeContent(currNode);
264     for (auto& num : numbers) {
265         if (!WindowHelper::IsFloatingNumber(num, allowNeg)) {
266             WLOGFE("read float number error: nodeName:(%{public}s)", currNode->name);
267             return {};
268         }
269         floatsValue.push_back(std::stof(num));
270     }
271     return floatsValue;
272 }
273 
ReadStringConfigInfo(const xmlNodePtr& currNode)274 std::string WindowSceneConfig::ReadStringConfigInfo(const xmlNodePtr& currNode)
275 {
276     std::string stringValue;
277     xmlChar* context = xmlNodeGetContent(currNode);
278     if (context == nullptr) {
279         WLOGFE("read xml node error: nodeName:(%{public}s)", currNode->name);
280         return {};
281     }
282 
283     stringValue = std::string(reinterpret_cast<const char*>(context));
284     xmlFree(context);
285     return stringValue;
286 }
287 
DumpConfig(const std::map<std::string, ConfigItem>& config)288 void WindowSceneConfig::DumpConfig(const std::map<std::string, ConfigItem>& config)
289 {
290     for (auto& conf : config) {
291         WLOGI("%{public}s", conf.first.c_str());
292         std::map<std::string, ConfigItem> propMap;
293         if (conf.second.property_) {
294             propMap = *conf.second.property_;
295         }
296         for (auto prop : propMap) {
297             switch (prop.second.type_) {
298                 case ValueType::BOOL:
299                     WLOGI("Prop: %{public}s %{public}u", prop.first.c_str(), prop.second.boolValue_);
300                     break;
301                 case ValueType::STRING:
302                     WLOGI("Prop: %{public}s %{public}s", prop.first.c_str(),
303                         prop.second.stringValue_.c_str());
304                     break;
305                 default:
306                     break;
307             }
308         }
309         switch (conf.second.type_) {
310             case ValueType::MAP:
311                 if (conf.second.mapValue_) {
312                     DumpConfig(*conf.second.mapValue_);
313                 }
314                 break;
315             case ValueType::BOOL:
316                 WLOGI("%{public}u", conf.second.boolValue_);
317                 break;
318             case ValueType::STRING:
319                 WLOGI("%{public}s", conf.second.stringValue_.c_str());
320                 break;
321             case ValueType::INTS:
322                 for (auto& num : *conf.second.intsValue_) {
323                     WLOGI("Num: %{public}d", num);
324                 }
325                 break;
326             case ValueType::FLOATS:
327                 for (auto& num : *conf.second.floatsValue_) {
328                     WLOGI("Num: %{public}f", num);
329                 }
330                 break;
331             default:
332                 break;
333         }
334     }
335 }
336 
337 } // namespace Rosen
338 } // namespace OHOS
339