• 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         deviceType == DeviceType::TWO_IN_ONE) {
260         return AceType::MakeRefPtr<ResourceAdapterImpl>();
261     }
262     return RefPtr<ResourceAdapter>();
263 }
264 
Init(const ResourceInfo & resourceInfo)265 void ResourceAdapterImpl::Init(const ResourceInfo& resourceInfo)
266 {
267     std::vector<std::string> hapFiles;
268     hapFiles.emplace_back(resourceInfo.GetPackagePath());
269     auto configuration = ConvertConfig(resourceInfo.GetResourceConfiguration());
270     auto handlers = resourceInfo.GetResourceHandlers();
271     bool initRet = false;
272     if (handlers.empty()) {
273         initRet = resourceManger_.InitMock(hapFiles, resourceInfo.GetSystemPackagePath(), configuration);
274     } else {
275         initRet = resourceManger_.Init(hapFiles, handlers);
276         resourceManger_.UpdateConfig(configuration);
277     }
278     LOGI("Init result=%{public}d, handle=%{public}zu, ori=%{public}d, dpi=%{public}f, device=%{public}d, "
279          "font=%{public}f, color=%{public}d",
280         initRet, handlers.size(), configuration.orientation_, configuration.resolution_, configuration.deviceType_,
281         configuration.fontRatio_, configuration.colorMode_);
282 }
283 
UpdateConfig(const ResourceConfiguration & config)284 void ResourceAdapterImpl::UpdateConfig(const ResourceConfiguration& config)
285 {
286     auto configuration = ConvertConfig(config);
287     LOGI("UpdateConfig ori=%{public}d, dpi=%{public}f, device=%{public}d, font=%{public}f, color=%{public}d",
288         configuration.orientation_, configuration.resolution_, configuration.deviceType_, configuration.fontRatio_,
289         configuration.colorMode_);
290     resourceManger_.UpdateConfig(configuration);
291 }
292 
GetTheme(int32_t themeId)293 RefPtr<ThemeStyle> ResourceAdapterImpl::GetTheme(int32_t themeId)
294 {
295     CheckThemeId(themeId);
296     auto theme = AceType::MakeRefPtr<RawThemeStyle>(AceType::Claim(this));
297     auto& attrMap = theme->rawAttrs_;
298     auto ret = resourceManger_.GetTheme(themeId, attrMap);
299     LOGI("GetTheme themeId=%{public}d, ret=%{public}d, attr size=%{public}zu", themeId, ret, attrMap.size());
300     auto iter = attrMap.find(THEME_ATTR_BG_COLOR);
301     if (iter != attrMap.end()) {
302         auto& attribute = iter->second;
303         if (attribute) {
304             Color bgColor(attribute->GetColorValue());
305             theme->SetAttr(THEME_ATTR_BG_COLOR, { .type = ThemeConstantsType::COLOR, .value = bgColor });
306         }
307     }
308     return theme;
309 }
310 
GetColor(uint32_t resId)311 Color ResourceAdapterImpl::GetColor(uint32_t resId)
312 {
313     uint32_t result = 0;
314     auto ret = resourceManger_.GetColor(static_cast<int32_t>(resId), result);
315     if (!ret) {
316         LOGE("GetColor error, id=%{public}u", resId);
317     }
318     return Color(result);
319 }
320 
GetDimension(uint32_t resId)321 Dimension ResourceAdapterImpl::GetDimension(uint32_t resId)
322 {
323     float result = 0;
324     std::string unit = "";
325     auto ret = resourceManger_.GetFloat(static_cast<int32_t>(resId), result, unit);
326     if (!ret) {
327         LOGE("GetDimension error, id=%{public}u", resId);
328     }
329     return Dimension(result, ParseDimensionUnit(unit));
330 }
331 
GetString(uint32_t resId)332 std::string ResourceAdapterImpl::GetString(uint32_t resId)
333 {
334     std::string strResult = "";
335     auto ret = resourceManger_.GetString(static_cast<int32_t>(resId), strResult);
336     if (!ret) {
337         LOGE("GetString error, id=%{public}u", resId);
338     }
339     return strResult;
340 }
341 
GetPluralString(uint32_t resId,int quantity)342 std::string ResourceAdapterImpl::GetPluralString(uint32_t resId, int quantity)
343 {
344     std::vector<std::string> pluralResults;
345     auto ret = resourceManger_.GetStringArray(static_cast<int32_t>(resId), pluralResults);
346     if (!ret) {
347         LOGE("GetPluralString error, id=%{public}u", resId);
348     }
349 
350     auto pluralChoice = Localization::GetInstance()->PluralRulesFormat(quantity);
351     auto iter = std::find(pluralResults.begin(), pluralResults.end(), pluralChoice);
352     std::string originStr;
353     if (iter != pluralResults.end() && ++iter != pluralResults.end()) {
354         originStr = *iter;
355     }
356     return originStr;
357 }
358 
GetStringArray(uint32_t resId) const359 std::vector<std::string> ResourceAdapterImpl::GetStringArray(uint32_t resId) const
360 {
361     std::vector<std::string> strResults;
362     auto ret = resourceManger_.GetStringArray(static_cast<int32_t>(resId), strResults);
363     if (!ret) {
364         LOGE("GetStringArray error, id=%{public}u", resId);
365     }
366     return strResults;
367 }
368 
GetDouble(uint32_t resId)369 double ResourceAdapterImpl::GetDouble(uint32_t resId)
370 {
371     float result = 0.0f;
372     auto ret = resourceManger_.GetFloat(static_cast<int32_t>(resId), result);
373     if (!ret) {
374         LOGE("GetDouble error, id=%{public}u", resId);
375     }
376     return static_cast<double>(result);
377 }
378 
GetInt(uint32_t resId)379 int32_t ResourceAdapterImpl::GetInt(uint32_t resId)
380 {
381     int32_t result = 0;
382     auto ret = resourceManger_.GetInt(static_cast<int32_t>(resId), result);
383     if (!ret) {
384         LOGE("GetInt error, id=%{public}u", resId);
385     }
386     return result;
387 }
388 
GetResource(uint32_t resId,std::ostream & dest) const389 bool ResourceAdapterImpl::GetResource(uint32_t resId, std::ostream& dest) const
390 {
391     return resourceManger_.GetResource(static_cast<int32_t>(resId), dest);
392 }
393 
GetResource(const std::string & path,std::ostream & dest) const394 bool ResourceAdapterImpl::GetResource(const std::string& path, std::ostream& dest) const
395 {
396     return resourceManger_.GetResource(path, dest);
397 }
398 
ConvertToGlobalResourceType(const std::string & resTypeName,Global::Resource::ResourceType & resType) const399 bool ResourceAdapterImpl::ConvertToGlobalResourceType(
400     const std::string& resTypeName, Global::Resource::ResourceType& resType) const
401 {
402     if (resTypeName == "color") {
403         resType = Global::Resource::ResourceType::COLOR;
404         return true;
405     }
406     if (resTypeName == "float") {
407         resType = Global::Resource::ResourceType::FLOAT;
408         return true;
409     }
410     if (resTypeName == "string") {
411         resType = Global::Resource::ResourceType::STRING;
412         return true;
413     }
414     if (resTypeName == "media") {
415         resType = Global::Resource::ResourceType::MEDIA;
416         return true;
417     }
418     LOGE("unsupported resource type(=%{public}s)", resTypeName.c_str());
419     return false;
420 }
421 
GetIdByName(const std::string & resName,const std::string & resType,uint32_t & resId) const422 bool ResourceAdapterImpl::GetIdByName(const std::string& resName, const std::string& resType, uint32_t& resId) const
423 {
424     Global::Resource::ResourceType globalResType;
425     if (!ConvertToGlobalResourceType(resType, globalResType)) {
426         return false;
427     }
428     int32_t globalResId = 0;
429     if (!resourceManger_.GetIdByName("", resName, globalResType, globalResId)) {
430         LOGE("get resource id failed.(name=%{public}s, type=%{public}s)", resName.c_str(), resType.c_str());
431         return false;
432     }
433     resId = static_cast<uint32_t>(globalResId);
434     return true;
435 }
436 
GetMediaPath(uint32_t resId)437 std::string ResourceAdapterImpl::GetMediaPath(uint32_t resId)
438 {
439     std::string mediaPath = "";
440     auto ret = resourceManger_.GetString(static_cast<int32_t>(resId), mediaPath);
441     if (!ret) {
442         LOGE("GetMediaPath error, id=%{public}u", resId);
443         return "";
444     }
445     return "resource://" + mediaPath.substr(0, mediaPath.find_last_of("/")) + "/" +
446             std::to_string(resId) + mediaPath.substr(mediaPath.find_last_of("."));
447 }
448 
GetRawfile(const std::string & fileName)449 std::string ResourceAdapterImpl::GetRawfile(const std::string& fileName)
450 {
451     auto container = Container::Current();
452     if (!container) {
453         LOGW("container is null");
454         return "";
455     }
456     auto moduleName = container->GetModuleName();
457 #if defined(PREVIEW)
458     return "resource://RAWFILE/" + moduleName + "/resources/rawfile/" + fileName;
459 #else
460     return "resource://RAWFILE/assets/" + moduleName + "/resources/rawfile/" + fileName;
461 #endif
462 }
463 } // namespace OHOS::Ace
464