diff --git a/frameworks/native/inputmethod_controller/include/input_method_property.h b/frameworks/native/inputmethod_controller/include/input_method_property.h index 1b61e2a4b2deb7b7b1a3cd1fc3d8bc170aef57f8..b19d18a69b3a4dc28d313f8b377420ccc0f4cd2d 100644 --- a/frameworks/native/inputmethod_controller/include/input_method_property.h +++ b/frameworks/native/inputmethod_controller/include/input_method_property.h @@ -166,6 +166,9 @@ struct SwitchInfo { std::chrono::system_clock::time_point timestamp{}; std::string bundleName; std::string subName; + /* isTmpImeSwitchSubtype:true -- switch subtype of self, switch trigger is current running ime, + but not default ime set by user */ + bool isTmpImeSwitchSubtype{ false }; bool operator==(const SwitchInfo &info) const { return (timestamp == info.timestamp && bundleName == info.bundleName && subName == info.subName); diff --git a/services/include/input_method_system_ability.h b/services/include/input_method_system_ability.h index 0aaf44a4fb0032ba859c48542beaa3bf751dc0f9..9ffe9e226ff854a953cd96ee93f2c3e8bd049882 100644 --- a/services/include/input_method_system_ability.h +++ b/services/include/input_method_system_ability.h @@ -179,7 +179,7 @@ private: int32_t CheckInputTypeOption(int32_t userId, InputClientInfo &inputClientInfo); int32_t IsDefaultImeFromTokenId(int32_t userId, uint32_t tokenId); void DealSwitchRequest(); - bool IsCurrentIme(int32_t userId); + bool IsCurrentIme(int32_t userId, uint32_t tokenId); int32_t StartInputType(int32_t userId, InputType type); // if switch input type need to switch ime, then no need to hide panel first. void NeedHideWhenSwitchInputType(int32_t userId, InputType type, bool &needHide); @@ -210,6 +210,8 @@ private: int32_t RestoreInputmethod(std::string &bundleName); void IncreaseAttachCount(); void DecreaseAttachCount(); + bool IsTmpIme(int32_t userId, uint32_t tokenId); + bool IsTmpImeSwitchSubtype(int32_t userId, uint32_t tokenId, const SwitchInfo &switchInfo); class AttachStateGuard { public: diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index 5b6e6a3f5225cb3dcece483885f347f8a66f088f..32512990bad31043d8fbc0b4fecb148f3f446e32 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -839,15 +839,16 @@ ErrCode InputMethodSystemAbility::SetCoreAndAgent(const sptr & IMSA_HILOGD("InputMethodSystemAbility start."); auto pid = IPCSkeleton::GetCallingPid(); auto userId = GetCallingUserId(); + auto tokenId = GetCallingTokenID(); auto session = UserSessionManager::GetInstance().GetUserSession(userId); if (session == nullptr) { IMSA_HILOGE("%{public}d session is nullptr!", userId); return ErrorCode::ERROR_NULL_POINTER; } - if (identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID())) { + if (identityChecker_->IsNativeSa(tokenId)) { return session->OnRegisterProxyIme(core, agent, pid); } - if (!IsCurrentIme(userId)) { + if (!IsCurrentIme(userId, tokenId)) { IMSA_HILOGE("not current ime, userId:%{public}d", userId); return ErrorCode::ERROR_NOT_CURRENT_IME; } @@ -945,15 +946,17 @@ ErrCode InputMethodSystemAbility::InitConnect() { IMSA_HILOGD("InputMethodSystemAbility init connect."); auto userId = GetCallingUserId(); + auto tokenId = GetCallingTokenID(); + auto pid = IPCSkeleton::GetCallingPid(); auto session = UserSessionManager::GetInstance().GetUserSession(userId); if (session == nullptr) { IMSA_HILOGE("%{public}d session is nullptr!", userId); return ErrorCode::ERROR_NULL_POINTER; } - if (!IsCurrentIme(userId)) { + if (!IsCurrentIme(userId, tokenId)) { return ErrorCode::ERROR_NOT_CURRENT_IME; } - return session->InitConnect(IPCSkeleton::GetCallingPid()); + return session->InitConnect(pid); } ErrCode InputMethodSystemAbility::HideCurrentInput() @@ -995,7 +998,8 @@ ErrCode InputMethodSystemAbility::ShowCurrentInputInner() ErrCode InputMethodSystemAbility::PanelStatusChange(uint32_t status, const ImeWindowInfo &info) { auto userId = GetCallingUserId(); - if (!IsCurrentIme(userId)) { + auto tokenId = GetCallingTokenID(); + if (!IsCurrentIme(userId, tokenId)) { IMSA_HILOGE("not current ime!"); return ErrorCode::ERROR_NOT_CURRENT_IME; } @@ -1077,7 +1081,9 @@ ErrCode InputMethodSystemAbility::GetInputStartInfo(bool& isInputStart, ErrCode InputMethodSystemAbility::IsCurrentIme(bool& resultValue) { - resultValue = IsCurrentIme(GetCallingUserId()); + auto userId = GetCallingUserId(); + auto tokenId = GetCallingTokenID(); + resultValue = IsCurrentIme(userId, tokenId); return ERR_OK; } @@ -1194,8 +1200,9 @@ ErrCode InputMethodSystemAbility::SwitchInputMethod(const std::string &bundleNam IMSA_HILOGW("caller counterfeit!"); return ErrorCode::ERROR_BAD_PARAMETERS; } - SwitchInfo switchInfo = { std::chrono::system_clock::now(), bundleName, subName }; int32_t userId = GetCallingUserId(); + auto tokenId = GetCallingTokenID(); + SwitchInfo switchInfo = { std::chrono::system_clock::now(), bundleName, subName }; auto session = UserSessionManager::GetInstance().GetUserSession(userId); if (session == nullptr) { IMSA_HILOGE("%{public}d session is nullptr!", userId); @@ -1216,6 +1223,7 @@ ErrCode InputMethodSystemAbility::SwitchInputMethod(const std::string &bundleNam switchInfo.subName = currentImeCfg->subName; } switchInfo.timestamp = std::chrono::system_clock::now(); + switchInfo.isTmpImeSwitchSubtype = IsTmpImeSwitchSubtype(userId, tokenId, switchInfo); session->GetSwitchQueue().Push(switchInfo); return InputTypeManager::GetInstance().IsInputType({ bundleName, subName }) ? OnStartInputType(userId, switchInfo, true) @@ -1257,7 +1265,9 @@ int32_t InputMethodSystemAbility::StartSwitch(int32_t userId, const SwitchInfo & { InputMethodSyncTrace tracer("InputMethodSystemAbility_OnSwitchInputMethod"); std::string targetImeName = info->prop.name + "/" + info->prop.id; - ImeCfgManager::GetInstance().ModifyImeCfg({ userId, targetImeName, switchInfo.subName, true }); + if (!switchInfo.isTmpImeSwitchSubtype) { + ImeCfgManager::GetInstance().ModifyImeCfg({ userId, targetImeName, switchInfo.subName, true }); + } auto targetIme = std::make_shared( ImeNativeCfg{ targetImeName, info->prop.name, switchInfo.subName, info->prop.id }); ret = session->StartIme(targetIme); @@ -1267,7 +1277,9 @@ int32_t InputMethodSystemAbility::StartSwitch(int32_t userId, const SwitchInfo & return ret; } GetValidSubtype(switchInfo.subName, info); - session->NotifyImeChangeToClients(info->prop, info->subProp); + if (!switchInfo.isTmpImeSwitchSubtype) { + session->NotifyImeChangeToClients(info->prop, info->subProp); + } ret = session->SwitchSubtype(info->subProp); } ret = info->isSpecificSubName ? ret : ErrorCode::NO_ERROR; @@ -1278,6 +1290,48 @@ int32_t InputMethodSystemAbility::StartSwitch(int32_t userId, const SwitchInfo & return ret; } +bool InputMethodSystemAbility::IsTmpIme(int32_t userId, uint32_t tokenId) +{ + auto session = UserSessionManager::GetInstance().GetUserSession(userId); + if (session == nullptr) { + IMSA_HILOGE("user:%{public}d session is nullptr!", userId); + return false; + } + auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId); + if (currentImeCfg == nullptr) { + IMSA_HILOGE("user:%{public}d has no default ime.", userId); + return false; + } + auto imeData = session->GetImeData(ImeType::IME); + if (imeData == nullptr) { + IMSA_HILOGE("user:%{public}d has no running ime.", userId); + return false; + } + auto bundleName = FullImeInfoManager::GetInstance().Get(userId, tokenId); + if (bundleName.empty()) { + bundleName = identityChecker_->GetBundleNameByToken(tokenId); + IMSA_HILOGW("%{public}d/%{public}d/%{public}s not find in cache.", userId, tokenId, bundleName.c_str()); + } + return !currentImeCfg->bundleName.empty() && !bundleName.empty() && + imeData->ime.first != currentImeCfg->bundleName && imeData->ime.first == bundleName; +} + +bool InputMethodSystemAbility::IsTmpImeSwitchSubtype(int32_t userId, uint32_t tokenId, const SwitchInfo &switchInfo) +{ + if (!IsTmpIme(userId, tokenId)) { + IMSA_HILOGD("user:%{public}d tokenId:%{public}d not tmp ime.", userId, tokenId); + return false; + } + auto bundleName = FullImeInfoManager::GetInstance().Get(userId, tokenId); + if (bundleName.empty()) { + bundleName = identityChecker_->GetBundleNameByToken(tokenId); + IMSA_HILOGW("%{public}d/%{public}d/%{public}s not find in cache.", userId, tokenId, bundleName.c_str()); + } + bool ret = !bundleName.empty() && bundleName == switchInfo.bundleName; + IMSA_HILOGD("%{public}s/%{public}d switch.", switchInfo.bundleName.c_str(), ret); + return ret; +} + int32_t InputMethodSystemAbility::OnSwitchInputMethod(int32_t userId, const SwitchInfo &switchInfo, SwitchTrigger trigger) { @@ -2215,6 +2269,7 @@ int32_t InputMethodSystemAbility::CheckSwitchPermission(int32_t userId, const Sw SwitchTrigger trigger) { IMSA_HILOGD("trigger: %{public}d.", static_cast(trigger)); + auto tokenId = IPCSkeleton::GetCallingTokenID(); if (trigger == SwitchTrigger::IMSA) { return ErrorCode::NO_ERROR; } @@ -2226,8 +2281,7 @@ int32_t InputMethodSystemAbility::CheckSwitchPermission(int32_t userId, const Sw IMSA_HILOGE("not system app!"); return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION; } - if (!identityChecker_->HasPermission(IPCSkeleton::GetCallingTokenID(), - std::string(PERMISSION_CONNECT_IME_ABILITY))) { + if (!identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) { IMSA_HILOGE("have not PERMISSION_CONNECT_IME_ABILITY!"); return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; } @@ -2235,14 +2289,12 @@ int32_t InputMethodSystemAbility::CheckSwitchPermission(int32_t userId, const Sw } if (trigger == SwitchTrigger::CURRENT_IME) { // PERMISSION_CONNECT_IME_ABILITY check temporarily reserved for application adaptation, will be deleted soon - if (identityChecker_->HasPermission(IPCSkeleton::GetCallingTokenID(), - std::string(PERMISSION_CONNECT_IME_ABILITY))) { + if (identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) { return ErrorCode::NO_ERROR; } IMSA_HILOGE("have not PERMISSION_CONNECT_IME_ABILITY!"); // switchInfo.subName.empty() check temporarily reserved for application adaptation, will be deleted soon - auto currentBundleName = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId)->bundleName; - if (identityChecker_->IsBundleNameValid(IPCSkeleton::GetCallingTokenID(), currentBundleName)) { + if (IsCurrentIme(userId, tokenId)) { return ErrorCode::NO_ERROR; } IMSA_HILOGE("not current ime!"); @@ -2459,17 +2511,17 @@ uint64_t InputMethodSystemAbility::GetCallingDisplayId(sptr abili return identityChecker_->GetDisplayIdByPid(IPCSkeleton::GetCallingPid(), abilityToken); } -bool InputMethodSystemAbility::IsCurrentIme(int32_t userId) +bool InputMethodSystemAbility::IsCurrentIme(int32_t userId, uint32_t tokenId) { auto session = UserSessionManager::GetInstance().GetUserSession(userId); if (session == nullptr) { IMSA_HILOGE("%{public}d session is nullptr!", userId); return false; } - auto bundleName = FullImeInfoManager::GetInstance().Get(userId, IPCSkeleton::GetCallingTokenID()); + auto bundleName = FullImeInfoManager::GetInstance().Get(userId, tokenId); if (bundleName.empty()) { - IMSA_HILOGW("user:%{public}d tokenId:%{public}d not find.", userId, IPCSkeleton::GetCallingTokenID()); - bundleName = identityChecker_->GetBundleNameByToken(IPCSkeleton::GetCallingTokenID()); + IMSA_HILOGW("user:%{public}d tokenId:%{public}d not find.", userId, tokenId); + bundleName = identityChecker_->GetBundleNameByToken(tokenId); } auto imeData = session->GetImeData(ImeType::IME); return imeData != nullptr && bundleName == imeData->ime.first; diff --git a/test/unittest/cpp_test/common/src/tdd_util.cpp b/test/unittest/cpp_test/common/src/tdd_util.cpp index 4646f41786cb4adfaf4f17c405d9b2e3c8128ad8..a25ff1dda842a2177d35e7efe5eb1235426f02ba 100644 --- a/test/unittest/cpp_test/common/src/tdd_util.cpp +++ b/test/unittest/cpp_test/common/src/tdd_util.cpp @@ -138,10 +138,9 @@ uint64_t TddUtil::AllocTestTokenID( uint64_t TddUtil::GetTestTokenID(const std::string &bundleName) { - HapInfoParams infoParams = { .userID = GetUserIdByBundleName(bundleName, GetCurrentUserId()), - .bundleName = bundleName, - .instIndex = 0, - .appIDDesc = "ohos.inputmethod_test.demo" }; + HapInfoParams infoParams = { .userID = GetCurrentUserId(), .bundleName = bundleName, + .instIndex = 0, .appIDDesc = "ohos.inputmethod_test.demo" + }; return AccessTokenKit::GetHapTokenID(infoParams.userID, infoParams.bundleName, infoParams.instIndex); } diff --git a/test/unittest/cpp_test/src/identity_checker_test.cpp b/test/unittest/cpp_test/src/identity_checker_test.cpp index bee3587e192a9d6326d9d7a711706cadc6d305e3..295e50283613294b69ccddc339dd660025de9306 100644 --- a/test/unittest/cpp_test/src/identity_checker_test.cpp +++ b/test/unittest/cpp_test/src/identity_checker_test.cpp @@ -436,7 +436,7 @@ HWTEST_F(IdentityCheckerTest, testIsCurrentIme_001, TestSize.Level1) { IMSA_HILOGI("IdentityCheckerTest testIsCurrentIme_001 start"); service_->identityChecker_ = identityCheckerImpl_; - bool ret = IdentityCheckerTest::service_->IsCurrentIme(MAIN_USER_ID); + bool ret = IdentityCheckerTest::service_->IsCurrentIme(MAIN_USER_ID, 0); EXPECT_FALSE(ret); } @@ -451,7 +451,7 @@ HWTEST_F(IdentityCheckerTest, testIsCurrentIme_002, TestSize.Level1) { IMSA_HILOGI("IdentityCheckerTest testIsCurrentIme_002 start"); IdentityCheckerTest::IdentityCheckerMock::isBundleNameValid_ = true; - bool ret = IdentityCheckerTest::service_->IsCurrentIme(MAIN_USER_ID); + bool ret = IdentityCheckerTest::service_->IsCurrentIme(MAIN_USER_ID, 0); EXPECT_FALSE(ret); } @@ -689,28 +689,6 @@ HWTEST_F(IdentityCheckerTest, testSwitchInputMethod_001, TestSize.Level1) EXPECT_EQ(ret, ErrorCode::ERROR_STATUS_PERMISSION_DENIED); } -/** - * @tc.name: testSwitchInputMethod_002 - * @tc.desc: has no PERMISSION_CONNECT_IME_ABILITY, currentIme switch subtype - * @tc.type: FUNC - * @tc.require: - * @tc.author: - */ -HWTEST_F(IdentityCheckerTest, testSwitchInputMethod_002, TestSize.Level1) -{ - IMSA_HILOGI("IdentityCheckerTest testSwitchInputMethod_002 start"); - ImeEnabledCfg cfg; - ImeEnabledInfo enabledInfo{ CURRENT_BUNDLENAME, CURRENT_EXTNAME, EnabledStatus::BASIC_MODE }; - enabledInfo.extraInfo.isDefaultIme = true; - cfg.enabledInfos.push_back(enabledInfo); - ImeEnabledInfoManager::GetInstance().imeEnabledCfg_.insert_or_assign(MAIN_USER_ID, cfg); - IdentityCheckerTest::IdentityCheckerMock::hasPermission_ = false; - IdentityCheckerTest::IdentityCheckerMock::isBundleNameValid_ = true; - int32_t ret = IdentityCheckerTest::service_->SwitchInputMethod( - CURRENT_BUNDLENAME, CURRENT_SUBNAME, static_cast(SwitchTrigger::CURRENT_IME)); - EXPECT_EQ(ret, ErrorCode::ERROR_IMSA_GET_IME_INFO_FAILED); -} - /** * @tc.name: testSwitchInputMethod_003 * @tc.desc: has PERMISSION_CONNECT_IME_ABILITY, not currentIme switch subtype diff --git a/test/unittest/cpp_test/src/input_method_private_member_test.cpp b/test/unittest/cpp_test/src/input_method_private_member_test.cpp index 3f6251f081c1eefbf67a06097b8f4196951ae43f..a78ea4f90f4e73bba7fb48ede74fc3dea4fb1417 100644 --- a/test/unittest/cpp_test/src/input_method_private_member_test.cpp +++ b/test/unittest/cpp_test/src/input_method_private_member_test.cpp @@ -1394,7 +1394,7 @@ HWTEST_F(InputMethodPrivateMemberTest, BranchCoverage002, TestSize.Level0) bool needHide = false; InputType type = InputType::NONE; - auto ret3 = service_->IsCurrentIme(INVALID_USER_ID); + auto ret3 = service_->IsCurrentIme(INVALID_USER_ID, 0); service_->NeedHideWhenSwitchInputType(INVALID_USER_ID, type, needHide); EXPECT_FALSE(ret3); } @@ -2874,5 +2874,61 @@ HWTEST_F(InputMethodPrivateMemberTest, PerUserSession_RemoveImeData_002, TestSiz EXPECT_EQ(it, userSession->imeData_.end()); } +/** + * @tc.name: IMSA_IsTmpIme + * @tc.desc: IMSA_IsTmpIme + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(InputMethodPrivateMemberTest, IMSA_IsTmpIme, TestSize.Level0) +{ + IMSA_HILOGI("InputMethodPrivateMemberTest::IMSA_IsTmpIme start."); + InputMethodSystemAbility systemAbility; + UserSessionManager::GetInstance().userSessions_.clear(); + uint32_t tokenId = 345; + // not has MAIN_USER_ID userSession + auto ret = systemAbility.IsTmpIme(MAIN_USER_ID, tokenId); + EXPECT_FALSE(ret); + auto userSession = std::make_shared(MAIN_USER_ID); + UserSessionManager::GetInstance().userSessions_.insert_or_assign(MAIN_USER_ID, userSession); + ImeEnabledCfg cfg; + ImeEnabledInfo enabledInfo{ "", "extName1", EnabledStatus::BASIC_MODE }; + enabledInfo.extraInfo.isDefaultIme = true; + cfg.enabledInfos.push_back(enabledInfo); + ImeEnabledInfoManager::GetInstance().imeEnabledCfg_.insert_or_assign(MAIN_USER_ID, cfg); + // has no running ime + userSession->imeData_.clear(); + ret = systemAbility.IsTmpIme(MAIN_USER_ID, tokenId); + EXPECT_FALSE(ret); + auto imeData = std::make_shared(nullptr, nullptr, nullptr, 10); + std::string bundleName2 = "bundleName2"; + imeData->ime.first = bundleName2; + userSession->imeData_.insert_or_assign(ImeType::IME, std::vector>{ imeData }); + FullImeInfo info; + info.tokenId = tokenId; + info.prop.name = bundleName2; + FullImeInfoManager::GetInstance().fullImeInfos_.insert({ MAIN_USER_ID, { info } }); + // caller is same with running ime, but the bundleName of default ime is empty + ret = systemAbility.IsTmpIme(MAIN_USER_ID, tokenId); + EXPECT_FALSE(ret); + enabledInfo.bundleName = bundleName2; + cfg.enabledInfos.clear(); + cfg.enabledInfos.push_back(enabledInfo); + ImeEnabledInfoManager::GetInstance().imeEnabledCfg_.insert_or_assign(MAIN_USER_ID, cfg); + // caller is same with running ime, the bundleName of default ime is also same with + ret = systemAbility.IsTmpIme(MAIN_USER_ID, tokenId); + EXPECT_FALSE(ret); + enabledInfo.bundleName = "diffBundleName"; + cfg.enabledInfos.clear(); + cfg.enabledInfos.push_back(enabledInfo); + ImeEnabledInfoManager::GetInstance().imeEnabledCfg_.insert_or_assign(MAIN_USER_ID, cfg); + // caller is same with running ime, but the bundleName of default ime is not same with + ret = systemAbility.IsTmpIme(MAIN_USER_ID, tokenId); + EXPECT_TRUE(ret); + SwitchInfo switchInfo; + switchInfo.bundleName = bundleName2; + ret = systemAbility.IsTmpImeSwitchSubtype(MAIN_USER_ID, tokenId, switchInfo); + EXPECT_TRUE(ret); +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/test/unittest/cpp_test/src/newIme_switch_test.cpp b/test/unittest/cpp_test/src/newIme_switch_test.cpp index def7443a3b4d4fdede61520880c832e9bf4b7564..daac1e3c110ab3369900fc4f1a7bf98b3dacef44 100644 --- a/test/unittest/cpp_test/src/newIme_switch_test.cpp +++ b/test/unittest/cpp_test/src/newIme_switch_test.cpp @@ -64,6 +64,7 @@ void NewImeSwitchTest::SetUpTestCase(void) imc_ = InputMethodController::GetInstance(); auto listener = std::make_shared(); ImeEventMonitorManagerImpl::GetInstance().RegisterImeEventListener(EVENT_IME_CHANGE_MASK, listener); + TddUtil::InitWindow(false); } void NewImeSwitchTest::TearDownTestCase(void) @@ -71,6 +72,7 @@ void NewImeSwitchTest::TearDownTestCase(void) IMSA_HILOGI("NewImeSwitchTest::TearDownTestCase"); TddUtil::GrantNativePermission(); InputMethodController::GetInstance()->Close(); + TddUtil::DestroyWindow(); TddUtil::RestoreSelfTokenID(); } @@ -249,7 +251,7 @@ HWTEST_F(NewImeSwitchTest, testSubTypeSwitchWithErrorSubName, TestSize.Level0) /** * @tc.name: testSwitchToCurrentImeWithEmptySubName - * @tc.desc: switch to currentIme witch empty subName. + * @tc.desc: switch to currentIme with empty subName. * @tc.type: FUNC * @tc.require: * @tc.author: chenyu diff --git a/test/unittest/resource/ohos_test/ohos_test.xml b/test/unittest/resource/ohos_test/ohos_test.xml index 92a36907fcb5605446cc01d32757b975dbdcd883..168270627bc87424e928a2f9130deeffa394207e 100644 --- a/test/unittest/resource/ohos_test/ohos_test.xml +++ b/test/unittest/resource/ohos_test/ohos_test.xml @@ -46,6 +46,8 @@