* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "window_manager_config.h"
#include "config_policy_utils.h"
#include "window_helper.h"
#include "window_manager_hilog.h"
namespace OHOS {
namespace Rosen {
namespace {
constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowManagerConfig"};
}
WindowManagerConfig::ConfigItem WindowManagerConfig::config_;
const std::map<std::string, WindowManagerConfig::ValueType> WindowManagerConfig::configItemTypeMap_ = {
{ "maxAppWindowNumber", WindowManagerConfig::ValueType::INTS },
{ "modeChangeHotZones", WindowManagerConfig::ValueType::INTS },
{ "duration", WindowManagerConfig::ValueType::INTS },
{ "durationIn", WindowManagerConfig::ValueType::INTS },
{ "durationOut", WindowManagerConfig::ValueType::INTS },
{ "defaultWindowMode", WindowManagerConfig::ValueType::INTS },
{ "dragFrameGravity", WindowManagerConfig::ValueType::INTS },
{ "floatingBottomPosY", WindowManagerConfig::ValueType::INTS },
{ "defaultFloatingWindow", WindowManagerConfig::ValueType::INTS },
{ "maxMainFloatingWindowNumber", WindowManagerConfig::ValueType::INTS },
{ "maxFloatingWindowSize", WindowManagerConfig::ValueType::INTS },
{ "defaultMaximizeMode", WindowManagerConfig::ValueType::INTS },
{ "windowAnimation", WindowManagerConfig::ValueType::MAP },
{ "keyboardAnimation", WindowManagerConfig::ValueType::MAP },
{ "animationIn", WindowManagerConfig::ValueType::MAP },
{ "animationOut", WindowManagerConfig::ValueType::MAP },
{ "timing", WindowManagerConfig::ValueType::MAP },
{ "windowEffect", WindowManagerConfig::ValueType::MAP },
{ "appWindows", WindowManagerConfig::ValueType::MAP },
{ "cornerRadius", WindowManagerConfig::ValueType::MAP },
{ "shadow", WindowManagerConfig::ValueType::MAP },
{ "focused", WindowManagerConfig::ValueType::MAP },
{ "unfocused", WindowManagerConfig::ValueType::MAP },
{ "decor", WindowManagerConfig::ValueType::MAP },
{ "startWindowTransitionAnimation", WindowManagerConfig::ValueType::MAP },
{ "curve", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "splitRatios", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "exitSplitRatios", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "scale", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "opacity", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "opacityStart", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "opacityEnd", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "elevation", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "alpha", WindowManagerConfig::ValueType::POSITIVE_FLOATS },
{ "rotation", WindowManagerConfig::ValueType::FLOATS },
{ "translate", WindowManagerConfig::ValueType::FLOATS },
{ "offsetX", WindowManagerConfig::ValueType::FLOATS },
{ "offsetY", WindowManagerConfig::ValueType::FLOATS },
{ "radius", WindowManagerConfig::ValueType::FLOATS },
{ "fullScreen", WindowManagerConfig::ValueType::STRING },
{ "split", WindowManagerConfig::ValueType::STRING },
{ "float", WindowManagerConfig::ValueType::STRING },
{ "color", WindowManagerConfig::ValueType::STRING },
{ "supportedMode", WindowManagerConfig::ValueType::STRINGS },
{ "minimizeByOther", WindowManagerConfig::ValueType::UNDIFINED },
{ "stretchable", WindowManagerConfig::ValueType::UNDIFINED },
{ "remoteAnimation", WindowManagerConfig::ValueType::UNDIFINED },
{ "configMainFloatingWindowAbove", WindowManagerConfig::ValueType::UNDIFINED },
{ "uiType", WindowManagerConfig::ValueType::STRING },
{ "supportTypeFloatWindow", WindowManagerConfig::ValueType::STRING },
};
std::vector<std::string> WindowManagerConfig::SplitNodeContent(const xmlNodePtr& node, const std::string& pattern)
{
xmlChar* content = xmlNodeGetContent(node);
if (content == nullptr) {
WLOGFE("[WmConfig] read xml node error: nodeName:(%{public}s)", node->name);
return std::vector<std::string>();
}
std::string contentStr = reinterpret_cast<const char*>(content);
xmlFree(content);
if (contentStr.size() == 0) {
return std::vector<std::string>();
}
return WindowHelper::Split(contentStr, pattern);
}
std::string WindowManagerConfig::GetConfigPath(const std::string& configFileName)
{
char buf[PATH_MAX + 1];
char* configPath = GetOneCfgFile(configFileName.c_str(), buf, PATH_MAX + 1);
char tmpPath[PATH_MAX + 1] = { 0 };
if (!configPath || strlen(configPath) == 0 || strlen(configPath) > PATH_MAX || !realpath(configPath, tmpPath)) {
WLOGI("[WmConfig] can not get customization config file");
return "/system/" + configFileName;
}
return std::string(tmpPath);
}
void WindowManagerConfig::ReadConfig(const xmlNodePtr& rootPtr, std::map<std::string, ConfigItem>& mapValue)
{
for (xmlNodePtr curNodePtr = rootPtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
if (!IsValidNode(*curNodePtr)) {
WLOGFE("[WmConfig]: invalid node!");
continue;
}
std::string nodeName = reinterpret_cast<const char*>(curNodePtr->name);
if (configItemTypeMap_.count(nodeName)) {
std::map<std::string, ConfigItem> property = ReadProperty(curNodePtr);
if (property.size() > 0) {
mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetProperty(property);
}
switch (configItemTypeMap_.at(nodeName)) {
case ValueType::INTS: {
std::vector<int> v = ReadIntNumbersConfigInfo(curNodePtr);
mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
break;
}
case ValueType::FLOATS: {
std::vector<float> v = ReadFloatNumbersConfigInfo(curNodePtr, true);
mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
break;
}
case ValueType::POSITIVE_FLOATS: {
std::vector<float> v = ReadFloatNumbersConfigInfo(curNodePtr, false);
mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
break;
}
case ValueType::STRING: {
std::string v = ReadStringConfigInfo(curNodePtr);
mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
break;
}
case ValueType::STRINGS: {
std::vector<std::string> v = ReadStringsConfigInfo(curNodePtr);
mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
break;
}
case ValueType::MAP: {
std::map<std::string, ConfigItem> v;
ReadConfig(curNodePtr, v);
mapValue[reinterpret_cast<const char*>(curNodePtr->name)].SetValue(v);
break;
}
default:
break;
}
}
}
}
bool WindowManagerConfig::LoadConfigXml()
{
auto configFilePath = GetConfigPath("etc/window/resources/window_manager_config.xml");
xmlDocPtr docPtr = nullptr;
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
docPtr = xmlReadFile(configFilePath.c_str(), nullptr, XML_PARSE_NOBLANKS);
}
WLOGI("[WmConfig] filePath: %{public}s", configFilePath.c_str());
if (docPtr == nullptr) {
WLOGFE("[WmConfig] load xml error!");
return false;
}
xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr);
if (rootPtr == nullptr || rootPtr->name == nullptr ||
xmlStrcmp(rootPtr->name, reinterpret_cast<const xmlChar*>("Configs"))) {
WLOGFE("[WmConfig] get root element failed!");
xmlFreeDoc(docPtr);
return false;
}
std::map<std::string, ConfigItem> configMap;
config_.SetValue(configMap);
ReadConfig(rootPtr, *config_.mapValue_);
xmlFreeDoc(docPtr);
return true;
}
bool WindowManagerConfig::IsValidNode(const xmlNode& currNode)
{
if (currNode.name == nullptr || currNode.type == XML_COMMENT_NODE) {
return false;
}
return true;
}
std::map<std::string, XmlConfigBase::ConfigItem> WindowManagerConfig::ReadProperty(const xmlNodePtr& currNode)
{
std::map<std::string, ConfigItem> property;
xmlChar* propVal = xmlGetProp(currNode, reinterpret_cast<const xmlChar*>("enable"));
if (propVal != nullptr) {
if (!xmlStrcmp(propVal, reinterpret_cast<const xmlChar*>("true"))) {
property["enable"].SetValue(true);
} else if (!xmlStrcmp(propVal, reinterpret_cast<const xmlChar*>("false"))) {
property["enable"].SetValue(false);
}
xmlFree(propVal);
}
propVal = xmlGetProp(currNode, reinterpret_cast<const xmlChar*>("name"));
if (propVal != nullptr) {
property["name"].SetValue(std::string(reinterpret_cast<const char*>(propVal)));
xmlFree(propVal);
}
return property;
}
std::vector<int> WindowManagerConfig::ReadIntNumbersConfigInfo(const xmlNodePtr& currNode)
{
std::vector<int> intsValue;
auto numbers = SplitNodeContent(currNode);
for (auto& num : numbers) {
if (!WindowHelper::IsNumber(num)) {
WLOGFE("[WmConfig] read int number error: nodeName:(%{public}s)", currNode->name);
return {};
}
intsValue.push_back(std::stoi(num));
}
return intsValue;
}
std::vector<std::string> WindowManagerConfig::ReadStringsConfigInfo(const xmlNodePtr& currNode)
{
return SplitNodeContent(currNode);
}
std::vector<float> WindowManagerConfig::ReadFloatNumbersConfigInfo(const xmlNodePtr& currNode, bool allowNeg)
{
std::vector<float> floatsValue;
auto numbers = SplitNodeContent(currNode);
for (auto& num : numbers) {
if (!WindowHelper::IsFloatingNumber(num, allowNeg)) {
WLOGFE("[WmConfig] read float number error: nodeName:(%{public}s)", currNode->name);
return {};
}
floatsValue.push_back(std::stof(num));
}
return floatsValue;
}
std::string WindowManagerConfig::ReadStringConfigInfo(const xmlNodePtr& currNode)
{
std::string stringValue;
xmlChar* context = xmlNodeGetContent(currNode);
if (context == nullptr) {
WLOGFE("[WmConfig] read xml node error: nodeName:(%{public}s)", currNode->name);
return {};
}
stringValue = std::string(reinterpret_cast<const char*>(context));
xmlFree(context);
return stringValue;
}
void WindowManagerConfig::DumpConfig(const std::map<std::string, ConfigItem>& config)
{
for (auto& conf : config) {
WLOGI("[WmConfig] %{public}s", conf.first.c_str());
std::map<std::string, ConfigItem> propMap;
if (conf.second.property_) {
propMap = *conf.second.property_;
}
for (auto prop : propMap) {
switch (prop.second.type_) {
case ValueType::BOOL:
WLOGI("[WmConfig] Prop: %{public}s %{public}u", prop.first.c_str(), prop.second.boolValue_);
break;
case ValueType::STRING:
WLOGI("[WmConfig] Prop: %{public}s %{public}s", prop.first.c_str(),
prop.second.stringValue_.c_str());
break;
default:
break;
}
}
switch (conf.second.type_) {
case ValueType::INTS:
for (auto& num : *conf.second.intsValue_) {
TLOGI(WmsLogTag::DEFAULT, "[WmConfig] Num: %{public}d", num);
}
break;
case ValueType::MAP:
if (conf.second.mapValue_) {
DumpConfig(*conf.second.mapValue_);
}
break;
case ValueType::STRING:
TLOGI(WmsLogTag::DEFAULT, "[WmConfig] %{public}s", conf.second.stringValue_.c_str());
break;
case ValueType::BOOL:
TLOGI(WmsLogTag::DEFAULT, "[WmConfig] %{public}u", conf.second.boolValue_);
break;
case ValueType::FLOATS:
for (auto& num : *conf.second.floatsValue_) {
TLOGI(WmsLogTag::DEFAULT, "[WmConfig] Num: %{public}f", num);
}
break;
default:
break;
}
}
}
}
}