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 }