From 1df49102c14d470902ef3a01ef1618d64017007a Mon Sep 17 00:00:00 2001 From: zhaolinglan Date: Wed, 14 May 2025 14:58:10 +0800 Subject: [PATCH] add auto numKey input Signed-off-by: zhaolinglan --- common/src/itypes_util.cpp | 5 +- .../js_keyboard_delegate_setting.cpp | 11 +- .../js_keyboard_delegate_setting.h | 2 +- .../include/input_method_ability.h | 1 + .../src/input_method_ability.cpp | 41 ++++ .../IInputDataChannel.idl | 1 + .../include/input_attribute.h | 8 +- .../include/input_data_channel_service_impl.h | 1 + .../src/input_data_channel_service_impl.cpp | 10 + .../adapter/settings_data_provider/BUILD.gn | 1 + .../common/include/settings_data_observer.h | 5 +- .../common/include/settings_data_utils.h | 8 +- .../common/src/settings_data_observer.cpp | 5 + .../common/src/settings_data_utils.cpp | 48 ++-- .../include/numkey_apps_manager.h | 104 +++++++++ .../src/numkey_apps_manager.cpp | 218 ++++++++++++++++++ services/include/ime_info_inquirer.h | 1 + services/include/peruser_session.h | 1 + services/include/sys_cfg_parser.h | 2 + services/json/include/serializable.h | 18 ++ services/src/ime_info_inquirer.cpp | 5 + services/src/input_method_system_ability.cpp | 6 + services/src/peruser_session.cpp | 5 + 23 files changed, 481 insertions(+), 26 deletions(-) create mode 100644 services/adapter/settings_data_provider/include/numkey_apps_manager.h create mode 100644 services/adapter/settings_data_provider/src/numkey_apps_manager.cpp diff --git a/common/src/itypes_util.cpp b/common/src/itypes_util.cpp index 83102c605..10576eda4 100644 --- a/common/src/itypes_util.cpp +++ b/common/src/itypes_util.cpp @@ -187,7 +187,7 @@ bool ITypesUtil::Unmarshalling(SubProperty &output, MessageParcel &data) bool ITypesUtil::Marshalling(const InputAttribute &input, MessageParcel &data) { if (!Marshal(data, input.inputPattern, input.enterKeyType, input.inputOption, input.isTextPreviewSupported, - input.bundleName, input.immersiveMode, input.windowId, input.callingDisplayId)) { + input.bundleName, input.immersiveMode, input.windowId, input.callingDisplayId, input.needAutoInputNumkey)) { IMSA_HILOGE("write InputAttribute to message parcel failed."); return false; } @@ -197,7 +197,8 @@ bool ITypesUtil::Marshalling(const InputAttribute &input, MessageParcel &data) bool ITypesUtil::Unmarshalling(InputAttribute &output, MessageParcel &data) { if (!Unmarshal(data, output.inputPattern, output.enterKeyType, output.inputOption, output.isTextPreviewSupported, - output.bundleName, output.immersiveMode, output.windowId, output.callingDisplayId)) { + output.bundleName, output.immersiveMode, output.windowId, output.callingDisplayId, + output.needAutoInputNumkey)) { IMSA_HILOGE("read InputAttribute from message parcel failed."); return false; } diff --git a/frameworks/js/napi/inputmethodability/js_keyboard_delegate_setting.cpp b/frameworks/js/napi/inputmethodability/js_keyboard_delegate_setting.cpp index 990f8a5ae..b00aaf983 100644 --- a/frameworks/js/napi/inputmethodability/js_keyboard_delegate_setting.cpp +++ b/frameworks/js/napi/inputmethodability/js_keyboard_delegate_setting.cpp @@ -303,7 +303,7 @@ bool JsKeyboardDelegateSetting::OnDealKeyEvent(const std::shared_ptrGetKeyCode(), keyEvent->GetKeyAction(), false }; std::string type = (keyEvent->GetKeyAction() == ARGC_TWO ? "keyDown" : "keyUp"); auto keyCodeEntry = GetEntry(type, [¶](UvEntry &entry) { @@ -332,7 +332,7 @@ void JsKeyboardDelegateSetting::DealKeyEvent(const std::shared_ptr &key napi_value keyEventObject{}; auto result = napi_create_object(env, &keyEventObject); CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create object", false); - result = MMI::KeyEventNapi::CreateKeyEvent(env, keyEventEntry->pullKeyEventPara, keyEventObject); + result = MMI::KeyEventNapi::CreateKeyEvent(env, keyEventEntry->fullKeyEventPara, keyEventObject); CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create key event object", false); // 0 means the first param of callback. args[0] = keyEventObject; @@ -362,10 +362,11 @@ void JsKeyboardDelegateSetting::DealKeyEvent(const std::shared_ptr &key } bool consumeResult = isKeyEventConsumed || isKeyCodeConsumed; if (consumer != nullptr) { - consumer->OnKeyEventResult(consumeResult); if (!consumeResult) { IMSA_HILOGW("ime is not consumed, result: %{public}d.", consumeResult); + InputMethodAbility::GetInstance().HandleUnconsumedKey(keyEventEntry->fullKeyEventPara); } + consumer->OnKeyEventResult(consumeResult); } } @@ -374,7 +375,7 @@ bool JsKeyboardDelegateSetting::OnKeyEvent(const std::shared_ptr { std::string type = "keyEvent"; auto entry = GetEntry(type, [keyEvent, &consumer](UvEntry &entry) { - entry.pullKeyEventPara = keyEvent; + entry.fullKeyEventPara = keyEvent; entry.keyEvenetConsumer = consumer; }); if (entry == nullptr) { @@ -397,7 +398,7 @@ bool JsKeyboardDelegateSetting::OnKeyEvent(const std::shared_ptr napi_value keyEventObject{}; auto result = napi_create_object(env, &keyEventObject); CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create object", false); - result = MMI::KeyEventNapi::CreateKeyEvent(env, entry->pullKeyEventPara, keyEventObject); + result = MMI::KeyEventNapi::CreateKeyEvent(env, entry->fullKeyEventPara, keyEventObject); CHECK_RETURN((result == napi_ok) && (keyEventObject != nullptr), "create key event object", false); // 0 means the first param of callback. args[0] = keyEventObject; diff --git a/frameworks/js/napi/inputmethodability/js_keyboard_delegate_setting.h b/frameworks/js/napi/inputmethodability/js_keyboard_delegate_setting.h index a29db4283..95b808c59 100644 --- a/frameworks/js/napi/inputmethodability/js_keyboard_delegate_setting.h +++ b/frameworks/js/napi/inputmethodability/js_keyboard_delegate_setting.h @@ -84,7 +84,7 @@ private: CursorPara curPara; SelectionPara selPara; KeyEventPara keyEventPara; - std::shared_ptr pullKeyEventPara; + std::shared_ptr fullKeyEventPara; std::string text; sptr keyEvenetConsumer = nullptr; InputAttribute inputAttribute; diff --git a/frameworks/native/inputmethod_ability/include/input_method_ability.h b/frameworks/native/inputmethod_ability/include/input_method_ability.h index 6fffe233d..4fe1904a0 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_ability.h +++ b/frameworks/native/inputmethod_ability/include/input_method_ability.h @@ -106,6 +106,7 @@ public: int32_t RegisterMsgHandler(const std::shared_ptr &msgHandler = nullptr); int32_t OnCallingDisplayIdChanged(uint64_t displayId); int32_t OnSendPrivateData(const std::unordered_map &privateCommand); + bool HandleUnconsumedKey(const std::shared_ptr &keyEvent); public: /* called from TaskManager worker thread */ diff --git a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp index 014a1b8bf..595696f45 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp @@ -1739,5 +1739,46 @@ int32_t InputMethodAbility::OnSendPrivateData(const std::unordered_map &keyEvent) +{ + if (keyEvent == nullptr) { + IMSA_HILOGE("keyEvent nullptr"); + return false; + } + auto channel = GetInputDataChannelProxy(); + if (channel == nullptr) { + IMSA_HILOGD("channel is nullptr!"); + return false; + } + if (!GetInputAttribute().needAutoInputNumkey) { + IMSA_HILOGD("no need"); + return false; + } + if (keyEvent->GetKeyAction() != MMI::KeyEvent::KEY_ACTION_DOWN) { + IMSA_HILOGD("not down key"); + return false; + } + if (keyEvent->GetPressedKeys().size() > 1) { + IMSA_HILOGD("only handle single key"); + return false; + } + int32_t keyCode = keyEvent->GetKeyCode(); + std::string inputNumber; + if (MMI::KeyEvent::KEYCODE_0 <= keyCode && keyCode <= MMI::KeyEvent::KEYCODE_9) { + IMSA_HILOGD("auto input a number"); + channel->InsertTextAsync(std::to_string(keyCode - MMI::KeyEvent::KEYCODE_0)); + return true; + } + if (!keyEvent->GetFunctionKey(MMI::KeyEvent::NUM_LOCK_FUNCTION_KEY)) { + return false; + } + if (MMI::KeyEvent::KEYCODE_NUMPAD_0 <= keyCode && keyCode <= MMI::KeyEvent::KEYCODE_NUMPAD_9) { + IMSA_HILOGD("auto input a number"); + channel->InsertTextAsync(std::to_string(keyCode - MMI::KeyEvent::KEYCODE_NUMPAD_0)); + return true; + } + return false; +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/IInputDataChannel.idl b/frameworks/native/inputmethod_controller/IInputDataChannel.idl index b798d6359..d810d6f36 100644 --- a/frameworks/native/inputmethod_controller/IInputDataChannel.idl +++ b/frameworks/native/inputmethod_controller/IInputDataChannel.idl @@ -22,6 +22,7 @@ sequenceable input_method_utils..OHOS.MiscServices.RangeInner; sequenceable input_method_utils..OHOS.MiscServices.ArrayBuffer; interface OHOS.MiscServices.IInputDataChannel { [ipccode 0] void InsertText([in] String text); + [oneway] void InsertTextAsync([in] String text); void DeleteForward([in] int length); void DeleteBackward([in] int length); void GetTextBeforeCursor([in] int number, [out] String text); diff --git a/frameworks/native/inputmethod_controller/include/input_attribute.h b/frameworks/native/inputmethod_controller/include/input_attribute.h index 6d0242dcd..f39da5a85 100644 --- a/frameworks/native/inputmethod_controller/include/input_attribute.h +++ b/frameworks/native/inputmethod_controller/include/input_attribute.h @@ -38,6 +38,7 @@ struct InputAttribute { int32_t immersiveMode = 0; uint32_t windowId = 0; // for transfer uint64_t callingDisplayId = 0; + bool needAutoInputNumkey { false }; // number keys need to be automatically handled by imf bool GetSecurityFlag() const { @@ -58,7 +59,7 @@ struct InputAttribute { << "enterKeyType:" << enterKeyType << "inputOption:" << inputOption << "isTextPreviewSupported:" << isTextPreviewSupported << "bundleName:" << bundleName << "immersiveMode:" << immersiveMode << "windowId:" << windowId - << "callingDisplayId:" << callingDisplayId << "]"; + << "callingDisplayId:" << callingDisplayId << "needNumInput: " << needAutoInputNumkey << "]"; return ss.str(); } }; @@ -77,6 +78,7 @@ struct InputAttributeInner : public Parcelable { int32_t immersiveMode = 0; uint32_t windowId = 0; // for transfer uint64_t callingDisplayId = 0; + bool needAutoInputNumkey { false }; // number keys need to be automatically handled by imf bool ReadFromParcel(Parcel &in) { @@ -88,6 +90,7 @@ struct InputAttributeInner : public Parcelable { immersiveMode = in.ReadInt32(); windowId = in.ReadUint32(); callingDisplayId = in.ReadUint64(); + needAutoInputNumkey = in.ReadBool(); return true; } @@ -117,6 +120,9 @@ struct InputAttributeInner : public Parcelable { if (!out.WriteUint64(callingDisplayId)) { return false; } + if (!out.WriteBool(needAutoInputNumkey)) { + return false; + } return true; } diff --git a/frameworks/native/inputmethod_controller/include/input_data_channel_service_impl.h b/frameworks/native/inputmethod_controller/include/input_data_channel_service_impl.h index 66ca83644..092295628 100644 --- a/frameworks/native/inputmethod_controller/include/input_data_channel_service_impl.h +++ b/frameworks/native/inputmethod_controller/include/input_data_channel_service_impl.h @@ -34,6 +34,7 @@ public: ~InputDataChannelServiceImpl(); ErrCode InsertText(const std::string &text) override; + ErrCode InsertTextAsync(const std::string &text) override; ErrCode DeleteForward(int32_t length) override; ErrCode DeleteBackward(int32_t length) override; ErrCode GetTextBeforeCursor(int32_t number, std::string &text) override; diff --git a/frameworks/native/inputmethod_controller/src/input_data_channel_service_impl.cpp b/frameworks/native/inputmethod_controller/src/input_data_channel_service_impl.cpp index 3f4830b1b..a5744e753 100644 --- a/frameworks/native/inputmethod_controller/src/input_data_channel_service_impl.cpp +++ b/frameworks/native/inputmethod_controller/src/input_data_channel_service_impl.cpp @@ -39,6 +39,16 @@ ErrCode InputDataChannelServiceImpl::InsertText(const std::string &text) return instance->InsertText(Str8ToStr16(text)); } +ErrCode InputDataChannelServiceImpl::InsertTextAsync(const std::string &text) +{ + auto instance = InputMethodController::GetInstance(); + if (instance == nullptr) { + IMSA_HILOGE("failed to get InputMethodController instance!"); + return ErrorCode::ERROR_EX_NULL_POINTER; + } + return instance->InsertText(Str8ToStr16(text)); +} + ErrCode InputDataChannelServiceImpl::DeleteForward(int32_t length) { auto instance = InputMethodController::GetInstance(); diff --git a/services/adapter/settings_data_provider/BUILD.gn b/services/adapter/settings_data_provider/BUILD.gn index e4bf3920c..ae00c0c31 100644 --- a/services/adapter/settings_data_provider/BUILD.gn +++ b/services/adapter/settings_data_provider/BUILD.gn @@ -37,6 +37,7 @@ ohos_static_library("settings_data_static") { "common/src/settings_data_observer.cpp", "common/src/settings_data_utils.cpp", "src/enable_ime_data_parser.cpp", + "src/numkey_apps_manager.cpp", "src/security_mode_parser.cpp", ] diff --git a/services/adapter/settings_data_provider/common/include/settings_data_observer.h b/services/adapter/settings_data_provider/common/include/settings_data_observer.h index f51ea06bb..1b839f1c0 100644 --- a/services/adapter/settings_data_provider/common/include/settings_data_observer.h +++ b/services/adapter/settings_data_provider/common/include/settings_data_observer.h @@ -25,12 +25,15 @@ namespace MiscServices { class SettingsDataObserver : public AAFwk::DataAbilityObserverStub { public: using CallbackFunc = std::function; - SettingsDataObserver(const std::string &key, CallbackFunc &func) : key_(key), func_(func){}; + SettingsDataObserver(const std::string &uriProxy, const std::string &key, const CallbackFunc &func) + : uriProxy_(uriProxy), key_(key), func_(func){}; ~SettingsDataObserver() = default; void OnChange() override; + const std::string &GetUriProxy(); const std::string &GetKey(); private: + std::string uriProxy_; std::string key_; CallbackFunc func_ = nullptr; }; diff --git a/services/adapter/settings_data_provider/common/include/settings_data_utils.h b/services/adapter/settings_data_provider/common/include/settings_data_utils.h index 602cae5ba..dc7402129 100644 --- a/services/adapter/settings_data_provider/common/include/settings_data_utils.h +++ b/services/adapter/settings_data_provider/common/include/settings_data_utils.h @@ -16,6 +16,8 @@ #ifndef SETTINGS_DATA_UTILS_H #define SETTINGS_DATA_UTILS_H +#include + #include "datashare_helper.h" #include "input_method_property.h" #include "serializable.h" @@ -50,6 +52,9 @@ public: static sptr GetInstance(); std::shared_ptr CreateDataShareHelper(const std::string &uriProxy); int32_t CreateAndRegisterObserver(const std::string &key, SettingsDataObserver::CallbackFunc func); + int32_t RegisterObserver(const std::string &uriProxy, const std::string &key, + const SettingsDataObserver::CallbackFunc &func, sptr &observer); + int32_t UnregisterObserver(const sptr &observer); int32_t GetStringValue(const std::string &uriProxy, const std::string &key, std::string &value); bool SetStringValue(const std::string &uriProxy, const std::string &key, const std::string &value); bool ReleaseDataShareHelper(std::shared_ptr &helper); @@ -60,7 +65,6 @@ private: SettingsDataUtils() = default; ~SettingsDataUtils(); int32_t RegisterObserver(const sptr &observer); - int32_t UnregisterObserver(const sptr &observer); sptr GetToken(); std::vector Split(const std::string &text, char separator); std::string SetSettingValues(const std::string &settingValue, const std::string &bundleName); @@ -71,7 +75,7 @@ private: std::mutex remoteObjMutex_; sptr remoteObj_ = nullptr; std::mutex observerListMutex_; - std::vector> observerList_; + std::list> observerList_; }; } // namespace MiscServices } // namespace OHOS diff --git a/services/adapter/settings_data_provider/common/src/settings_data_observer.cpp b/services/adapter/settings_data_provider/common/src/settings_data_observer.cpp index 94395818a..aa9b82128 100644 --- a/services/adapter/settings_data_provider/common/src/settings_data_observer.cpp +++ b/services/adapter/settings_data_provider/common/src/settings_data_observer.cpp @@ -24,6 +24,11 @@ void SettingsDataObserver::OnChange() } } +const std::string &SettingsDataObserver::GetUriProxy() +{ + return key_; +} + const std::string &SettingsDataObserver::GetKey() { return key_; diff --git a/services/adapter/settings_data_provider/common/src/settings_data_utils.cpp b/services/adapter/settings_data_provider/common/src/settings_data_utils.cpp index 26a9308e3..5a4a9b366 100644 --- a/services/adapter/settings_data_provider/common/src/settings_data_utils.cpp +++ b/services/adapter/settings_data_provider/common/src/settings_data_utils.cpp @@ -57,7 +57,8 @@ sptr SettingsDataUtils::GetInstance() int32_t SettingsDataUtils::CreateAndRegisterObserver(const std::string &key, SettingsDataObserver::CallbackFunc func) { IMSA_HILOGD("key: %{public}s.", key.c_str()); - sptr observer = new (std::nothrow) SettingsDataObserver(key, func); + sptr observer = new (std::nothrow) + SettingsDataObserver(std::string(SETTING_URI_PROXY), key, func); if (observer == nullptr) { IMSA_HILOGE("observer is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; @@ -65,38 +66,57 @@ int32_t SettingsDataUtils::CreateAndRegisterObserver(const std::string &key, Set return RegisterObserver(observer); } -int32_t SettingsDataUtils::RegisterObserver(const sptr &observer) +int32_t SettingsDataUtils::RegisterObserver(const std::string &uriProxy, const std::string &key, + const SettingsDataObserver::CallbackFunc &func, sptr &observer) { + observer = new (std::nothrow) SettingsDataObserver(uriProxy, key, func); if (observer == nullptr) { IMSA_HILOGE("observer is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } + return RegisterObserver(observer); +} - auto uri = GenerateTargetUri(std::string(SETTING_URI_PROXY), observer->GetKey()); - auto helper = SettingsDataUtils::CreateDataShareHelper(std::string(SETTING_URI_PROXY)); +int32_t SettingsDataUtils::UnregisterObserver(const sptr &observer) +{ + if (observer == nullptr) { + IMSA_HILOGE("observer is nullptr!"); + return ErrorCode::ERROR_NULL_POINTER; + } + auto uri = GenerateTargetUri(observer->GetUriProxy(), observer->GetKey()); + auto helper = SettingsDataUtils::CreateDataShareHelper(observer->GetUriProxy()); if (helper == nullptr) { IMSA_HILOGE("helper is nullptr!"); - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_IMSA_NULLPTR; } - helper->RegisterObserver(uri, observer); + helper->UnregisterObserver(uri, observer); ReleaseDataShareHelper(helper); - IMSA_HILOGD("succeed to register observer of uri: %{public}s.", uri.ToString().c_str()); + IMSA_HILOGD("succeed to unregister observer of uri: %{public}s.", uri.ToString().c_str()); std::lock_guard lock(observerListMutex_); - observerList_.push_back(observer); + observerList_.remove(observer); return ErrorCode::NO_ERROR; } -int32_t SettingsDataUtils::UnregisterObserver(const sptr &observer) +int32_t SettingsDataUtils::RegisterObserver(const sptr &observer) { - auto uri = GenerateTargetUri(std::string(SETTING_URI_PROXY), observer->GetKey()); - auto helper = SettingsDataUtils::CreateDataShareHelper(std::string(SETTING_URI_PROXY)); + if (observer == nullptr) { + IMSA_HILOGE("observer is nullptr!"); + return ErrorCode::ERROR_NULL_POINTER; + } + + auto uri = GenerateTargetUri(observer->GetUriProxy(), observer->GetKey()); + auto helper = SettingsDataUtils::CreateDataShareHelper(observer->GetUriProxy()); if (helper == nullptr) { - return ErrorCode::ERROR_ENABLE_IME; + IMSA_HILOGE("helper is nullptr!"); + return ErrorCode::ERROR_NULL_POINTER; } - helper->UnregisterObserver(uri, observer); + helper->RegisterObserver(uri, observer); ReleaseDataShareHelper(helper); - IMSA_HILOGD("succeed to unregister observer of uri: %{public}s.", uri.ToString().c_str()); + IMSA_HILOGD("succeed to register observer of uri: %{public}s.", uri.ToString().c_str()); + + std::lock_guard lock(observerListMutex_); + observerList_.push_back(observer); return ErrorCode::NO_ERROR; } diff --git a/services/adapter/settings_data_provider/include/numkey_apps_manager.h b/services/adapter/settings_data_provider/include/numkey_apps_manager.h new file mode 100644 index 000000000..eece630a4 --- /dev/null +++ b/services/adapter/settings_data_provider/include/numkey_apps_manager.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INPUTMETHOD_IMF_AUTO_NUMBER_INPUT_APPS_MANAGER_H +#define INPUTMETHOD_IMF_AUTO_NUMBER_INPUT_APPS_MANAGER_H + +#include "settings_data_utils.h" + +namespace OHOS { +namespace MiscServices { +static constexpr int32_t BLOCK_MODE = 8; +struct NumkeyAPP : public Serializable { + std::string name; + bool numKey{ false }; + bool Unmarshal(cJSON *node) override + { + GetValue(node, GET_NAME(name), name); + GetValue(node, GET_NAME(numKey), numKey); + return true; + } +}; + +struct NumkeyAppListCfg : public Serializable { + std::vector numkeyApps; + bool Unmarshal(cJSON *node) override + { + std::function func = [](const NumkeyAPP &app) { return app.numKey; }; + GetValues(node, numkeyApps, func); + return true; + } +}; + +struct UserBlockApp : public Serializable { + std::string name; + int32_t mode; + bool Unmarshal(cJSON *node) override + { + GetValue(node, GET_NAME(name), name); + GetValue(node, GET_NAME(mode), mode); + return true; + } +}; + +struct UserBlockListCfg : public Serializable { + std::vector blockApps; + bool Unmarshal(cJSON *node) override + { + std::function func = [](const UserBlockApp &app) { return app.mode == BLOCK_MODE; }; + GetValues(node, blockApps, func); + return true; + } +}; + +class NumkeyAppsManager { +public: + static NumkeyAppsManager &GetInstance(); + int32_t Init(int32_t userId); + bool NeedAutoNumKeyInput(int32_t userId, const std::string &bundleName); + int32_t OnUserSwitched(int32_t userId); + int32_t OnUserRemoved(int32_t userId); + int32_t RegisterUserBlockListData(int32_t userId); + static constexpr const char *COMPATIBLE_SETTING_STRATEGY = "COMPATIBLE_SETTING_STRATEGY"; + static constexpr const char *COMPATIBLE_APP_STRATEGY = "COMPATIBLE_APP_STRATEGY"; + +private: + NumkeyAppsManager() = default; + ~NumkeyAppsManager() = default; + NumkeyAppsManager(const NumkeyAppsManager &) = delete; + NumkeyAppsManager(NumkeyAppsManager &&) = delete; + NumkeyAppsManager &operator=(const NumkeyAppsManager &) = delete; + NumkeyAppsManager &operator=(NumkeyAppsManager &&) = delete; + + int32_t InitWhiteList(int32_t userId); + int32_t UpdateUserBlockList(int32_t userId); + static int32_t ParseWhiteList(int32_t userId, std::unordered_set &list); + static int32_t ParseBlockList(int32_t userId, std::unordered_set &list); + + bool isFeatureEnabled_{ false }; + + std::atomic isListInited_{ false }; + std::mutex appListLock_; + std::unordered_set numKeyAppList_; + + std::mutex blockListLock_; + std::map> usersBlockList_; + std::mutex observersLock_; + std::map> observers_; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // INPUTMETHOD_IMF_AUTO_NUMBER_INPUT_APPS_MANAGER_H diff --git a/services/adapter/settings_data_provider/src/numkey_apps_manager.cpp b/services/adapter/settings_data_provider/src/numkey_apps_manager.cpp new file mode 100644 index 000000000..8ad9b623f --- /dev/null +++ b/services/adapter/settings_data_provider/src/numkey_apps_manager.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "numkey_apps_manager.h" + +#include "global.h" +#include "ime_info_inquirer.h" + +namespace OHOS { +namespace MiscServices { +#define CHECK_FEATURE_ENABLE() \ + do { \ + if (!isFeatureEnabled_) { \ + IMSA_HILOGD("feature not enabled"); \ + return ErrorCode::NO_ERROR; \ + } \ + } while (0) + +NumkeyAppsManager &NumkeyAppsManager::GetInstance() +{ + static NumkeyAppsManager numkeyAppsManager; + return numkeyAppsManager; +} + +int32_t NumkeyAppsManager::Init(int32_t userId) +{ + IMSA_HILOGI("start, userId: %{public}d", userId); + isFeatureEnabled_ = ImeInfoInquirer::GetInstance().IsEnableNumKey(); + CHECK_FEATURE_ENABLE(); + + int32_t ret = InitWhiteList(userId); + IMSA_HILOGE("InitWhiteList ret: %{public}d", ret); + + ret = RegisterUserBlockListData(userId); + IMSA_HILOGI("RegisterUserBlockListData ret: %{public}d", ret); + + ret = UpdateUserBlockList(userId); + IMSA_HILOGI("UpdateUserBlockList ret: %{public}d", ret); + return ret; +} + +bool NumkeyAppsManager::NeedAutoNumKeyInput(int32_t userId, const std::string &bundleName) +{ + if (!isFeatureEnabled_) { + IMSA_HILOGD("feature not enabled"); + return false; + } + { + std::lock_guard lock(appListLock_); + if (numKeyAppList_.find(bundleName) == numKeyAppList_.end()) { + IMSA_HILOGD("not in white list %{public}s", bundleName.c_str()); + return false; + } + } + std::lock_guard lock(blockListLock_); + if (usersBlockList_.find(userId) == usersBlockList_.end()) { + IMSA_HILOGD("user %{public}d block list is empty", userId); + return true; + } + auto blockList = usersBlockList_[userId]; + bool needAutoInput = blockList.find(bundleName) == blockList.end(); + IMSA_HILOGD("bundleName: %{public}s, needAutoInput: %{public}d", bundleName.c_str(), needAutoInput); + return needAutoInput; +} + +int32_t NumkeyAppsManager::OnUserSwitched(int32_t userId) +{ + CHECK_FEATURE_ENABLE(); + IMSA_HILOGI("userId %{public}d", userId); + { + std::lock_guard lock(blockListLock_); + if (usersBlockList_.find(userId) != usersBlockList_.end()) { + IMSA_HILOGI("block list already set"); + return ErrorCode::NO_ERROR; + } + } + RegisterUserBlockListData(userId); + int32_t ret = UpdateUserBlockList(userId); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("UpdateUserBlockList failed, ret: {public}d", ret); + return ret; + } + return ErrorCode::NO_ERROR; +} + +int32_t NumkeyAppsManager::OnUserRemoved(int32_t userId) +{ + CHECK_FEATURE_ENABLE(); + IMSA_HILOGI("userId %{public}d", userId); + sptr observer = nullptr; + { + std::lock_guard lock(observersLock_); + auto iter = observers_.find(userId); + if (iter == observers_.end()) { + IMSA_HILOGD("observer not found"); + return ErrorCode::NO_ERROR; + } + observer = iter->second; + } + int32_t ret = SettingsDataUtils::GetInstance()->UnregisterObserver(observer); + { + std::lock_guard lock(observersLock_); + observers_.erase(userId); + } + return ret; +} + +int32_t NumkeyAppsManager::InitWhiteList(int32_t userId) +{ + if (isListInited_.load()) { + return ErrorCode::NO_ERROR; + } + std::unordered_set whiteList; + int32_t ret = ParseWhiteList(userId, whiteList); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGI("ParseWhiteList failed, ret: %{public}d", ret); + return ret; + } + std::lock_guard lock(appListLock_); + numKeyAppList_ = whiteList; + IMSA_HILOGI("success, list size: %{public}lu", numKeyAppList_.size()); + return ErrorCode::NO_ERROR; +} + +int32_t NumkeyAppsManager::UpdateUserBlockList(int32_t userId) +{ + std::unordered_set blockList; + int32_t ret = ParseBlockList(userId, blockList); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("ParseBlockList failed, ret: %{public}d", ret); + return ret; + } + std::lock_guard lock(blockListLock_); + usersBlockList_[userId] = blockList; + return ErrorCode::NO_ERROR; +} + +int32_t NumkeyAppsManager::ParseWhiteList(int32_t userId, std::unordered_set &list) +{ + std::string valueStr; + int32_t ret = + SettingsDataUtils::GetInstance()->GetStringValue(SETTING_URI_PROXY, COMPATIBLE_APP_STRATEGY, valueStr); + if (ret != ErrorCode::NO_ERROR && ret != ErrorCode::ERROR_KEYWORD_NOT_FOUND) { + IMSA_HILOGE("failed to get white list from settings data, ret: %{public}d", ret); + return ret; + } + if (ret == ErrorCode::ERROR_KEYWORD_NOT_FOUND) { + IMSA_HILOGD("key not found"); + return ErrorCode::NO_ERROR; + } + NumkeyAppListCfg whiteListCfg; + if (!whiteListCfg.Unmarshall(valueStr)) { + IMSA_HILOGE("unmarshall failed"); + return ErrorCode::ERROR_PARSE_CONFIG_FILE; + } + for (const auto &app : whiteListCfg.numkeyApps) { + list.insert(app.name); + } + return ErrorCode::NO_ERROR; +} + +int32_t NumkeyAppsManager::ParseBlockList(int32_t userId, std::unordered_set &list) +{ + std::string valueStr; + int32_t ret = SettingsDataUtils::GetInstance()->GetStringValue( + SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true", COMPATIBLE_SETTING_STRATEGY, valueStr); + if (ret != ErrorCode::NO_ERROR && ret != ErrorCode::ERROR_KEYWORD_NOT_FOUND) { + IMSA_HILOGE("failed to get white list from settings data, ret: %{public}d", ret); + return ret; + } + if (ret == ErrorCode::ERROR_KEYWORD_NOT_FOUND) { + IMSA_HILOGD("key not found"); + return ErrorCode::NO_ERROR; + } + UserBlockListCfg blockListCfg; + if (!blockListCfg.Unmarshall(valueStr)) { + IMSA_HILOGE("unmarshall failed"); + return ErrorCode::ERROR_PARSE_CONFIG_FILE; + } + for (const auto &app : blockListCfg.blockApps) { + list.insert(app.name); + } + return ErrorCode::NO_ERROR; +} + +int32_t NumkeyAppsManager::RegisterUserBlockListData(int32_t userId) +{ + auto func = [this, userId]() { + IMSA_HILOGI("on block list change, userId: %{public}d", userId); + UpdateUserBlockList(userId); + }; + std::string uriProxy = SETTINGS_USER_DATA_URI + std::to_string(userId) + "?Proxy=true"; + sptr observer = nullptr; + int32_t ret = + SettingsDataUtils::GetInstance()->RegisterObserver(uriProxy, COMPATIBLE_SETTING_STRATEGY, func, observer); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("RegisterObserver failed, ret: %{public}d", ret); + return ret; + } + IMSA_HILOGI("end, userId: %{public}d ", userId); + std::lock_guard lock(observersLock_); + observers_[userId] = observer; + return ErrorCode::NO_ERROR; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/services/include/ime_info_inquirer.h b/services/include/ime_info_inquirer.h index 2c8e0aa76..57f5a465b 100644 --- a/services/include/ime_info_inquirer.h +++ b/services/include/ime_info_inquirer.h @@ -88,6 +88,7 @@ public: bool IsEnableInputMethod(); bool IsEnableSecurityMode(); bool IsEnableAppAgent(); + bool IsEnableNumKey(); bool IsVirtualProxyIme(int32_t callingUid); bool IsSpecialSaUid(int32_t callingUid); EnabledStatus GetSystemInitEnabledState(); diff --git a/services/include/peruser_session.h b/services/include/peruser_session.h index c7de5b2fd..d380b7d52 100644 --- a/services/include/peruser_session.h +++ b/services/include/peruser_session.h @@ -149,6 +149,7 @@ public: int32_t SpecialSendPrivateData(const std::unordered_map &privateCommand); uint64_t GetDisplayGroupId(uint64_t displayId); bool IsDefaultDisplayGroup(uint64_t displayId); + bool IsNumkeyAutoInputApp(const std::string &bundleName); private: struct ResetManager { diff --git a/services/include/sys_cfg_parser.h b/services/include/sys_cfg_parser.h index 96b84fb04..2ed8e9b2c 100644 --- a/services/include/sys_cfg_parser.h +++ b/services/include/sys_cfg_parser.h @@ -28,6 +28,7 @@ struct SystemConfig : public Serializable { bool enableFullExperienceFeature = false; EnabledStatus initEnabledState{ EnabledStatus::DISABLED }; bool enableAppAgentFeature = false; + bool enableNumKeyFeature = false; std::unordered_set proxyImeUidList; std::unordered_set specialSaUidList; std::unordered_set defaultImeScreenList; @@ -41,6 +42,7 @@ struct SystemConfig : public Serializable { GetValue(node, GET_NAME(initEnabledState), enableState); initEnabledState = static_cast(enableState); GetValue(node, GET_NAME(enableAppAgentFeature), enableAppAgentFeature); + GetValue(node, GET_NAME(enableNumKeyFeature), enableNumKeyFeature); GetValue(node, GET_NAME(proxyImeUidList), proxyImeUidList); GetValue(node, GET_NAME(specialSaUidList), specialSaUidList); GetValue(node, GET_NAME(defaultImeScreenList), defaultImeScreenList); diff --git a/services/json/include/serializable.h b/services/json/include/serializable.h index ea85f7d4c..32e26e101 100644 --- a/services/json/include/serializable.h +++ b/services/json/include/serializable.h @@ -45,6 +45,24 @@ public: static bool GetValue(cJSON *node, const std::string &name, Serializable &value); static bool GetValue(cJSON *node, const std::string &name, std::vector> &values); template + static bool GetValues(cJSON *nodes, std::vector &values, const std::function &func = nullptr) + { + cJSON *child = nodes->child; + bool result = true; + while (child != nullptr) { + std::string nodeKey = child->string; + cJSON *node = GetSubNode(nodes, nodeKey); + T value; + bool ret = GetValue(node, "", value); + if (ret && (func == nullptr || func(value))) { + values.push_back(value); + } + result = result && ret; + child = child->next; + } + return result; + } + template static bool GetValue(cJSON *node, const std::string &name, std::vector &values, int32_t maxNum = 0) { auto subNode = GetSubNode(node, name); diff --git a/services/src/ime_info_inquirer.cpp b/services/src/ime_info_inquirer.cpp index da9d643ba..3f7bd6cfb 100644 --- a/services/src/ime_info_inquirer.cpp +++ b/services/src/ime_info_inquirer.cpp @@ -74,6 +74,11 @@ bool ImeInfoInquirer::IsEnableAppAgent() return systemConfig_.enableAppAgentFeature; } +bool ImeInfoInquirer::IsEnableNumKey() +{ + return systemConfig_.enableNumKeyFeature; +} + bool ImeInfoInquirer::IsVirtualProxyIme(int32_t callingUid) { return systemConfig_.proxyImeUidList.find(callingUid) != systemConfig_.proxyImeUidList.end(); diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index a16e64851..e74708608 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -30,6 +30,7 @@ #include "iservice_registry.h" #include "itypes_util.h" #include "mem_mgr_client.h" +#include "numkey_apps_manager.h" #include "inputmethod_message_handler.h" #include "os_account_adapter.h" #include "scene_board_judgement.h" @@ -383,6 +384,7 @@ void InputMethodSystemAbility::UpdateUserInfo(int32_t userId) if (enableSecurityMode_.load()) { SecurityModeParser::GetInstance()->UpdateFullModeList(userId_); } + NumkeyAppsManager::GetInstance().OnUserSwitched(userId_); } int32_t InputMethodSystemAbility::OnIdle(const SystemAbilityOnDemandReason &idleReason) @@ -565,6 +567,8 @@ int32_t InputMethodSystemAbility::GenerateClientInfo(int32_t userId, InputClient clientInfo.config.windowId = callingWindowInfo.windowId; clientInfo.config.inputAttribute.windowId = callingWindowInfo.windowId; clientInfo.config.inputAttribute.callingDisplayId = callingWindowInfo.displayId; + clientInfo.config.inputAttribute.needAutoInputNumkey = + session->IsNumkeyAutoInputApp(clientInfo.config.inputAttribute.bundleName); IMSA_HILOGD("result:%{public}s,wid:%{public}d", clientInfo.config.inputAttribute.ToString().c_str(), clientInfo.config.windowId); } @@ -1552,6 +1556,7 @@ int32_t InputMethodSystemAbility::OnUserRemoved(const Message *msg) } ImeCfgManager::GetInstance().DeleteImeCfg(userId); FullImeInfoManager::GetInstance().Delete(userId); + NumkeyAppsManager::GetInstance().OnUserRemoved(userId); return ErrorCode::NO_ERROR; } @@ -1868,6 +1873,7 @@ void InputMethodSystemAbility::HandleDataShareReady() enableSecurityMode_.store(true); } FullImeInfoManager::GetInstance().Init(); + NumkeyAppsManager::GetInstance().Init(userId_); } int32_t InputMethodSystemAbility::InitAccountMonitor() diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp index 9fe291ebc..8e7855fa3 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -27,6 +27,7 @@ #include "ipc_skeleton.h" #include "iservice_registry.h" #include "mem_mgr_client.h" +#include "numkey_apps_manager.h" #include "on_demand_start_stop_sa.h" #include "os_account_adapter.h" #include "scene_board_judgement.h" @@ -2216,5 +2217,9 @@ void PerUserSession::ClearRequestKeyboardReason(std::shared_ptr clientInfo->requestKeyboardReason = RequestKeyboardReason::NONE; } +bool PerUserSession::IsNumkeyAutoInputApp(const std::string &bundleName) +{ + return NumkeyAppsManager::GetInstance().NeedAutoNumKeyInput(userId_, bundleName); +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file -- Gitee