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