• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 #define MLOG_TAG "ringtone_language"
17 
18 #include "ringtone_language_manager.h"
19 
20 #include "parameter.h"
21 #include "ringtone_errno.h"
22 #include "ringtone_log.h"
23 #include "ringtone_rdbstore.h"
24 #include "ringtone_type.h"
25 #include "ringtone_file_utils.h"
26 #ifdef USE_CONFIG_POLICY
27 #include "config_policy_utils.h"
28 #endif
29 
30 #include <cstring>
31 #include <libxml/tree.h>
32 #include <libxml/parser.h>
33 
34 namespace OHOS {
35 namespace Media {
36 using namespace OHOS::NativeRdb;
37 using namespace std;
38 
39 const char *LANGUAGE_KEY = "persist.global.language";
40 const char *DEFAULT_LANGUAGE_KEY = "const.global.language";
41 const string CHINESE_ABBREVIATION = "zh-Hans";
42 const string ENGLISH_ABBREVIATION = "en-Latn-US";
43 const int32_t SYSPARA_SIZE = 64;
44 const int32_t SYSINIT_TYPE = 1;
45 const int32_t UNKNOWN_INDEX = -1;
46 const int32_t FIELD_LENGTH = 2;
47 #ifdef USE_CONFIG_POLICY
48 static constexpr char RINGTONE_MULTILINGUAL_FILE_PATH[] =
49     "etc/resource/media/audio/ringtone_list_language.xml";
50 #else
51 static constexpr char RINGTONE_MULTILINGUAL_FILE_PATH[] =
52     "/system/variant/phone/base/etc/resource/media/audio/ringtone_list_language.xml";
53 #endif
54 
55 shared_ptr<RingtoneLanguageManager> RingtoneLanguageManager::instance_ = nullptr;
56 mutex RingtoneLanguageManager::mutex_;
57 
RingtoneLanguageManager(void)58 RingtoneLanguageManager::RingtoneLanguageManager(void)
59 {
60 }
61 
~RingtoneLanguageManager(void)62 RingtoneLanguageManager::~RingtoneLanguageManager(void)
63 {
64 }
65 
GetInstance()66 shared_ptr<RingtoneLanguageManager> RingtoneLanguageManager::GetInstance()
67 {
68     if (instance_ == nullptr) {
69         lock_guard<mutex> lock(mutex_);
70 
71         if (instance_ == nullptr) {
72             instance_ = make_shared<RingtoneLanguageManager>();
73         }
74     }
75     return instance_;
76 }
77 
SyncAssetLanguage()78 void RingtoneLanguageManager::SyncAssetLanguage()
79 {
80     RINGTONE_INFO_LOG("SyncAssetLanguage start.");
81     systemLanguage_ = GetSystemLanguage();
82     if (systemLanguage_.empty()) {
83         RINGTONE_ERR_LOG("Failed to get system language");
84         return;
85     }
86     RINGTONE_INFO_LOG("system language is %{public}s", systemLanguage_.c_str());
87     if (strncmp(systemLanguage_.c_str(), CHINESE_ABBREVIATION.c_str(), CHINESE_ABBREVIATION.size()) == 0) {
88         systemLanguage_ = CHINESE_ABBREVIATION;
89     } else {
90         systemLanguage_ = ENGLISH_ABBREVIATION;
91     }
92     UpdateRingtoneLanguage();
93     RINGTONE_INFO_LOG("SyncAssetLanguage end.");
94 }
95 
GetSystemLanguage()96 string RingtoneLanguageManager::GetSystemLanguage()
97 {
98     char param[SYSPARA_SIZE] = {0};
99     int status = GetParameter(LANGUAGE_KEY, "", param, SYSPARA_SIZE);
100     if (status > 0) {
101         return param;
102     }
103     status = GetParameter(DEFAULT_LANGUAGE_KEY, "", param, SYSPARA_SIZE);
104     if (status > 0) {
105         return param;
106     }
107     return "";
108 }
109 
UpdateRingtoneLanguage()110 void RingtoneLanguageManager::UpdateRingtoneLanguage()
111 {
112     RINGTONE_INFO_LOG("UpdateRingtonLanguage start.");
113     int32_t rowCount = 0;
114     std::shared_ptr<NativeRdb::ResultSet> resultSet;
115     if (CheckLanguageTypeByRingtone(rowCount, resultSet) != E_OK) {
116         return;
117     }
118     RINGTONE_INFO_LOG("%{public}d ring tones need to be sync", rowCount);
119     if (rowCount == 0) {
120         return;
121     }
122 #ifdef USE_CONFIG_POLICY
123     char buf[MAX_PATH_LEN] = {0};
124     char *path = GetOneCfgFile(RINGTONE_MULTILINGUAL_FILE_PATH, buf, MAX_PATH_LEN);
125     if (path == nullptr || *path == '\0') {
126         RINGTONE_ERR_LOG("GetOneCfgFile for %{public}s failed.", RINGTONE_MULTILINGUAL_FILE_PATH);
127         return;
128     }
129 #else
130     const char *path = RINGTONE_MULTILINGUAL_FILE_PATH;
131 #endif
132 
133     if (!ReadMultilingualResources(path, RINGTONE_FILE)) {
134         return;
135     }
136     ChangeLanguageDataToRingtone(rowCount, resultSet);
137     RINGTONE_INFO_LOG("UpdateRingtonLanguage end.");
138 }
139 
CheckLanguageTypeByRingtone(int32_t & rowCount,shared_ptr<ResultSet> & resultSet)140 int32_t RingtoneLanguageManager::CheckLanguageTypeByRingtone(int32_t &rowCount,
141     shared_ptr<ResultSet> &resultSet)
142 {
143     vector<string> columns = {
144         RINGTONE_COLUMN_TONE_ID,
145         RINGTONE_COLUMN_DATA
146     };
147 
148     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
149     if (rawRdb == nullptr) {
150         RINGTONE_ERR_LOG("failed to get raw rdb");
151         return E_RDB;
152     }
153 
154     AbsRdbPredicates absRdbPredicates(RINGTONE_TABLE);
155     absRdbPredicates.EqualTo(RINGTONE_COLUMN_SOURCE_TYPE, SYSINIT_TYPE);
156     absRdbPredicates.And();
157     absRdbPredicates.BeginWrap();
158     absRdbPredicates.NotEqualTo(RINGTONE_COLUMN_DISPLAY_LANGUAGE_TYPE, systemLanguage_);
159     absRdbPredicates.Or();
160     absRdbPredicates.IsNull(RINGTONE_COLUMN_DISPLAY_LANGUAGE_TYPE);
161     absRdbPredicates.EndWrap();
162     resultSet = rawRdb->Query(absRdbPredicates, columns);
163     if (resultSet == nullptr) {
164         RINGTONE_ERR_LOG("failed to query rdb");
165         return E_RDB;
166     }
167 
168     int32_t ret = resultSet->GetRowCount(rowCount);
169     if (ret != NativeRdb::E_OK) {
170         RINGTONE_ERR_LOG("failed to get resultSet row count");
171         return E_RDB;
172     }
173     return E_OK;
174 }
175 
ChangeLanguageDataToRingtone(int32_t rowCount,const std::shared_ptr<ResultSet> & resultSet)176 void RingtoneLanguageManager::ChangeLanguageDataToRingtone(int32_t rowCount,
177     const std::shared_ptr<ResultSet> &resultSet)
178 {
179     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
180     if (rawRdb == nullptr) {
181         RINGTONE_ERR_LOG("failed to get raw rdb");
182         return;
183     }
184 
185     vector<pair<string, int>> fieldIndex = {
186         { RINGTONE_COLUMN_TONE_ID, UNKNOWN_INDEX },
187         { RINGTONE_COLUMN_DATA, UNKNOWN_INDEX }
188     };
189     if (GetFieldIndex(resultSet, fieldIndex) != E_OK) {
190         return;
191     }
192 
193     for (int i = 0; i < rowCount; i++) {
194         if (resultSet->GoToRow(i) != E_OK) {
195             RINGTONE_ERR_LOG("failed to goto row : %{public}d", i);
196             return;
197         }
198 
199         ValuesBucket values;
200         int ringtoneId;
201         if (SetValuesFromResultSet(resultSet, fieldIndex, values, ringtoneId) == E_OK) {
202             AbsRdbPredicates absRdbPredicates(RINGTONE_TABLE);
203             absRdbPredicates.EqualTo(RINGTONE_COLUMN_TONE_ID, ringtoneId);
204             int32_t changedRows;
205             int32_t result = rawRdb->Update(changedRows, values, absRdbPredicates);
206             if (result != E_OK || changedRows <= 0) {
207                 RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, changedRows);
208                 return;
209             }
210         }
211     }
212 }
213 
GetFieldIndex(const shared_ptr<ResultSet> & resultSet,vector<pair<string,int>> & fieldIndex)214 int32_t RingtoneLanguageManager::GetFieldIndex(const shared_ptr<ResultSet> &resultSet,
215     vector<pair<string, int>> &fieldIndex)
216 {
217     for (auto& field : fieldIndex) {
218         if (resultSet->GetColumnIndex(field.first, field.second) != E_OK) {
219             RINGTONE_ERR_LOG("failed to get field index");
220             return E_RDB;
221         }
222     }
223     return E_OK;
224 }
225 
SetValuesFromResultSet(const shared_ptr<ResultSet> & resultSet,const vector<pair<string,int>> & fieldIndex,ValuesBucket & values,int32_t & ringtoneId)226 int32_t RingtoneLanguageManager::SetValuesFromResultSet(const shared_ptr<ResultSet> &resultSet,
227     const vector<pair<string, int>> &fieldIndex, ValuesBucket &values, int32_t &ringtoneId)
228 {
229     string data;
230     if (fieldIndex.size() < FIELD_LENGTH) {
231         return E_RDB;
232     }
233     if (resultSet->GetInt(fieldIndex[0].second, ringtoneId) != E_OK) {
234         RINGTONE_ERR_LOG("failed to get tone_id value");
235         return E_RDB;
236     }
237     if (resultSet->GetString(fieldIndex[1].second, data) != E_OK) {
238         RINGTONE_ERR_LOG("failed to get data value");
239         return E_RDB;
240     }
241     values.PutString(RINGTONE_COLUMN_DISPLAY_LANGUAGE_TYPE, systemLanguage_);
242     string realName = RingtoneFileUtils::GetBaseNameFromPath(data);
243     auto item = ringtoneTranslate_[systemLanguage_].find(realName);
244     if (item == ringtoneTranslate_[systemLanguage_].end()) {
245         return E_OK;
246     }
247     string titleName = item->second;
248     values.PutString(RINGTONE_COLUMN_TITLE, titleName);
249     return E_OK;
250 }
251 
ReadMultilingualResources(const string & filePath,ResourceFileType resourceFileType)252 bool RingtoneLanguageManager::ReadMultilingualResources(const string &filePath, ResourceFileType resourceFileType)
253 {
254     std::unique_ptr<xmlDoc, decltype(&xmlFreeDoc)> docPtr(
255         xmlReadFile(filePath.c_str(), nullptr, XML_PARSE_NOBLANKS), xmlFreeDoc);
256     if (docPtr == nullptr) {
257         RINGTONE_ERR_LOG("failed to read xml file [%{public}s]", filePath.c_str());
258         xmlErrorPtr error = xmlGetLastError();
259         if (error != nullptr) {
260             RINGTONE_ERR_LOG("Error: %{public}s (line %{public}d): %{public}s",
261                 error->file, error->line, error->message);
262             xmlResetLastError();
263         }
264         return false;
265     }
266 
267     xmlNodePtr rootNode = xmlDocGetRootElement(docPtr.get());
268     if (rootNode == nullptr) {
269         RINGTONE_ERR_LOG("failed to read root node");
270         return false;
271     }
272     if (resourceFileType == RINGTONE_FILE) {
273         if (xmlStrcmp(rootNode->name, BAD_CAST "RingtoneList") != 0) {
274             RINGTONE_ERR_LOG("failed to root node name is not matched");
275             return false;
276         }
277         ringtoneTranslate_.clear();
278     }
279     return ParseMultilingualXml(rootNode, resourceFileType);
280 }
281 
ParseMultilingualXml(xmlNodePtr & rootNode,ResourceFileType resourceFileType)282 bool RingtoneLanguageManager::ParseMultilingualXml(xmlNodePtr &rootNode, ResourceFileType resourceFileType)
283 {
284     for (xmlNodePtr itemNode = rootNode->children; itemNode; itemNode = itemNode->next) {
285         if (xmlStrcmp(itemNode->name, BAD_CAST "Language") != 0) {
286             continue;
287         }
288 
289         string language;
290         auto xmlLanguage = reinterpret_cast<char*>(xmlGetProp(itemNode, BAD_CAST "type"));
291         if (xmlLanguage != nullptr) {
292             language = string(xmlLanguage);
293             xmlFree(xmlLanguage);
294         }
295 
296         for (xmlNodePtr childNode = itemNode->children; childNode; childNode = childNode->next) {
297             if (resourceFileType == RINGTONE_FILE && xmlStrcmp(childNode->name, BAD_CAST "Ring") != 0) {
298                 RINGTONE_ERR_LOG("failed to child node name is not matched");
299                 return false;
300             }
301 
302             string resourceName, displayName;
303             auto xmlResourceName = reinterpret_cast<char*>(xmlGetProp(childNode, BAD_CAST "resource_name"));
304             if (xmlResourceName) {
305                 resourceName = string(xmlResourceName);
306                 xmlFree(xmlResourceName);
307             }
308 
309             auto xmlDisplayName = reinterpret_cast<char*>(xmlGetProp(childNode, BAD_CAST "title"));
310             if (xmlDisplayName) {
311                 displayName = string(xmlDisplayName);
312                 xmlFree(xmlDisplayName);
313             }
314 
315             if (resourceFileType == RINGTONE_FILE && !resourceName.empty() && !displayName.empty()) {
316                 ringtoneTranslate_[language][resourceName] = displayName;
317             }
318         }
319     }
320     return true;
321 }
322 
323 } // namespace Media
324 } // namespace OHOS
325