• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "adapter/preview/osal/resource_adapter_impl.h"
17 
18 #include <set>
19 
20 #include "base/i18n/localization.h"
21 #include "base/utils/system_properties.h"
22 #include "core/common/ace_application_info.h"
23 #include "core/common/container.h"
24 #include "core/components/common/layout/constants.h"
25 #include "core/components/theme/theme_attributes.h"
26 
27 namespace OHOS::Ace {
28 namespace {
29 
30 constexpr char COLOR_VALUE_PREFIX[] = "$color:";
31 constexpr char PATTERN_NAME_KEY_WORD[] = "$pattern:";
32 constexpr char STATE_VALUE_KEY_WORD[] = ".sxml";
33 constexpr char REF_ATTR_VALUE_KEY_WORD[] = "?theme:";
34 constexpr char STATE_CONTAINER[] = "state-container";
35 constexpr char STATE_ELEMENT[] = "element";
36 constexpr uint32_t STATE_MAX = 128;
37 constexpr double DPI_BASE = 160.0;
38 constexpr uint32_t THEME_ID_LIGHT = 117440515;
39 constexpr uint32_t THEME_ID_DARK = 117440516;
40 
CheckThemeId(int32_t & themeId)41 void CheckThemeId(int32_t& themeId)
42 {
43     if (themeId >= 0) {
44         return;
45     }
46     auto deviceType = SystemProperties::GetDeviceType();
47     themeId = (deviceType == DeviceType::PHONE || deviceType == DeviceType::UNKNOWN || deviceType == DeviceType::CAR)
48                   ? THEME_ID_LIGHT
49                   : THEME_ID_DARK;
50 }
51 
ParseDimensionUnit(const std::string & unit)52 DimensionUnit ParseDimensionUnit(const std::string& unit)
53 {
54     if (unit == "px") {
55         return DimensionUnit::PX;
56     } else if (unit == "fp") {
57         return DimensionUnit::FP;
58     } else if (unit == "lpx") {
59         return DimensionUnit::LPX;
60     } else if (unit == "%") {
61         return DimensionUnit::PERCENT;
62     } else {
63         return DimensionUnit::VP;
64     }
65 };
66 
ConvertOrientation(DeviceOrientation orientation)67 Global::Resource::ORIENTATION ConvertOrientation(DeviceOrientation orientation)
68 {
69     return orientation == DeviceOrientation::PORTRAIT ? Global::Resource::ORIENTATION::ORIENTATION_PORTRAIT
70                                                       : Global::Resource::ORIENTATION::ORIENTATION_LANDSCAPE;
71 }
72 
ConvertResolution(double density)73 Global::Resource::RESOLUTION ConvertResolution(double density)
74 {
75     static const std::vector<std::pair<double, Global::Resource::RESOLUTION>> resolutions = {
76         { 120.0, Global::Resource::RESOLUTION::RESOLUTION_LOW },
77         { 160.0, Global::Resource::RESOLUTION::RESOLUTION_MEDIUM },
78         { 240.0, Global::Resource::RESOLUTION::RESOLUTION_HIGH },
79         { 320.0, Global::Resource::RESOLUTION::RESOLUTION_XHIGH },
80         { 480.0, Global::Resource::RESOLUTION::RESOLUTION_XXHIGH },
81         { 640.0, Global::Resource::RESOLUTION::RESOLUTION_XXXHIGH },
82     };
83     double deviceDpi = density * DPI_BASE;
84     auto resolution = Global::Resource::RESOLUTION::RESOLUTION_LOW;
85     for (const auto& [dpi, value] : resolutions) {
86         resolution = value;
87         if (LessOrEqual(deviceDpi, dpi)) {
88             break;
89         }
90     }
91     return resolution;
92 }
93 
ConvertDeviceType(DeviceType type)94 Global::Resource::DEVICE_TYPE ConvertDeviceType(DeviceType type)
95 {
96     switch (type) {
97         case DeviceType::PHONE:
98             return Global::Resource::DEVICE_TYPE::DEVICE_TYPE_PHONE;
99         case DeviceType::TV:
100             return Global::Resource::DEVICE_TYPE::DEVICE_TYPE_TV;
101         case DeviceType::WATCH:
102             return Global::Resource::DEVICE_TYPE::DEVICE_TYPE_WATCH;
103         case DeviceType::CAR:
104             return Global::Resource::DEVICE_TYPE::DEVICE_TYPE_CAR;
105         case DeviceType::TABLET:
106             return Global::Resource::DEVICE_TYPE::DEVICE_TYPE_TABLET;
107         default:
108             return Global::Resource::DEVICE_TYPE::DEVICE_TYPE_UNDEFINED;
109     }
110 }
111 
ConvertColorMode(ColorMode colorMode)112 Global::Resource::COLOR_MODE ConvertColorMode(ColorMode colorMode)
113 {
114     return colorMode == ColorMode::LIGHT ? Global::Resource::COLOR_MODE::COLOR_MODE_LIGHT
115                                          : Global::Resource::COLOR_MODE::COLOR_MODE_DARK;
116 }
117 
ConvertConfig(const ResourceConfiguration & config)118 Global::Resource::Configuration ConvertConfig(const ResourceConfiguration& config)
119 {
120     Global::Resource::Configuration::Locale locale(AceApplicationInfo::GetInstance().GetLanguage(),
121         AceApplicationInfo::GetInstance().GetCountryOrRegion(), AceApplicationInfo::GetInstance().GetScript());
122     Global::Resource::Configuration globalConfig = {
123         .locales_ = { locale },
124         .orientation_ = ConvertOrientation(config.GetOrientation()),
125         .resolution_ = ConvertResolution(config.GetDensity()),
126         .deviceType_ = ConvertDeviceType(config.GetDeviceType()),
127         .fontRatio_ = config.GetFontRatio(),
128         .colorMode_ = ConvertColorMode(config.GetColorMode()),
129     };
130     return globalConfig;
131 }
132 
ParseStateResource(const std::string & styleName,const std::string & attrName,std::unique_ptr<Global::Resource::SolidXmlWrapper> xmlWrapper)133 RefPtr<StateResource> ParseStateResource(const std::string& styleName, const std::string& attrName,
134     std::unique_ptr<Global::Resource::SolidXmlWrapper> xmlWrapper)
135 {
136     auto rootNode = xmlWrapper->GetRoot();
137     if (!rootNode) {
138         LOGE("Parse %{public}s state resource %{public}s error! No root!", styleName.c_str(), attrName.c_str());
139         return nullptr;
140     }
141     if (rootNode->GetNodeName() != STATE_CONTAINER) {
142         return nullptr;
143     }
144     auto stateResource = AceType::MakeRefPtr<StateResource>();
145     auto node = rootNode->GetChild();
146     uint32_t stateCount = 0;
147     while (node && ++stateCount < STATE_MAX) {
148         // Parse each item
149         auto nodeAttrs = node->GetAttributes();
150         auto valueFindIter = nodeAttrs.find(STATE_ELEMENT);
151         if (valueFindIter == nodeAttrs.end()) {
152             continue;
153         }
154         auto stateColor = Color(valueFindIter->second.GetColorValue());
155         uint32_t state = STATE_NORMAL;
156         static const std::unordered_map<std::string, uint32_t> stateMap = {
157             { "state_pressed", STATE_PRESSED },
158             { "state_focus", STATE_FOCUS },
159             { "state_checked", STATE_CHECKED },
160             { "state_disabled", STATE_DISABLED },
161             { "state_waiting", STATE_WAITING },
162             { "state_hovered", STATE_HOVERED },
163         };
164         for (auto& [stateKey, stateValue] : nodeAttrs) {
165             auto stateFindIter = stateMap.find(stateKey);
166             if (stateFindIter == stateMap.end()) {
167                 continue;
168             }
169             if (stateValue.GetStringValue() != "true") {
170                 continue;
171             }
172             state |= stateFindIter->second;
173         }
174         stateResource->SetStateValue(state, { .type = ThemeConstantsType::COLOR, .value = stateColor });
175         node = node->GetSibling();
176     }
177     return stateResource;
178 }
179 } // namespace
180 
181 class RawThemeStyle : public ThemeStyle {
182     DECLARE_ACE_TYPE(RawThemeStyle, ThemeStyle);
183 
184 public:
185     friend class ResourceAdapterImpl;
186     using RawAttrMap = std::unordered_map<std::string, std::unique_ptr<Global::Resource::TypeAttribute>>;
187 
RawThemeStyle(RefPtr<ResourceAdapter> resAdapter)188     explicit RawThemeStyle(RefPtr<ResourceAdapter> resAdapter) : resAdapter_(resAdapter) {}
189     ~RawThemeStyle() override = default;
190 
191     void ParseContent() override;
192 
193 private:
194     RawAttrMap rawAttrs_; // key and value read from global resource api.
195     RefPtr<ResourceAdapter> resAdapter_;
196 };
197 
ParseContent()198 void RawThemeStyle::ParseContent()
199 {
200     static const std::set<std::string> stringAttrs = {
201         "attr_text_font_family_regular",
202         "attr_text_font_family_medium"
203     };
204     for (auto& [attrName, attrValue] : rawAttrs_) {
205         if (!attrValue) {
206             continue;
207         }
208         auto rawString = attrValue->GetOriginalValue();
209         if (rawString.size() == 0) {
210             continue;
211         }
212         if (rawString.front() == '#' || rawString.find(COLOR_VALUE_PREFIX) != std::string::npos) {
213             // color
214             attributes_[attrName] = { .type = ThemeConstantsType::COLOR, .value = Color(attrValue->GetColorValue()) };
215         } else if (stringAttrs.find(attrName) != stringAttrs.end()) {
216             // string
217             attributes_[attrName] = { .type = ThemeConstantsType::STRING, .value = rawString };
218         } else if (rawString.find(PATTERN_NAME_KEY_WORD) != std::string::npos) {
219             // pattern
220             auto patternStyle = AceType::MakeRefPtr<RawThemeStyle>(resAdapter_);
221             patternStyle->SetName(attrName);
222             patternStyle->parentStyle_ = AceType::WeakClaim(this);
223             patternStyle->rawAttrs_ = attrValue->GetPattern();
224             patternStyle->ParseContent();
225             attributes_[attrName] = { .type = ThemeConstantsType::PATTERN,
226                 .value = RefPtr<ThemeStyle>(std::move(patternStyle)) };
227         } else if (rawString.rfind(STATE_VALUE_KEY_WORD) != std::string::npos) {
228             // state graphic value
229             auto xmlWrapper = attrValue->GetLayoutValue();
230             if (!xmlWrapper) {
231                 LOGE("Parse %{public}s state resource %{public}s error! xml is null!", name_.c_str(), attrName.c_str());
232                 continue;
233             }
234             auto stateResource = ParseStateResource(name_, attrName, std::move(xmlWrapper));
235             if (!stateResource) {
236                 continue;
237             }
238             attributes_[attrName] = { .type = ThemeConstantsType::STATE_RESOURCE, .value = stateResource };
239         } else if (rawString.find(REF_ATTR_VALUE_KEY_WORD) != std::string::npos) {
240             attributes_[attrName] = { .type = ThemeConstantsType::REFERENCE_ATTR, .value = rawString };
241         } else {
242             // double & dimension
243             std::string unit = "";
244             auto doubleValue = static_cast<double>(attrValue->GetFloat(unit));
245             if (unit.empty()) {
246                 attributes_[attrName] = { .type = ThemeConstantsType::DOUBLE, .value = doubleValue };
247             } else {
248                 attributes_[attrName] = { .type = ThemeConstantsType::DIMENSION,
249                     .value = Dimension(doubleValue, ParseDimensionUnit(unit)) };
250             }
251         }
252     }
253 }
254 
Create()255 RefPtr<ResourceAdapter> ResourceAdapter::Create()
256 {
257     auto deviceType = SystemProperties::GetDeviceType();
258     if (deviceType == DeviceType::PHONE || deviceType == DeviceType::CAR || deviceType == DeviceType::TABLET) {
259         return AceType::MakeRefPtr<ResourceAdapterImpl>();
260     }
261     return RefPtr<ResourceAdapter>();
262 }
263 
Init(const ResourceInfo & resourceInfo)264 void ResourceAdapterImpl::Init(const ResourceInfo& resourceInfo)
265 {
266     std::vector<std::string> hapFiles;
267     hapFiles.emplace_back(resourceInfo.GetPackagePath());
268     auto configuration = ConvertConfig(resourceInfo.GetResourceConfiguration());
269     auto handlers = resourceInfo.GetResourceHandlers();
270     bool initRet = false;
271     if (handlers.empty()) {
272         initRet = resourceManger_.InitMock(hapFiles, resourceInfo.GetSystemPackagePath(), configuration);
273     } else {
274         initRet = resourceManger_.Init(hapFiles, handlers);
275         resourceManger_.UpdateConfig(configuration);
276     }
277     LOGI("Init result=%{public}d, handle=%{public}zu, ori=%{public}d, dpi=%{public}f, device=%{public}d, "
278          "font=%{public}f, color=%{public}d",
279         initRet, handlers.size(), configuration.orientation_, configuration.resolution_, configuration.deviceType_,
280         configuration.fontRatio_, configuration.colorMode_);
281 }
282 
Reload()283 void ResourceAdapterImpl::Reload() {}
284 
UpdateConfig(const ResourceConfiguration & config)285 void ResourceAdapterImpl::UpdateConfig(const ResourceConfiguration& config)
286 {
287     auto configuration = ConvertConfig(config);
288     LOGI("UpdateConfig ori=%{public}d, dpi=%{public}f, device=%{public}d, font=%{public}f, color=%{public}d",
289         configuration.orientation_, configuration.resolution_, configuration.deviceType_, configuration.fontRatio_,
290         configuration.colorMode_);
291     resourceManger_.UpdateConfig(configuration);
292 }
293 
GetTheme(int32_t themeId)294 RefPtr<ThemeStyle> ResourceAdapterImpl::GetTheme(int32_t themeId)
295 {
296     CheckThemeId(themeId);
297     auto theme = AceType::MakeRefPtr<RawThemeStyle>(AceType::Claim(this));
298     auto& attrMap = theme->rawAttrs_;
299     auto ret = resourceManger_.GetTheme(themeId, attrMap);
300     LOGI("GetTheme themeId=%{public}d, ret=%{public}d, attr size=%{public}zu", themeId, ret, attrMap.size());
301     auto iter = attrMap.find(THEME_ATTR_BG_COLOR);
302     if (iter != attrMap.end()) {
303         auto& attribute = iter->second;
304         if (attribute) {
305             Color bgColor(attribute->GetColorValue());
306             theme->SetAttr(THEME_ATTR_BG_COLOR, { .type = ThemeConstantsType::COLOR, .value = bgColor });
307         }
308     }
309     return theme;
310 }
311 
GetColor(uint32_t resId)312 Color ResourceAdapterImpl::GetColor(uint32_t resId)
313 {
314     uint32_t result = 0;
315     auto ret = resourceManger_.GetColor(static_cast<int32_t>(resId), result);
316     if (!ret) {
317         LOGE("GetColor error, id=%{public}u", resId);
318     }
319     return Color(result);
320 }
321 
GetDimension(uint32_t resId)322 Dimension ResourceAdapterImpl::GetDimension(uint32_t resId)
323 {
324     float result = 0;
325     std::string unit = "";
326     auto ret = resourceManger_.GetFloat(static_cast<int32_t>(resId), result, unit);
327     if (!ret) {
328         LOGE("GetDimension error, id=%{public}u", resId);
329     }
330     return Dimension(result, ParseDimensionUnit(unit));
331 }
332 
GetString(uint32_t resId)333 std::string ResourceAdapterImpl::GetString(uint32_t resId)
334 {
335     std::string strResult = "";
336     auto ret = resourceManger_.GetString(static_cast<int32_t>(resId), strResult);
337     if (!ret) {
338         LOGE("GetString error, id=%{public}u", resId);
339     }
340     return strResult;
341 }
342 
GetPluralString(uint32_t resId,int quantity)343 std::string ResourceAdapterImpl::GetPluralString(uint32_t resId, int quantity)
344 {
345     std::vector<std::string> pluralResults;
346     auto ret = resourceManger_.GetStringArray(static_cast<int32_t>(resId), pluralResults);
347     if (!ret) {
348         LOGE("GetPluralString error, id=%{public}u", resId);
349     }
350 
351     auto pluralChoice = Localization::GetInstance()->PluralRulesFormat(quantity);
352     auto iter = std::find(pluralResults.begin(), pluralResults.end(), pluralChoice);
353     std::string originStr;
354     if (iter != pluralResults.end() && ++iter != pluralResults.end()) {
355         originStr = *iter;
356     }
357     return originStr;
358 }
359 
GetStringArray(uint32_t resId) const360 std::vector<std::string> ResourceAdapterImpl::GetStringArray(uint32_t resId) const
361 {
362     std::vector<std::string> strResults;
363     auto ret = resourceManger_.GetStringArray(static_cast<int32_t>(resId), strResults);
364     if (!ret) {
365         LOGE("GetStringArray error, id=%{public}u", resId);
366     }
367     return strResults;
368 }
369 
GetDouble(uint32_t resId)370 double ResourceAdapterImpl::GetDouble(uint32_t resId)
371 {
372     float result = 0.0f;
373     auto ret = resourceManger_.GetFloat(static_cast<int32_t>(resId), result);
374     if (!ret) {
375         LOGE("GetDouble error, id=%{public}u", resId);
376     }
377     return static_cast<double>(result);
378 }
379 
GetInt(uint32_t resId)380 int32_t ResourceAdapterImpl::GetInt(uint32_t resId)
381 {
382     int32_t result = 0;
383     auto ret = resourceManger_.GetInt(static_cast<int32_t>(resId), result);
384     if (!ret) {
385         LOGE("GetInt error, id=%{public}u", resId);
386     }
387     return result;
388 }
389 
GetResource(uint32_t resId,std::ostream & dest) const390 bool ResourceAdapterImpl::GetResource(uint32_t resId, std::ostream& dest) const
391 {
392     return resourceManger_.GetResource(static_cast<int32_t>(resId), dest);
393 }
394 
GetResource(const std::string & path,std::ostream & dest) const395 bool ResourceAdapterImpl::GetResource(const std::string& path, std::ostream& dest) const
396 {
397     return resourceManger_.GetResource(path, dest);
398 }
399 
ConvertToGlobalResourceType(const std::string & resTypeName,Global::Resource::ResourceType & resType) const400 bool ResourceAdapterImpl::ConvertToGlobalResourceType(
401     const std::string& resTypeName, Global::Resource::ResourceType& resType) const
402 {
403     if (resTypeName == "color") {
404         resType = Global::Resource::ResourceType::COLOR;
405         return true;
406     }
407     if (resTypeName == "float") {
408         resType = Global::Resource::ResourceType::FLOAT;
409         return true;
410     }
411     if (resTypeName == "string") {
412         resType = Global::Resource::ResourceType::STRING;
413         return true;
414     }
415     if (resTypeName == "media") {
416         resType = Global::Resource::ResourceType::MEDIA;
417         return true;
418     }
419     LOGE("unsupported resource type(=%{public}s)", resTypeName.c_str());
420     return false;
421 }
422 
GetIdByName(const std::string & resName,const std::string & resType,uint32_t & resId) const423 bool ResourceAdapterImpl::GetIdByName(const std::string& resName, const std::string& resType, uint32_t& resId) const
424 {
425     Global::Resource::ResourceType globalResType;
426     if (!ConvertToGlobalResourceType(resType, globalResType)) {
427         return false;
428     }
429     int32_t globalResId = 0;
430     if (!resourceManger_.GetIdByName("", resName, globalResType, globalResId)) {
431         LOGE("get resource id failed.(name=%{public}s, type=%{public}s)", resName.c_str(), resType.c_str());
432         return false;
433     }
434     resId = static_cast<uint32_t>(globalResId);
435     return true;
436 }
437 
GetMediaPath(uint32_t resId)438 std::string ResourceAdapterImpl::GetMediaPath(uint32_t resId)
439 {
440     std::string mediaPath = "";
441     auto ret = resourceManger_.GetString(static_cast<int32_t>(resId), mediaPath);
442     if (!ret) {
443         LOGE("GetMediaPath error, id=%{public}u", resId);
444         return "";
445     }
446     return "resource://" + mediaPath.substr(0, mediaPath.find_last_of("/")) + "/" +
447             std::to_string(resId) + mediaPath.substr(mediaPath.find_last_of("."));
448 }
449 
GetRawfile(const std::string & fileName)450 std::string ResourceAdapterImpl::GetRawfile(const std::string& fileName)
451 {
452     auto container = Container::Current();
453     if (!container) {
454         LOGW("container is null");
455         return "";
456     }
457     auto moduleName = container->GetModuleName();
458 #if defined(PREVIEW)
459     return "resource://RAWFILE/" + moduleName + "/resources/rawfile/" + fileName;
460 #else
461     return "resource://RAWFILE/assets/" + moduleName + "/resources/rawfile/" + fileName;
462 #endif
463 }
464 } // namespace OHOS::Ace
465