• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "unistd.h"
17 #include "peruser_setting.h"
18 #include "platform.h"
19 #include "utils.h"
20 namespace OHOS {
21 namespace MiscServices {
22     /*! Constructor
23     \param userId the id number of this user
24     */
PerUserSetting(int userId)25     PerUserSetting::PerUserSetting(int userId)
26     {
27         userId_ = userId;
28         currentImeId = Utils::to_utf16("");
29         userState = UserState::USER_STATE_STARTED;
30     }
31 
32     /*! Destructor
33     */
~PerUserSetting()34     PerUserSetting::~PerUserSetting()
35     {
36         if (userState == UserState::USER_STATE_UNLOCKED) {
37             OnUserLocked();
38         }
39     }
40 
41     /* Initialize data for this user.
42      * It's called when this user is unlocked. The work includes:
43      * read all installed input method engine information from the system
44      * read input method setting data from the system
45      */
Initialize()46     void PerUserSetting::Initialize()
47     {
48         userState = UserState::USER_STATE_UNLOCKED;
49 
50         inputMethodProperties.clear();
51         int ret = Platform::Instance()->ListInputMethod(userId_, &inputMethodProperties);
52         if (ret != ErrorCode::NO_ERROR) {
53             IMSA_HILOGE("Failed to listInputMethod [%d]\n", userId_);
54         }
55         int size = inputMethodProperties.size();
56         if (size == 0) {
57             currentImeId = Utils::to_utf16("");
58         }
59 
60         ret = Platform::Instance()->GetInputMethodSetting(userId_, &inputMethodSetting);
61         if (ret != ErrorCode::NO_ERROR) {
62             IMSA_HILOGE("Failed to getInputMethodSetting [%d]\n", userId_);
63         } else {
64             if (size > 0) {
65                 InitInputMethodSetting();
66             }
67         }
68     }
69 
70     /**
71      * Add an input method engine.It's called when a package is installed in the system.
72      * @param packageName the package name of installed package.
73      * @param isSecurityIme check if the added ime is a security ime.
74      * @return ErrorCode::NO_ERROR The installed package is an IME package,
75       * and is added in the input method management system
76       * ErrorCode::ERROR_NOT_IME_PACKAGE The installed package is not an IME package.
77       * ErrorCode::ERROR_IME_PACKAGE_DUPLICATED The installed package is duplicated.
78      */
OnPackageAdded(std::u16string & packageName,bool isSecurityIme)79     int PerUserSetting::OnPackageAdded(std::u16string& packageName, bool isSecurityIme)
80     {
81         if (isSecurityIme) {
82             isSecurityIme = false;
83         }
84         std::u16string imeId = GetImeId(packageName);
85         if (imeId.size() != 0) {
86             IMSA_HILOGI("%s [%d]\n", ErrorCode::ToString(ErrorCode::ERROR_IME_PACKAGE_DUPLICATED), userId_);
87             return ErrorCode::ERROR_IME_PACKAGE_DUPLICATED;
88         }
89         // retake the input method list installed in the system.
90         InputMethodProperty *property = new InputMethodProperty();
91         int ret = Platform::Instance()->GetInputMethodProperty(userId_, packageName, property);
92         if (ret != ErrorCode::NO_ERROR) {
93             delete property;
94             property = nullptr;
95             IMSA_HILOGI("%s [%d]\n", ErrorCode::ToString(ErrorCode::ERROR_NOT_IME_PACKAGE), userId_);
96             return ErrorCode::ERROR_NOT_IME_PACKAGE;
97         }
98         inputMethodProperties.push_back(property);
99         if (CheckIfSecurityIme(*property)) {
100             if (isSecurityIme) {
101                 isSecurityIme = true;
102             }
103             return ErrorCode::NO_ERROR;
104         }
105 
106         std::vector<int> types;
107         for (int i = 0; i < (int)property->mTypes.size(); i++) {
108             types.push_back(property->mTypes[i]->getHashCode());
109         }
110 
111         InputMethodSetting imSetting;
112         std::u16string key = InputMethodSetting::ENABLED_INPUT_METHODS_TAG;
113         imSetting.SetValue(key, inputMethodSetting.GetValue(key));
114         imSetting.AddEnabledInputMethod(property->mImeId, types);
115         types.clear();
116         Platform::Instance()->SetInputMethodSetting(userId_, imSetting);
117         return ErrorCode::NO_ERROR;
118     }
119 
120     /**
121      * Remove an input method engine.
122      * It's called when a package is removed from the system.
123      * @param packageName the package name of installed package.
124      * @param isSecurityIme check if the removed ime is a security ime.
125      * @return ErrorCode::NO_ERROR The removed package is an IME package,
126      * and is removed from the input method management system
127      * ErrorCode::ERROR_NOT_IME_PACKAGE The removed package is not an IME package.
128      */
OnPackageRemoved(std::u16string & packageName,bool isSecurityIme)129     int PerUserSetting::OnPackageRemoved(std::u16string& packageName, bool isSecurityIme)
130     {
131         if (isSecurityIme) {
132             isSecurityIme = false;
133         }
134         std::u16string imeId = GetImeId(packageName);
135         if (imeId.size() == 0) {
136             IMSA_HILOGI("%s [%d]\n", ErrorCode::ToString(ErrorCode::ERROR_NOT_IME_PACKAGE), userId_);
137             return ErrorCode::ERROR_NOT_IME_PACKAGE;
138         }
139         bool securityFlag = false;
140         std::vector<InputMethodProperty*>::iterator it;
141         for (it = inputMethodProperties.begin(); it < inputMethodProperties.end(); ++it) {
142             InputMethodProperty *node = (InputMethodProperty*)*it;
143             if (node->mImeId == imeId) {
144                 if (CheckIfSecurityIme(*node) == true) {
145                     securityFlag = true;
146                 }
147                 inputMethodProperties.erase(it);
148                 delete node;
149                 node = nullptr;
150                 break;
151             }
152         }
153         if (securityFlag) {
154             if (isSecurityIme) {
155                 isSecurityIme = true;
156             }
157             return ErrorCode::NO_ERROR;
158         }
159 
160         InputMethodSetting imSetting;
161         std::u16string key = InputMethodSetting::ENABLED_INPUT_METHODS_TAG;
162         imSetting.SetValue(key, inputMethodSetting.GetValue(key));
163 
164         bool flag = imSetting.RemoveEnabledInputMethod(imeId);
165         if (flag == false) {
166             IMSA_HILOGI("The package removed is not an enabled IME. [%d]\n", userId_);
167             return ErrorCode::NO_ERROR;
168         }
169         Platform::Instance()->SetInputMethodSetting(userId_, imSetting);
170         // wait for some time so that the setting change will not be overrided by the followed transact
171         usleep(COMMON_COUNT_ONE_HUNDRED_THOUSAND);
172         return ErrorCode::NO_ERROR;
173     }
174 
175     /*! Update input method setting data.
176     \n It's called when the input method setting data in the system is changed.
177     \param key the name of setting item
178     \param value the value of the setting item
179     \return ErrorCode::NO_ERROR update the setting data to input method management system.
180     \return ErrorCode::ERROR_SETTING_SAME_VALUE the current value is same as the one in the system.
181     */
OnSettingChanged(const std::u16string & key,const std::u16string & value)182     int PerUserSetting::OnSettingChanged(const std::u16string& key, const std::u16string& value)
183     {
184         std::u16string currentValue = inputMethodSetting.GetValue(key);
185 
186         if (currentValue == value) {
187             return ErrorCode::ERROR_SETTING_SAME_VALUE;
188         }
189 
190         inputMethodSetting.SetValue(key, value);
191 
192         if (key == InputMethodSetting::CURRENT_INPUT_METHOD_TAG) {
193             currentImeId = inputMethodSetting.GetCurrentInputMethod();
194         } else if (key == InputMethodSetting::ENABLED_INPUT_METHODS_TAG) {
195             if ((currentImeId.size() > 0 && value.find(currentImeId) == std::string::npos) ||
196                 currentImeId.size() == 0) {
197                 ResetCurrentInputMethod();
198                 InputMethodSetting tmpSetting;
199                 tmpSetting.ClearData();
200                 tmpSetting.SetCurrentInputMethod(currentImeId);
201                 tmpSetting.SetCurrentKeyboardType(-1);
202                 Platform::Instance()->SetInputMethodSetting(userId_, tmpSetting);
203             }
204         }
205         return ErrorCode::NO_ERROR;
206     }
207 
208     /*! Switch to the next input method service.
209     */
OnAdvanceToNext()210     void PerUserSetting::OnAdvanceToNext()
211     {
212         bool flag = false;
213         std::u16string enabledInputMethods = inputMethodSetting.GetValue(InputMethodSetting::ENABLED_INPUT_METHODS_TAG);
214         std::u16string imeId;
215         std::u16string nextImeId = Utils::to_utf16("");
216         InputMethodProperty *firstEnabledProperty = nullptr;
217         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
218             imeId = inputMethodProperties[i]->mImeId;
219             if (imeId == currentImeId) {
220                 flag = true;
221             } else if (enabledInputMethods.find(imeId) != std::string::npos) {
222                 if (flag == true) {
223                     nextImeId = imeId;
224                     break;
225                 } else if (firstEnabledProperty == nullptr) {
226                     firstEnabledProperty = inputMethodProperties[i];
227                 }
228             }
229         }
230 
231         if (nextImeId.size() == 0 && firstEnabledProperty) {
232             nextImeId = firstEnabledProperty->mImeId;
233         }
234 
235         // next enabled ime is not available.
236         if (nextImeId.size() == 0) {
237             IMSA_HILOGW("No next IME is available. [%d]\n", userId_);
238             return;
239         }
240 
241         InputMethodSetting tmpSetting;
242         tmpSetting.SetCurrentInputMethod(nextImeId);
243         tmpSetting.SetCurrentKeyboardType(-1);
244         Platform::Instance()->SetInputMethodSetting(userId_, tmpSetting);
245     }
246 
247     /* It's Called when this user is locked.
248      * Release data for this user including:
249      * release input method engine information
250      * release input method setting data
251      */
OnUserLocked()252     void PerUserSetting::OnUserLocked()
253     {
254         if (userState == UserState::USER_STATE_STARTED) {
255             return;
256         }
257         userState = UserState::USER_STATE_STARTED;
258         currentImeId = Utils::to_utf16("");
259 
260         // release input method properties
261         std::vector<InputMethodProperty*>::iterator it;
262         for (it = inputMethodProperties.begin(); it < inputMethodProperties.end();) {
263             InputMethodProperty *node = (InputMethodProperty*)*it;
264             if (node != nullptr) {
265                 it = inputMethodProperties.erase(it);
266                 delete node;
267                 node = nullptr;
268             }
269         }
270         inputMethodProperties.clear();
271         // release input method setting.
272         inputMethodSetting.ClearData();
273     }
274 
275     /* Print the related information for this user into the given stream
276      * The information includes:
277      * The user id and user state
278      * The information of all input method engine installed in the system
279      * The input method setting data of this user.
280      * param fd the raw file descriptor that the dump is being sent to
281      */
Dump(int fd)282     void PerUserSetting::Dump(int fd)
283     {
284         int size = inputMethodProperties.size();
285         dprintf(fd, "\n - User Setting State :\n");
286         dprintf(fd, " * Installed IME count = %d\n", size);
287         std::vector<std::u16string> imeList = inputMethodSetting.GetEnabledInputMethodList();
288         size = imeList.size();
289         dprintf(fd, "\n * Enabled IME count : %d\n", size);
290         for (int i = 0; i < size; i++) {
291             dprintf(fd, "  [%d] ImeId = %s\n", i, Utils::to_utf8(imeList[i]).c_str());
292             std::vector<int> hashCodeList = inputMethodSetting.GetEnabledKeyboardTypes(imeList[i]);
293             for (int j = 0; j < (int)hashCodeList.size(); j++) {
294                 dprintf(fd, "%d", hashCodeList[j]);
295                 if (j < (int)hashCodeList.size()-1) {
296                     dprintf(fd, ", ");
297                 }
298             }
299             dprintf(fd, "\n");
300             hashCodeList.clear();
301         }
302         imeList.clear();
303     }
304 
305     /*! Get the state of this user
306     \return UserState::USER_STATE_STARTED user is started
307     \return UserState::USER_STATE_UNLOCKED user is unlocked
308     */
GetUserState()309     int PerUserSetting::GetUserState()
310     {
311         return userState;
312     }
313 
314     /*! Get the current IME
315     \return a pointer of InputMethodProperty when an IME is available.
316     \return null when there is no enabled IME in the system.
317     \note The returned pointer should NOT be freed by caller
318     */
GetCurrentInputMethod()319     InputMethodProperty *PerUserSetting::GetCurrentInputMethod()
320     {
321         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
322             if (currentImeId == inputMethodProperties[i]->mImeId) {
323                 return inputMethodProperties[i];
324             }
325         }
326         // if default ime is null, we use security ime as default ime.
327         return GetSecurityInputMethod();
328     }
329 
330     /*! Get the system security IME
331     \return a pointer of InputMethodProperty when an system security IME is available.
332     \return null when there is no security IME in the system.
333     \note The returned pointer should NOT be freed by caller
334     */
GetSecurityInputMethod()335     InputMethodProperty *PerUserSetting::GetSecurityInputMethod()
336     {
337         InputMethodProperty *ime = nullptr;
338         std::u16string systemLocales = inputMethodSetting.GetValue(InputMethodSetting::SYSTEM_LOCALE_TAG);
339         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
340             InputMethodProperty *imp = inputMethodProperties[i];
341             if (CheckIfSecurityIme(*imp) == false) {
342                 continue;
343             }
344             // if systemLocales is not setting, return the first security ime
345             if (systemLocales.size() == 0) {
346                 return imp;
347             }
348             if (ime == nullptr) {
349                 ime = imp;
350             }
351             for (int j = 0; j < (int)inputMethodProperties[i]->mTypes.size(); j++) {
352                 std::u16string language = inputMethodProperties[i]->mTypes[j]->getLanguage();
353                 // if the keyboard language is in the list of system locales, return the ime
354                 if (systemLocales.find(language) != std::string::npos) {
355                     return imp;
356                 }
357             }
358         }
359         return ime;
360     }
361 
362     /*! Get the next enabled IME
363     \return a pointer of InputMethodProperty when the next enabled IME is available.
364     \return null when the next enabled IME is not available.
365     \note The returned pointer should NOT be freed by caller
366     */
GetNextInputMethod()367     InputMethodProperty *PerUserSetting::GetNextInputMethod()
368     {
369         bool flag = false;
370         std::u16string enabledInputMethods = inputMethodSetting.GetValue(InputMethodSetting::ENABLED_INPUT_METHODS_TAG);
371         std::u16string imeId;
372         InputMethodProperty *firstEnabledProperty = nullptr;
373         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
374             imeId = inputMethodProperties[i]->mImeId;
375             if (imeId == currentImeId) {
376                 flag = true;
377             } else if (enabledInputMethods.find(imeId) != std::string::npos) {
378                 if (flag == true) {
379                     return inputMethodProperties[i];
380                 } else if (firstEnabledProperty == nullptr) {
381                     firstEnabledProperty = inputMethodProperties[i];
382                 }
383             }
384         }
385         return firstEnabledProperty;
386     }
387 
388     /*! Get the input method setting data
389     \return a pointer of InputMethodSetting.
390     \note The returned pointer should NOT be freed by caller
391     */
GetInputMethodSetting()392     InputMethodSetting *PerUserSetting::GetInputMethodSetting()
393     {
394         return &inputMethodSetting;
395     }
396 
397     /*! list the details of all the enabled input method engine
398     \param[out] properties the details will be written to the param properties
399     \return ErrorCode::NO_ERROR
400     */
ListInputMethodEnabled(std::vector<InputMethodProperty * > * properties)401     int32_t PerUserSetting::ListInputMethodEnabled(std::vector<InputMethodProperty*> *properties)
402     {
403         std::u16string enabledInputMethods = inputMethodSetting.GetValue(InputMethodSetting::ENABLED_INPUT_METHODS_TAG);
404         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
405             if (enabledInputMethods.find(inputMethodProperties[i]->mImeId) != std::string::npos) {
406                 properties->push_back(inputMethodProperties[i]);
407             }
408         }
409         return ErrorCode::NO_ERROR;
410     }
411 
412     /*! List the details of all input method engine installed in the system
413     \param[out] properties the details will be written to the param properties
414     \return ErrorCode::NO_ERROR
415     */
ListInputMethod(std::vector<InputMethodProperty * > * properties)416     int32_t PerUserSetting::ListInputMethod(std::vector<InputMethodProperty*> *properties)
417     {
418         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
419             properties->push_back(inputMethodProperties[i]);
420         }
421         return ErrorCode::NO_ERROR;
422     }
423 
424     /*! List the keyboard types of given input method engine
425     \param imeId the id of the given IME
426     \param[out] types the data of type list of the given IME will be written to types
427     \return ErrorCode::NO_ERROR
428     */
ListKeyboardType(const std::u16string & imeId,std::vector<KeyboardType * > * types)429     int32_t PerUserSetting::ListKeyboardType(const std::u16string& imeId, std::vector<KeyboardType*> *types)
430     {
431         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
432             if (imeId == inputMethodProperties[i]->mImeId) {
433                 for (int j = 0; j < (int)inputMethodProperties[i]->mTypes.size(); j++) {
434                     types->push_back(inputMethodProperties[i]->mTypes[j]);
435                 }
436                 break;
437             }
438         }
439         return ErrorCode::NO_ERROR;
440     }
441 
442     /*! Get the input method engine details of the given imeId
443     \param imeId the id of the given IME
444     \return a pointer of InputMethodProperty when the given IME exists.
445     \return null when the given IME is not available
446     \note the returned pointer should not be freed by the caller.
447     */
GetInputMethodProperty(const std::u16string & imeId)448     InputMethodProperty *PerUserSetting::GetInputMethodProperty(const std::u16string& imeId)
449     {
450         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
451             if (inputMethodProperties[i]->mImeId == imeId) {
452                 return inputMethodProperties[i];
453             }
454         }
455         return nullptr;
456     }
457 
458     /*! Get the language of keyboard type according to the given hashCode
459     \param property a pointer to an IME
460     \param hashCode the given hashCode
461     \return language value when the given hashCode is found
462     \return an empty string when the given hashCode is not found
463     */
GetKeyboardTypeLanguage(const InputMethodProperty * property,int hashCode)464     std::u16string PerUserSetting::GetKeyboardTypeLanguage(const InputMethodProperty *property, int hashCode)
465     {
466         for (int i = 0; i < (int)property->mTypes.size(); i++) {
467             if (property->mTypes[i]->getHashCode() == hashCode) {
468                 return property->mTypes[i]->getLanguage();
469             }
470         }
471         return Utils::to_utf16("");
472     }
473 
474     /*! Init input method setting data
475     */
InitInputMethodSetting()476     void PerUserSetting::InitInputMethodSetting()
477     {
478         bool flag = inputMethodSetting.FindKey(InputMethodSetting::ENABLED_INPUT_METHODS_TAG);
479         if (flag == false) {
480             for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
481                 if (CheckIfSecurityIme(*inputMethodProperties[i]) == true) {
482                     continue;
483                 }
484                 std::vector<int> types;
485                 for (int j = 0; j < (int)inputMethodProperties[i]->mTypes.size(); j++) {
486                     types.push_back(inputMethodProperties[i]->mTypes[j]->getHashCode());
487                 }
488                 inputMethodSetting.AddEnabledInputMethod(inputMethodProperties[i]->mImeId, types);
489                 types.clear();
490             }
491         }
492 
493         flag = inputMethodSetting.FindKey(InputMethodSetting::CURRENT_INPUT_METHOD_TAG);
494         std::u16string imeId = inputMethodSetting.GetCurrentInputMethod();
495         if (flag == false) {
496             ResetCurrentInputMethod();
497         } else {
498             currentImeId = imeId;
499         }
500         flag = inputMethodSetting.FindKey(InputMethodSetting::CURRENT_SYS_KEYBOARD_TYPE_TAG);
501         if (flag == false) {
502             inputMethodSetting.SetCurrentSysKeyboardType(-1);
503         }
504         Platform::Instance()->SetInputMethodSetting(userId_, inputMethodSetting);
505     }
506 
507     /*! Reset the current (default) input method engine
508     \li Look for the first keyboard language which is in the system locale list.
509     \li If no keyboard language is in system locale list, we use the first system ime as current ime.
510     \li If no system ime is there, we use the first enabled ime as current ime.
511     \li If no enabled ime, set current ime as null.
512     */
ResetCurrentInputMethod()513     void PerUserSetting::ResetCurrentInputMethod()
514     {
515         std::u16string systemLocales = inputMethodSetting.GetValue(InputMethodSetting::SYSTEM_LOCALE_TAG);
516         std::u16string enabledInputMethods = inputMethodSetting.GetValue(InputMethodSetting::ENABLED_INPUT_METHODS_TAG);
517         std::u16string imeId;
518         InputMethodProperty *firstEnabledIme = nullptr;
519         bool flag = false;
520 
521         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
522             imeId = inputMethodProperties[i]->mImeId;
523             if (enabledInputMethods.find(imeId) == std::string::npos) {
524                 continue;
525             }
526             if (firstEnabledIme == nullptr) {
527                 firstEnabledIme = inputMethodProperties[i];
528             }
529 
530             std::vector<int> hashCodeList = inputMethodSetting.GetEnabledKeyboardTypes(imeId);
531             for (int j = 0; j < (int)hashCodeList.size(); j++) {
532                 std::u16string language = GetKeyboardTypeLanguage(inputMethodProperties[i], hashCodeList[j]);
533                 if (systemLocales.find(language) != std::string::npos) {
534                     currentImeId = imeId;
535                     flag = true;
536                     break;
537                 }
538             }
539             if (flag) {
540                 break;
541             }
542         }
543 
544         // if we cannot find any keyboard type which belongs to system locales,
545         // we will use the first enabled ime as current ime.
546         if (flag == false) {
547             if (firstEnabledIme) {
548                 currentImeId = firstEnabledIme->mImeId;
549             } else {
550                 currentImeId = Utils::to_utf16("");
551             }
552         }
553         inputMethodSetting.SetCurrentInputMethod(currentImeId);
554         inputMethodSetting.SetCurrentKeyboardType(-1);
555     }
556 
557     /*! Get the id of the given input method engine
558     \param packageName the packageName of the given IME
559     \return the id of the given IME
560     */
GetImeId(const std::u16string & packageName)561     std::u16string PerUserSetting::GetImeId(const std::u16string& packageName)
562     {
563         for (int i = 0; i < (int)inputMethodProperties.size(); i++) {
564             if (inputMethodProperties[i]->mPackageName == packageName) {
565                 return inputMethodProperties[i]->mImeId;
566             }
567         }
568         return Utils::to_utf16("");
569     }
570 
571     /*! Check if the InputMethodProperty object is a security ime
572     \param property the InputMethodProperty object needed to be checked
573     \return true - It's a security Ime
574     \n      false - It's not a security Ime
575     */
CheckIfSecurityIme(const InputMethodProperty & property)576     bool PerUserSetting::CheckIfSecurityIme(const InputMethodProperty& property)
577     {
578         return property.isSystemIme;
579     }
580 }
581 }