diff --git a/bundle.json b/bundle.json index 96832be51b3e3eb20146dd26597f55e2527fe061..5959d7e8fde854c9772fd6154dd13748b0162b08 100644 --- a/bundle.json +++ b/bundle.json @@ -59,6 +59,7 @@ "resource_management", "screenlock_mgr", "cJSON", + "icu", "selinux_adapter" ] }, diff --git a/common/BUILD.gn b/common/BUILD.gn index df7dee560b68f4d003920d0a1cee0eeb7a8777f2..1f8f84eb320741165eef6ad107e9be3950e39c42 100644 --- a/common/BUILD.gn +++ b/common/BUILD.gn @@ -48,6 +48,7 @@ ohos_shared_library("inputmethod_common") { "src/message.cpp", "src/message_handler.cpp", "src/on_demand_start_stop_sa.cpp", + "src/string_utils.cpp", ] if (imf_on_demand_start_stop_sa_enable) { @@ -75,6 +76,7 @@ ohos_shared_library("inputmethod_common") { "hisysevent:libhisysevent", "hitrace:hitrace_meter", "hitrace:libhitracechain", + "icu:shared_icuuc", "input:libmmi-client", "ipc:ipc_single", "samgr:samgr_proxy", diff --git a/common/include/string_utils.h b/common/include/string_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..f7a91e4033a2d67116180940bcc16cedf4ed9a7b --- /dev/null +++ b/common/include/string_utils.h @@ -0,0 +1,32 @@ +/* + * 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 FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_STRING_UTILS_H +#define FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_STRING_UTILS_H + +#include + +namespace OHOS { +namespace MiscServices { +class StringUtils final { +public: + static std::string ToHex(const std::string &in); + static std::string ToHex(const std::u16string &in); + static int32_t CountUtf16Chars(const std::u16string &in); + static void TruncateUtf16String(std::u16string &in, int32_t maxChars); +}; +} // namespace MiscServices +} // namespace OHOS +#endif // FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_STRING_UTILS_H \ No newline at end of file diff --git a/common/src/itypes_util.cpp b/common/src/itypes_util.cpp index 83102c605a147d0d6597c2f094e5c6c24c2a3498..3da31354d5de3d04324db053ebff85f4671bcad8 100644 --- a/common/src/itypes_util.cpp +++ b/common/src/itypes_util.cpp @@ -187,7 +187,8 @@ 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.placeholder, input.abilityName)) { IMSA_HILOGE("write InputAttribute to message parcel failed."); return false; } @@ -197,7 +198,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.placeholder, output.abilityName)) { IMSA_HILOGE("read InputAttribute from message parcel failed."); return false; } diff --git a/common/src/string_utils.cpp b/common/src/string_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..283578512585a7b5ac059d4825a1ca35e80f92ea --- /dev/null +++ b/common/src/string_utils.cpp @@ -0,0 +1,90 @@ +/* + * 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 "string_utils.h" + +#include +#include + +#include "unicode/ustring.h" +#include "unicode/unistr.h" + +#include "global.h" + +namespace OHOS { +namespace MiscServices { +constexpr int32_t HEX_BYTE_WIDTH = 2; + +std::string StringUtils::ToHex(const std::string &in) +{ + std::stringstream ss; + if (in.size() < 1) { + return ""; + } + for (size_t i = 0; i < in.size(); i++) { + ss << std::uppercase << std::hex << std::setw(sizeof(uint8_t) * HEX_BYTE_WIDTH) + << std::setfill('0') << static_cast(in.at(i)); + } + return ss.str(); +} + +std::string StringUtils::ToHex(const std::u16string &in) +{ + std::stringstream ss; + if (in.size() < 1) { + return ""; + } + for (size_t i = 0; i < in.size(); i++) { + ss << std::uppercase << std::hex << std::setw(sizeof(char16_t) * HEX_BYTE_WIDTH) + << std::setfill('0') << in.at(i); + } + return ss.str(); +} + +int32_t StringUtils::CountUtf16Chars(const std::u16string &in) +{ + int32_t ret = u_countChar32(in.data(), in.size()); + IMSA_HILOGD("size:%{public}zu,ret:%{public}d", in.size(), ret); + return ret; +} + +void StringUtils::TruncateUtf16String(std::u16string &in, int32_t maxChars) +{ + const UChar* src = in.data(); + size_t srcLen = in.size(); + size_t offset = 0; + int32_t count = 0; + if (maxChars < 0 || srcLen <= maxChars) { + IMSA_HILOGD("srcLen:%{public}zu,maxChars:%{public}d", srcLen, maxChars); + return; + } + while (offset < srcLen && count < maxChars) { + UChar32 c; + U16_NEXT(src, offset, srcLen, c); + if (c == U_SENTINEL) { + break; + } + count++; + } + IMSA_HILOGD("srcLen:%{public}zu,maxChars:%{public}d,resultLen:%{public}zu,count:%{public}d", + srcLen, maxChars, offset, count); + if (offset < srcLen) { + IMSA_HILOGI("chars length exceeds limit,maxChars:%{public}d,offset:%{public}zu", maxChars, offset); + in.resize(offset); + } + return; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/js/napi/common/event_checker.cpp b/frameworks/js/napi/common/event_checker.cpp index 434304c2b725ad9a99a028d95f0f17772552fb5f..38402c4051683684bd412f2baae60d4a9e2149f5 100644 --- a/frameworks/js/napi/common/event_checker.cpp +++ b/frameworks/js/napi/common/event_checker.cpp @@ -26,7 +26,7 @@ const std::unordered_set EVENT_TYPES[static_cast(EventSub [static_cast(EventSubscribeModule::INPUT_METHOD_SETTING)] = { "imeChange", "imeShow", "imeHide" }, [static_cast(EventSubscribeModule::INPUT_METHOD_ABILITY)] = { "inputStart", "inputStop", "keyboardShow", "keyboardHide", "setCallingWindow", "setSubtype", "securityModeChange", "privateCommand", - "callingDisplayDidChange" }, + "callingDisplayDidChange", "discardTypingText" }, [static_cast(EventSubscribeModule::KEYBOARD_DELEGATE)] = { "editorAttributeChanged", "keyDown", "keyUp", "keyEvent", "cursorContextChange", "selectionChange", "textChange" }, [static_cast(EventSubscribeModule::KEYBOARD_PANEL_MANAGER)] = { "panelPrivateCommand", "isPanelShow" }, diff --git a/frameworks/js/napi/common/js_util.cpp b/frameworks/js/napi/common/js_util.cpp index 30ee04b2f1dd14ae7af7b21e28a4e1acbec175c5..a987522ea45c86d61d3d555a93fb53cc478e254b 100644 --- a/frameworks/js/napi/common/js_util.cpp +++ b/frameworks/js/napi/common/js_util.cpp @@ -115,5 +115,25 @@ napi_value JsUtil::GetValue(napi_env env, bool in) napi_get_boolean(env, in, &out); return out; } + +napi_value JsUtil::GetValueU16String(napi_env env, const std::u16string &in) +{ + napi_value out = nullptr; + napi_create_string_utf16(env, in.c_str(), in.length(), &out); + return out; +} + +bool JsUtil::GetValueU16String(napi_env env, napi_value in, std::u16string &out) +{ + size_t size = 0; + auto status = napi_get_value_string_utf16(env, in, nullptr, 0, &size); + if (status != napi_ok) { + return false; + } + out.resize(size + 1, 0); + status = napi_get_value_string_utf16(env, in, out.data(), size + 1, &size); + out.resize(size); + return status == napi_ok; +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/frameworks/js/napi/common/js_util.h b/frameworks/js/napi/common/js_util.h index 8310808266830630289adf9c274d4e37a29492e7..146a689389b69bf5072733f17094a4849148d9da 100644 --- a/frameworks/js/napi/common/js_util.h +++ b/frameworks/js/napi/common/js_util.h @@ -34,6 +34,7 @@ public: static bool GetValue(napi_env env, napi_value in, int64_t &out); static bool GetValue(napi_env env, napi_value in, bool &out); static bool GetValue(napi_env env, napi_value in, double &out); + static bool GetValueU16String(napi_env env, napi_value in, std::u16string &out); template static bool GetValue(napi_env env, napi_value in, std::vector &items) { @@ -59,6 +60,7 @@ public: static napi_value GetValue(napi_env env, uint32_t in); static napi_value GetValue(napi_env env, int64_t in); static napi_value GetValue(napi_env env, bool in); + static napi_value GetValueU16String(napi_env env, const std::u16string &in); template static napi_value GetValue(napi_env env, const std::vector &items) { @@ -94,6 +96,24 @@ public: napi_get_named_property(env, object, property.c_str(), &propValue); return GetValue(env, propValue, value); } + + static bool ReadPropertyU16String(napi_env env, napi_value object, const std::string &property, + std::u16string &value) + { + napi_value propValue = nullptr; + napi_status status = napi_get_named_property(env, object, property.c_str(), &propValue); + if (status != napi_ok) { + value = u""; + return false; + } + return GetValueU16String(env, propValue, value); + } + + static bool WritePropertyU16String(napi_env env, napi_value object, const std::string &property, + const std::u16string &value) + { + return napi_set_named_property(env, object, property.c_str(), GetValueU16String(env, value)) == napi_ok; + } }; class Const { public: diff --git a/frameworks/js/napi/inputmethodability/js_input_method_engine_setting.cpp b/frameworks/js/napi/inputmethodability/js_input_method_engine_setting.cpp index a56dbce687b11f9cfc4a93d8db9ebbbc7e064c58..3f4715f1df3047725a6a16cf2ae22f4552bc50f2 100644 --- a/frameworks/js/napi/inputmethodability/js_input_method_engine_setting.cpp +++ b/frameworks/js/napi/inputmethodability/js_input_method_engine_setting.cpp @@ -77,6 +77,14 @@ napi_value JsInputMethodEngineSetting::Init(napi_env env, napi_value exports) "PATTERN_PASSWORD_NUMBER", GetJsConstProperty(env, static_cast(TextInputType::NUMBER_PASSWORD))), DECLARE_NAPI_PROPERTY("PATTERN_PASSWORD_SCREEN_LOCK", GetJsConstProperty(env, static_cast(TextInputType::SCREEN_LOCK_PASSWORD))), + DECLARE_NAPI_PROPERTY( + "PATTERN_USER_NAME", GetJsConstProperty(env, static_cast(TextInputType::USER_NAME))), + DECLARE_NAPI_PROPERTY( + "PATTERN_NEW_PASSWORD", GetJsConstProperty(env, static_cast(TextInputType::NEW_PASSWORD))), + DECLARE_NAPI_PROPERTY( + "PATTERN_NUMBER_DECIMAL", GetJsConstProperty(env, static_cast(TextInputType::NUMBER_DECIMAL))), + DECLARE_NAPI_PROPERTY( + "PATTERN_ONE_TIME_CODE", GetJsConstProperty(env, static_cast(TextInputType::ONE_TIME_CODE))), DECLARE_NAPI_FUNCTION("getInputMethodEngine", GetInputMethodEngine), DECLARE_NAPI_FUNCTION("getInputMethodAbility", GetInputMethodAbility), DECLARE_NAPI_STATIC_PROPERTY("PanelType", GetJsPanelTypeProperty(env)), @@ -90,7 +98,7 @@ napi_value JsInputMethodEngineSetting::Init(napi_env env, napi_value exports) NAPI_CALL( env, napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor)); return InitProperty(env, exports); -}; +} napi_value JsInputMethodEngineSetting::InitProperty(napi_env env, napi_value exports) { @@ -659,6 +667,25 @@ void JsInputMethodEngineSetting::OnInputStart() } } +int32_t JsInputMethodEngineSetting::OnDiscardTypingText() +{ + IMSA_HILOGI("DiscardTypingText start."); + std::string type = "discardTypingText"; + auto entry = GetEntry(type); + if (entry == nullptr) { + IMSA_HILOGE("entry is nullptr!"); + return ErrorCode::ERROR_NULL_POINTER; + } + auto eventHandler = GetEventHandler(); + if (eventHandler == nullptr) { + IMSA_HILOGE("eventHandler is nullptr!"); + return ErrorCode::ERROR_NULL_POINTER; + } + auto task = [entry]() { JsCallbackHandler::Traverse(entry->vecCopy); }; + return eventHandler->PostTask(task, type, 0, AppExecFwk::EventQueue::Priority::VIP) + ? ErrorCode::NO_ERROR : ErrorCode::ERROR_IME; +} + void JsInputMethodEngineSetting::OnKeyboardStatus(bool isShow) { std::string type = isShow ? "keyboardShow" : "keyboardHide"; @@ -872,6 +899,17 @@ std::shared_ptr JsInputMethodEngineSetting: return entry; } +bool JsInputMethodEngineSetting::IsCallbackRegistered(const std::string &type) +{ + IMSA_HILOGD("type: %{public}s.", type.c_str()); + std::lock_guard lock(mutex_); + if (jsCbMap_[type].empty()) { + IMSA_HILOGE("%{public}s cb-vector is empty", type.c_str()); + return false; + } + return true; +} + void JsInputMethodEngineSetting::FreeWorkIfFail(int ret, uv_work_t *work) { if (ret == 0 || work == nullptr) { diff --git a/frameworks/js/napi/inputmethodability/js_input_method_engine_setting.h b/frameworks/js/napi/inputmethodability/js_input_method_engine_setting.h index 2214a2caae21a34bc9e6585c703c421c5d0b5d87..b11d2bf824aac4141c1969b4face6add3882bde8 100644 --- a/frameworks/js/napi/inputmethodability/js_input_method_engine_setting.h +++ b/frameworks/js/napi/inputmethodability/js_input_method_engine_setting.h @@ -53,11 +53,13 @@ public: void OnInputStart() override; void OnKeyboardStatus(bool isShow) override; int32_t OnInputStop() override; + int32_t OnDiscardTypingText() override; void OnSetCallingWindow(uint32_t windowId) override; void OnSetSubtype(const SubProperty &property) override; void OnSecurityChange(int32_t security) override; void ReceivePrivateCommand(const std::unordered_map &privateCommand) override; bool PostTaskToEventHandler(std::function task, const std::string &taskName) override; + bool IsCallbackRegistered(const std::string &type) override; void OnCallingDisplayIdChanged(uint64_t callingDisplayId) override; private: struct PanelContext : public AsyncCall::Context { diff --git a/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp b/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp index 2164086be9925d33f24eb208f5e8dd171dbb67a4..c83fe59e5eb694a743817d858106a169ed106859 100644 --- a/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp +++ b/frameworks/js/napi/inputmethodability/js_text_input_client_engine.cpp @@ -24,6 +24,7 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" #include "string_ex.h" +#include "string_utils.h" #include "wm_common.h" #include "res_config.h" #include "resource_manager.h" @@ -1084,6 +1085,8 @@ napi_value JsInputAttribute::Write(napi_env env, const InputAttribute &nativeObj ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "windowId", nativeObject.windowId); ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "displayId", static_cast(nativeObject.callingDisplayId)); + ret = ret && JsUtil::Object::WritePropertyU16String(env, jsObject, "placeholder", nativeObject.placeholder); + ret = ret && JsUtil::Object::WritePropertyU16String(env, jsObject, "abilityName", nativeObject.abilityName); return ret ? jsObject : JsUtil::Const::Null(env); } @@ -1095,6 +1098,10 @@ bool JsInputAttribute::Read(napi_env env, napi_value jsObject, InputAttribute &n JsUtil::Object::ReadProperty(env, jsObject, "isTextPreviewSupported", nativeObject.isTextPreviewSupported); // not care read bundleName fail JsUtil::Object::ReadProperty(env, jsObject, "bundleName", nativeObject.bundleName); + JsUtil::Object::ReadPropertyU16String(env, jsObject, "placeholder", nativeObject.placeholder); + IMSA_HILOGD("placeholder:%{public}s", StringUtils::ToHex(nativeObject.placeholder).c_str()); + JsUtil::Object::ReadPropertyU16String(env, jsObject, "abilityName", nativeObject.abilityName); + IMSA_HILOGD("abilityName:%{public}s", StringUtils::ToHex(nativeObject.abilityName).c_str()); ret = ret && JsUtil::Object::ReadProperty(env, jsObject, "immersiveMode", nativeObject.immersiveMode); return ret; } diff --git a/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.cpp b/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.cpp index 55b60dfacd2361863579f68372561fc80b85fd13..0b0ece51e396f0a784fbba03bc9c5b43b5bfad2f 100644 --- a/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.cpp +++ b/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.cpp @@ -26,6 +26,7 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" #include "string_ex.h" +#include "string_utils.h" namespace OHOS { namespace MiscServices { @@ -33,6 +34,7 @@ constexpr size_t ARGC_ZERO = 0; constexpr size_t ARGC_ONE = 1; constexpr size_t ARGC_TWO = 2; constexpr int32_t MAX_WAIT_TIME_MESSAGE_HANDLER = 2000; +constexpr int32_t MAX_WAIT_TIME_ATTACH = 2000; const std::set EVENT_TYPE{ "selectByRange", "selectByMovement", @@ -56,6 +58,7 @@ std::shared_ptr JsGetInputMethodController::controll std::mutex JsGetInputMethodController::eventHandlerMutex_; std::shared_ptr JsGetInputMethodController::handler_{ nullptr }; BlockQueue JsGetInputMethodController::messageHandlerQueue_{ MAX_WAIT_TIME_MESSAGE_HANDLER }; +BlockQueue JsGetInputMethodController::attachQueue_{ MAX_WAIT_TIME_ATTACH }; napi_value JsGetInputMethodController::Init(napi_env env, napi_value info) { napi_property_descriptor descriptor[] = { @@ -89,6 +92,7 @@ napi_value JsGetInputMethodController::Init(napi_env env, napi_value info) DECLARE_NAPI_FUNCTION("off", UnSubscribe), DECLARE_NAPI_FUNCTION("sendMessage", SendMessage), DECLARE_NAPI_FUNCTION("recvMessage", RecvMessage), + DECLARE_NAPI_FUNCTION("discardTypingText", DiscardTypingText), }; napi_value cons = nullptr; NAPI_CALL(env, napi_define_class(env, IMC_CLASS_NAME.c_str(), IMC_CLASS_NAME.size(), JsConstructor, nullptr, @@ -162,6 +166,10 @@ napi_value JsGetInputMethodController::GetJsTextInputTypeProperty(napi_env env) napi_value typeUrl = nullptr; napi_value typeVisiblePassword = nullptr; napi_value typeNumberPassword = nullptr; + napi_value typeScreenLockPassword = nullptr; + napi_value typeUserName = nullptr; + napi_value typeNewPassword = nullptr; + napi_value typeNumberDecimal = nullptr; NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::NONE), &typeNone)); NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::TEXT), &typeText)); NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::MULTILINE), &typeMultiline)); @@ -172,6 +180,11 @@ napi_value JsGetInputMethodController::GetJsTextInputTypeProperty(napi_env env) NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::URL), &typeUrl)); NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::VISIBLE_PASSWORD), &typeVisiblePassword)); NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::NUMBER_PASSWORD), &typeNumberPassword)); + NAPI_CALL(env, napi_create_int32(env, + static_cast(TextInputType::SCREEN_LOCK_PASSWORD), &typeScreenLockPassword)); + NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::USER_NAME), &typeUserName)); + NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::NEW_PASSWORD), &typeNewPassword)); + NAPI_CALL(env, napi_create_int32(env, static_cast(TextInputType::NUMBER_DECIMAL), &typeNumberDecimal)); NAPI_CALL(env, napi_create_object(env, &textInputType)); NAPI_CALL(env, napi_set_named_property(env, textInputType, "NONE", typeNone)); NAPI_CALL(env, napi_set_named_property(env, textInputType, "TEXT", typeText)); @@ -183,7 +196,13 @@ napi_value JsGetInputMethodController::GetJsTextInputTypeProperty(napi_env env) NAPI_CALL(env, napi_set_named_property(env, textInputType, "URL", typeUrl)); NAPI_CALL(env, napi_set_named_property(env, textInputType, "VISIBLE_PASSWORD", typeVisiblePassword)); NAPI_CALL(env, napi_set_named_property(env, textInputType, "NUMBER_PASSWORD", typeNumberPassword)); - return textInputType; + NAPI_CALL(env, napi_set_named_property(env, textInputType, "SCREEN_LOCK_PASSWORD", typeScreenLockPassword)); + NAPI_CALL(env, napi_set_named_property(env, textInputType, "USER_NAME", typeUserName)); + NAPI_CALL(env, napi_set_named_property(env, textInputType, "NEW_PASSWORD", typeNewPassword)); + NAPI_CALL(env, napi_set_named_property(env, textInputType, "NUMBER_DECIMAL", typeNumberDecimal)); + bool ret = JsUtil::Object::WriteProperty(env, textInputType, "ONE_TIME_CODE", + static_cast(TextInputType::ONE_TIME_CODE)); + return ret ? textInputType : JsUtil::Const::Null(env); } napi_value JsGetInputMethodController::GetJsDirectionProperty(napi_env env) @@ -544,6 +563,7 @@ bool JsGetInputMethodController::GetValue(napi_env env, napi_value in, Range &ou * end: number * }, * windowId?: number + * newEditBox?: boolean * } */ bool JsGetInputMethodController::GetValue(napi_env env, napi_value in, TextConfig &out) @@ -553,7 +573,6 @@ bool JsGetInputMethodController::GetValue(napi_env env, napi_value in, TextConfi CHECK_RETURN(status == napi_ok, "inputAttribute must be InputAttribute!", false); bool ret = JsGetInputMethodController::GetValue(env, attributeResult, out.inputAttribute); CHECK_RETURN(ret, "inputAttribute of TextConfig must be valid!", ret); - napi_value cursorInfoResult = nullptr; status = JsUtils::GetValue(env, in, "cursorInfo", cursorInfoResult); bool result = false; @@ -577,6 +596,10 @@ bool JsGetInputMethodController::GetValue(napi_env env, napi_value in, TextConfi if (!result) { IMSA_HILOGE("get windowId failed."); } + result = JsUtil::Object::ReadProperty(env, in, "newEditBox", out.newEditBox); + if (!result) { + IMSA_HILOGE("get newEditBox failed."); + } return ret; } @@ -602,10 +625,13 @@ napi_value JsGetInputMethodController::Attach(napi_env env, napi_callback_info i JsUtil::GetValue(env, argv[2], ctxt->requestKeyboardReason); } } + ctxt->info = { std::chrono::system_clock::now(), ctxt->attribute}; + attachQueue_.Push(ctxt->info); return napi_ok; }; auto exec = [ctxt, env](AsyncCall::Context *ctx) { - ctxt->textListener = JsGetInputMethodTextChangedListener::GetInstance(); + attachQueue_.Wait(ctxt->info); + ctxt->textListener = JsGetInputMethodTextChangedListener::GetTextListener(ctxt->textConfig.newEditBox); OHOS::MiscServices::AttachOptions attachOptions; attachOptions.isShowKeyboard = ctxt->showKeyboard; attachOptions.requestKeyboardReason = @@ -615,6 +641,7 @@ napi_value JsGetInputMethodController::Attach(napi_env env, napi_callback_info i if (instance != nullptr) { status = instance->Attach(ctxt->textListener, attachOptions, ctxt->textConfig, ClientType::JS); } + attachQueue_.Pop(); ctxt->SetErrorCode(status); CHECK_RETURN_VOID(status == ErrorCode::NO_ERROR, "attach return error!"); ctxt->SetState(napi_ok); @@ -697,6 +724,22 @@ napi_value JsGetInputMethodController::HideTextInput(napi_env env, napi_callback false, true); } +napi_value JsGetInputMethodController::DiscardTypingText(napi_env env, napi_callback_info info) +{ + InputMethodSyncTrace tracer("JsGetInputMethodController_DiscardTypingText"); + return HandleSoftKeyboard( + env, info + , [] { + auto instance = InputMethodController::GetInstance(); + if (instance == nullptr) { + IMSA_HILOGE("GetInstance return nullptr!"); + return static_cast(ErrorCode::ERROR_CLIENT_NULL_POINTER); + } + return instance->DiscardTypingText(); + }, + false, true); +} + napi_value JsGetInputMethodController::SetCallingWindow(napi_env env, napi_callback_info info) { auto ctxt = std::make_shared(); @@ -792,7 +835,14 @@ napi_value JsGetInputMethodController::ChangeSelection(napi_env env, napi_callba bool JsGetInputMethodController::GetValue(napi_env env, napi_value in, InputAttribute &out) { auto ret = JsUtil::Object::ReadProperty(env, in, "textInputType", out.inputPattern); - return ret && JsUtil::Object::ReadProperty(env, in, "enterKeyType", out.enterKeyType); + ret = ret && JsUtil::Object::ReadProperty(env, in, "enterKeyType", out.enterKeyType); + // compatibility with older versions may not exist + JsUtil::Object::ReadPropertyU16String(env, in, "placeholder", out.placeholder); + IMSA_HILOGD("placeholder:%{public}s", StringUtils::ToHex(out.placeholder).c_str()); + // compatibility with older versions may not exist + JsUtil::Object::ReadPropertyU16String(env, in, "abilityName", out.abilityName); + IMSA_HILOGD("abilityName:%{public}s", StringUtils::ToHex(out.abilityName).c_str()); + return ret; } napi_value JsGetInputMethodController::UpdateAttribute(napi_env env, napi_callback_info info) diff --git a/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.h b/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.h index 4b8a383a0bae7e773a224b0001d03031b73b72b4..2964e1fefd90827a465cdbe6d72079d6ec9fedc1 100644 --- a/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.h +++ b/frameworks/js/napi/inputmethodclient/js_get_input_method_controller.h @@ -26,6 +26,15 @@ namespace OHOS { namespace MiscServices { +struct AttachInfo { + std::chrono::system_clock::time_point timestamp{}; + InputAttribute attribute; + bool operator==(const AttachInfo &info) const + { + return (timestamp == info.timestamp && attribute == info.attribute); + } +}; + struct HandleContext : public AsyncCall::Context { bool isHandle = false; napi_status status = napi_generic_failure; @@ -53,6 +62,7 @@ struct AttachContext : public AsyncCall::Context { bool showKeyboard = false; int32_t requestKeyboardReason = 0; TextConfig textConfig; + AttachInfo info; AttachContext() : Context(nullptr, nullptr){}; AttachContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){}; @@ -168,6 +178,7 @@ public: static napi_value Detach(napi_env env, napi_callback_info info); static napi_value ShowTextInput(napi_env env, napi_callback_info info); static napi_value HideTextInput(napi_env env, napi_callback_info info); + static napi_value DiscardTypingText(napi_env env, napi_callback_info info); static napi_value SetCallingWindow(napi_env env, napi_callback_info info); static napi_value UpdateCursor(napi_env env, napi_callback_info info); static napi_value ChangeSelection(napi_env env, napi_callback_info info); @@ -266,6 +277,7 @@ private: static constexpr size_t PARAM_POS_TWO = 2; static constexpr size_t PARAM_POS_THREE = 3; static BlockQueue messageHandlerQueue_; + static BlockQueue attachQueue_; }; } // namespace MiscServices } // namespace OHOS diff --git a/frameworks/js/napi/inputmethodclient/js_get_input_method_textchange_listener.cpp b/frameworks/js/napi/inputmethodclient/js_get_input_method_textchange_listener.cpp index 1f7aaa6cd30f2a842d162b2b902c1d1ba0855e6f..ff6e403aa8f3535f8c8d3b548383fa10cc924d30 100644 --- a/frameworks/js/napi/inputmethodclient/js_get_input_method_textchange_listener.cpp +++ b/frameworks/js/napi/inputmethodclient/js_get_input_method_textchange_listener.cpp @@ -19,12 +19,18 @@ namespace OHOS { namespace MiscServices { std::mutex JsGetInputMethodTextChangedListener::listenerMutex_; sptr JsGetInputMethodTextChangedListener::inputMethodListener_{ nullptr }; -sptr JsGetInputMethodTextChangedListener::GetInstance() +sptr JsGetInputMethodTextChangedListener::GetTextListener(bool newEditBox) { - if (inputMethodListener_ == nullptr) { + IMSA_HILOGD("newEditBox is %{public}d.", newEditBox); + if (newEditBox) { std::lock_guard lock(listenerMutex_); + inputMethodListener_ = new (std::nothrow) JsGetInputMethodTextChangedListener(); + } else { if (inputMethodListener_ == nullptr) { - inputMethodListener_ = new (std::nothrow) JsGetInputMethodTextChangedListener(); + std::lock_guard lock(listenerMutex_); + if (inputMethodListener_ == nullptr) { + inputMethodListener_ = new (std::nothrow) JsGetInputMethodTextChangedListener(); + } } } return inputMethodListener_; diff --git a/frameworks/js/napi/inputmethodclient/js_get_input_method_textchange_listener.h b/frameworks/js/napi/inputmethodclient/js_get_input_method_textchange_listener.h index cfefb2e3b239cca0b6283a003a66e03266f6395d..44cf0cecec9290555e19789fbadb72e1ea2966a0 100644 --- a/frameworks/js/napi/inputmethodclient/js_get_input_method_textchange_listener.h +++ b/frameworks/js/napi/inputmethodclient/js_get_input_method_textchange_listener.h @@ -23,7 +23,7 @@ class JsGetInputMethodTextChangedListener : public OnTextChangedListener { public: JsGetInputMethodTextChangedListener() = default; ~JsGetInputMethodTextChangedListener() = default; - static sptr GetInstance(); + static sptr GetTextListener(bool newEditBox = false); void InsertText(const std::u16string &text) override; void DeleteForward(int32_t length) override; diff --git a/frameworks/native/inputmethod_ability/IInputMethodAgent.idl b/frameworks/native/inputmethod_ability/IInputMethodAgent.idl index 30b2d4d6ae058c69618ed24112397fdaeba05b38..49b08ce29f0cebaa67aa89b665711715a59c422d 100644 --- a/frameworks/native/inputmethod_ability/IInputMethodAgent.idl +++ b/frameworks/native/inputmethod_ability/IInputMethodAgent.idl @@ -26,4 +26,5 @@ interface OHOS.MiscServices.IInputMethodAgent { void OnAttributeChange([in] InputAttributeInner attributeInner); void SendPrivateCommand([in] Value value); void SendMessage([in] ArrayBuffer arraybuffer); + void DiscardTypingText(); } diff --git a/frameworks/native/inputmethod_ability/include/input_method_ability.h b/frameworks/native/inputmethod_ability/include/input_method_ability.h index 6fffe233d8512e4b8eb86c52f00a618cbc49930a..dd3841220805c656a0daf0f53ac4be6c5bf524e0 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_ability.h +++ b/frameworks/native/inputmethod_ability/include/input_method_ability.h @@ -82,6 +82,7 @@ public: int32_t HidePanel(const std::shared_ptr &inputMethodPanel); bool IsCurrentIme(); bool IsEnable(); + bool IsCallbackRegistered(const std::string &type); bool IsSystemApp(); InputType GetInputType(); int32_t ExitCurrentInputType(); @@ -113,6 +114,7 @@ public: int32_t StopInput(sptr channelObj, uint32_t sessionId); int32_t ShowKeyboard(int32_t requestKeyboardReason); int32_t HideKeyboard(); + int32_t OnDiscardTypingText(); void OnInitInputControlChannel(sptr channelObj); void OnSetSubtype(SubProperty subProperty); diff --git a/frameworks/native/inputmethod_ability/include/input_method_agent_service_impl.h b/frameworks/native/inputmethod_ability/include/input_method_agent_service_impl.h index d0ad5498c4f40830591e00f11a0eb09ba8110f61..f2c2ee92c4b303b838cda84675191f6a27ad6d61 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_agent_service_impl.h +++ b/frameworks/native/inputmethod_ability/include/input_method_agent_service_impl.h @@ -38,6 +38,7 @@ public: ErrCode OnAttributeChange(const InputAttributeInner &attributeInner) override; ErrCode SendPrivateCommand(const Value &value) override; ErrCode SendMessage(const ArrayBuffer &arraybuffer) override; + ErrCode DiscardTypingText() override; }; } // namespace MiscServices } // namespace OHOS diff --git a/frameworks/native/inputmethod_ability/include/tasks/task.h b/frameworks/native/inputmethod_ability/include/tasks/task.h index 051f21e13becd197ed74a901e7061ceae7316243..77f1afcf9c74f7e44d1b07be9540e6858e4aa489 100644 --- a/frameworks/native/inputmethod_ability/include/tasks/task.h +++ b/frameworks/native/inputmethod_ability/include/tasks/task.h @@ -61,7 +61,8 @@ enum TaskType : uint32_t { TASK_TYPE_IMSA_SET_SUBPROPERTY, TASK_TYPE_IMSA_SET_CORE_AND_AGENT, TASK_TYPE_IMSA_ADJUST_KEYBOARD, - TASK_TYPE_IMSA_END = TASK_TYPE_IMSA_ADJUST_KEYBOARD, + TASK_TYPE_IMSA_DISCARD_TYPING_TEXT, + TASK_TYPE_IMSA_END = TASK_TYPE_IMSA_DISCARD_TYPING_TEXT, // Task from inner TASK_TYPE_RESUME, diff --git a/frameworks/native/inputmethod_ability/include/tasks/task_imsa.h b/frameworks/native/inputmethod_ability/include/tasks/task_imsa.h index 5d8bd121c8a5d3610cc172208e6015c13f65fc44..819b623cdcb2d24ce160dd39a7bab7cd0d8cc5a7 100644 --- a/frameworks/native/inputmethod_ability/include/tasks/task_imsa.h +++ b/frameworks/native/inputmethod_ability/include/tasks/task_imsa.h @@ -111,6 +111,18 @@ public: ~TaskImsaOnCursorUpdate() = default; }; +class TaskImsaDiscardTypingText : public Task { +public: + TaskImsaDiscardTypingText() : Task(TASK_TYPE_IMSA_DISCARD_TYPING_TEXT) + { + auto func = []() { + InputMethodAbility::GetInstance().OnDiscardTypingText(); + }; + actions_.emplace_back(std::make_unique(func)); + } + ~TaskImsaDiscardTypingText() = default; +}; + class TaskImsaSendPrivateCommand : public Task { public: TaskImsaSendPrivateCommand(std::unordered_map privateCommand) diff --git a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp index 014a1b8bf50ddd35854d7102f755e5d3bf92a07d..a505ae8c7304436eda828d6a50421780c4ee7405 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp @@ -469,6 +469,16 @@ int32_t InputMethodAbility::OnStopInputService(bool isTerminateIme) return ErrorCode::NO_ERROR; } +int32_t InputMethodAbility::OnDiscardTypingText() +{ + auto imeListener = GetImeListener(); + if (imeListener == nullptr) { + IMSA_HILOGE("imeListener is nullptr!"); + return ErrorCode::ERROR_IME_NOT_STARTED; + } + return imeListener_->OnDiscardTypingText(); +} + int32_t InputMethodAbility::HideKeyboard() { std::lock_guard lock(keyboardCmdLock_); @@ -1260,6 +1270,14 @@ bool InputMethodAbility::IsEnable() return imeListener_->IsEnable(); } +bool InputMethodAbility::IsCallbackRegistered(const std::string &type) +{ + if (imeListener_ == nullptr) { + return false; + } + return imeListener_->IsCallbackRegistered(type); +} + bool InputMethodAbility::IsSystemApp() { IMSA_HILOGD("InputMethodAbility start"); diff --git a/frameworks/native/inputmethod_ability/src/input_method_agent_service_impl.cpp b/frameworks/native/inputmethod_ability/src/input_method_agent_service_impl.cpp index bc9aec9f70a2b6a1f4281f0bfe82239fc82e8a28..561955df72322b4dbf576ed181108a8cb87f2613 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_agent_service_impl.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_agent_service_impl.cpp @@ -85,5 +85,20 @@ ErrCode InputMethodAgentServiceImpl::SendMessage(const ArrayBuffer &arraybuffer) { return InputMethodAbility::GetInstance().RecvMessage(arraybuffer); } + + +ErrCode InputMethodAgentServiceImpl::DiscardTypingText() +{ + IMSA_HILOGD("DiscardTypingText run"); + std::string type = "discardTypingText"; + auto ret = InputMethodAbility::GetInstance().IsCallbackRegistered(type); + if (!ret) { + IMSA_HILOGE("callback not registered"); + return ErrorCode::ERROR_MSG_HANDLER_NOT_REGIST; + } + auto task = std::make_shared(); + TaskManager::GetInstance().PostTask(task); + return ErrorCode::NO_ERROR; +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/include/input_attribute.h b/frameworks/native/inputmethod_controller/include/input_attribute.h index 6d0242dcd6c372155df6c55d49fd345d5879bb4f..bd12fb748817723e270e7137a291762e69de06de 100644 --- a/frameworks/native/inputmethod_controller/include/input_attribute.h +++ b/frameworks/native/inputmethod_controller/include/input_attribute.h @@ -30,6 +30,7 @@ struct InputAttribute { static const int32_t PATTERN_PASSWORD_NUMBER = 0x00000008; static const int32_t PATTERN_PASSWORD_SCREEN_LOCK = 0x00000009; static const int32_t PATTERN_NEWPASSWORD = 0x0000000b; + static const int32_t PATTERN_ONE_TIME_CODE = 0x0000000d; int32_t inputPattern = 0; int32_t enterKeyType = 0; int32_t inputOption = 0; @@ -38,6 +39,8 @@ struct InputAttribute { int32_t immersiveMode = 0; uint32_t windowId = 0; // for transfer uint64_t callingDisplayId = 0; + std::u16string placeholder { u"" }; + std::u16string abilityName { u"" }; bool GetSecurityFlag() const { @@ -45,6 +48,16 @@ struct InputAttribute { PATTERN_PASSWORD_NUMBER == inputPattern || PATTERN_NEWPASSWORD == inputPattern; } + bool IsOneTimeCodeFlag() const + { + return inputPattern == PATTERN_ONE_TIME_CODE; + } + + bool IsSecurityImeFlag() const + { + return GetSecurityFlag() || IsOneTimeCodeFlag(); + } + bool operator==(const InputAttribute &info) const { return inputPattern == info.inputPattern && enterKeyType == info.enterKeyType && @@ -58,7 +71,8 @@ struct InputAttribute { << "enterKeyType:" << enterKeyType << "inputOption:" << inputOption << "isTextPreviewSupported:" << isTextPreviewSupported << "bundleName:" << bundleName << "immersiveMode:" << immersiveMode << "windowId:" << windowId - << "callingDisplayId:" << callingDisplayId << "]"; + << "callingDisplayId:" << callingDisplayId + << "]"; return ss.str(); } }; @@ -77,6 +91,8 @@ struct InputAttributeInner : public Parcelable { int32_t immersiveMode = 0; uint32_t windowId = 0; // for transfer uint64_t callingDisplayId = 0; + std::u16string placeholder { u"" }; + std::u16string abilityName { u"" }; bool ReadFromParcel(Parcel &in) { @@ -88,6 +104,8 @@ struct InputAttributeInner : public Parcelable { immersiveMode = in.ReadInt32(); windowId = in.ReadUint32(); callingDisplayId = in.ReadUint64(); + placeholder = in.ReadString16(); + abilityName = in.ReadString16(); return true; } @@ -117,7 +135,8 @@ struct InputAttributeInner : public Parcelable { if (!out.WriteUint64(callingDisplayId)) { return false; } - return true; + auto ret = out.WriteString16(placeholder) && out.WriteString16(abilityName); + return ret; } static InputAttributeInner *Unmarshalling(Parcel &in) diff --git a/frameworks/native/inputmethod_controller/include/input_method_utils.h b/frameworks/native/inputmethod_controller/include/input_method_utils.h index 534c4b4a046419553fcc02107db31634090820a7..ab912a4275388d1883cdf0e3529f44e86665bc64 100644 --- a/frameworks/native/inputmethod_controller/include/input_method_utils.h +++ b/frameworks/native/inputmethod_controller/include/input_method_utils.h @@ -62,6 +62,7 @@ enum class TextInputType { USER_NAME, NEW_PASSWORD, NUMBER_DECIMAL, + ONE_TIME_CODE, }; enum class Direction { @@ -391,6 +392,7 @@ struct TextConfig { uint32_t windowId = INVALID_WINDOW_ID; double positionY = 0; double height = 0; + bool newEditBox = false; std::unordered_map privateCommand = {}; std::string ToString() const @@ -471,6 +473,7 @@ enum class InputType : int32_t { SECURITY_INPUT, VOICE_INPUT, VOICEKB_INPUT, + ONE_TIME_CODE = 13, END }; diff --git a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp index a91d97abdbec00ef1b0ccd336595716e922f0250..389a368eb6419ca65caadfed168342a086f45fff 100644 --- a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp +++ b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp @@ -35,6 +35,7 @@ #include "keyevent_consumer_service_impl.h" #include "on_demand_start_stop_sa.h" #include "string_ex.h" +#include "string_utils.h" #include "sys/prctl.h" #include "system_ability_definition.h" #include "system_cmd_channel_stub.h" @@ -54,6 +55,8 @@ constexpr int32_t LOOP_COUNT = 5; constexpr int32_t LOG_MAX_TIME = 20; constexpr int64_t DELAY_TIME = 100; constexpr int32_t ACE_DEAL_TIME_OUT = 200; +constexpr int32_t MAX_PLACEHOLDER_SIZE = 255; // 256 utf16 char +constexpr int32_t MAX_ABILITY_NAME_SIZE = 127; // 127 utf16 char InputMethodController::InputMethodController() { IMSA_HILOGD("IMC structure."); @@ -207,6 +210,8 @@ void InputMethodController::SaveTextConfig(const TextConfig &textConfig) { std::lock_guard lock(textConfigLock_); textConfig_ = textConfig; + StringUtils::TruncateUtf16String(textConfig_.inputAttribute.placeholder, MAX_PLACEHOLDER_SIZE); + StringUtils::TruncateUtf16String(textConfig_.inputAttribute.abilityName, MAX_ABILITY_NAME_SIZE); } if (textConfig.range.start != INVALID_VALUE) { std::lock_guard lock(editorContentLock_); @@ -710,6 +715,20 @@ void InputMethodController::RestoreClientInfoInSaDied() } } +int32_t InputMethodController::DiscardTypingText() +{ + if (!IsBound()) { + IMSA_HILOGE("not bound."); + return ErrorCode::ERROR_CLIENT_NOT_BOUND; + } + auto agent = GetAgent(); + if (agent == nullptr) { + IMSA_HILOGE("agent is nullptr!"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + return agent->DiscardTypingText(); +} + int32_t InputMethodController::OnCursorUpdate(CursorInfo cursorInfo) { if (!IsBound()) { diff --git a/frameworks/native/inputmethod_controller/src/input_method_tools.cpp b/frameworks/native/inputmethod_controller/src/input_method_tools.cpp index 2635c6871bcc4ac9917b0df77f35ebf3d9e5c505..43cf625fbd1eec1bf99466246469255be501f9c6 100644 --- a/frameworks/native/inputmethod_controller/src/input_method_tools.cpp +++ b/frameworks/native/inputmethod_controller/src/input_method_tools.cpp @@ -35,6 +35,8 @@ InputAttributeInner InputMethodTools::AttributeToInner(const InputAttribute &att inner.immersiveMode = attribute.immersiveMode; inner.windowId = attribute.windowId; inner.callingDisplayId = attribute.callingDisplayId; + inner.placeholder = attribute.placeholder; + inner.abilityName = attribute.abilityName; return inner; } @@ -49,6 +51,8 @@ InputAttribute InputMethodTools::InnerToAttribute(const InputAttributeInner &inn inputAttribute.immersiveMode = inner.immersiveMode; inputAttribute.windowId = inner.windowId; inputAttribute.callingDisplayId = inner.callingDisplayId; + inputAttribute.placeholder = inner.placeholder; + inputAttribute.abilityName = inner.abilityName; return inputAttribute; } diff --git a/frameworks/ndk/BUILD.gn b/frameworks/ndk/BUILD.gn index e656a38d5009cff41dee31b13092ebe373e07f83..bfd2b8edfa5424bf48be464b07e495de9c4c2ebb 100644 --- a/frameworks/ndk/BUILD.gn +++ b/frameworks/ndk/BUILD.gn @@ -42,7 +42,10 @@ ohos_shared_library("ohinputmethod") { "include", "${inputmethod_path}/interfaces/kits/c", ] - deps = [ "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client" ] + deps = [ + "${inputmethod_path}/common:inputmethod_common", + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client", + ] configs = [ "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability_native_public_config" ] @@ -90,7 +93,10 @@ ohos_static_library("ohinputmethod_static") { "${inputmethod_path}/interfaces/kits/c", ] - deps = [ "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static" ] + deps = [ + "${inputmethod_path}/common:inputmethod_common", + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static", + ] configs = [ "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:inputmethod_ability_native_public_config" ] diff --git a/frameworks/ndk/include/native_inputmethod_types.h b/frameworks/ndk/include/native_inputmethod_types.h index 909b83a4c130866dbe1403807787d87a8a17f539..e97ed8973fe2e2b691386b323b18831a3dc20225 100644 --- a/frameworks/ndk/include/native_inputmethod_types.h +++ b/frameworks/ndk/include/native_inputmethod_types.h @@ -18,6 +18,16 @@ #include #include "inputmethod_controller_capi.h" +constexpr int32_t MAX_PLACEHOLDER_SIZE = 255; // 255 utf-16 chars +constexpr int32_t MAX_ABILITY_NAME_SIZE = 127; // 127 utf-16 chars +// Maximum size of char16_t string, including the null terminator (0x0000). +// The range of one UTF16 encoded character is [1,2] char16_t. +constexpr size_t MAX_PLACEHOLDER_INPUT_SIZE = MAX_PLACEHOLDER_SIZE * 2 + 1; +// Maximum size of char16_t string, including the null terminator (0x0000). +constexpr size_t MAX_ABILITY_NAME_INPUT_SIZE = MAX_ABILITY_NAME_SIZE * 2 + 1; +constexpr char16_t UTF16_ENDING_SYMBOL = u'\0'; +constexpr size_t ENDING_SYMBOL_SIZE = 1; + struct InputMethod_PrivateCommand { std::string key; std::variant value; @@ -43,6 +53,10 @@ struct InputMethod_TextConfig { int32_t selectionStart; int32_t selectionEnd; int32_t windowId; + char16_t placeholder[MAX_PLACEHOLDER_INPUT_SIZE]; + size_t placeholderLength = 1; + char16_t abilityName[MAX_ABILITY_NAME_INPUT_SIZE]; + size_t abilityNameLength = 1; }; struct InputMethod_MessageHandlerProxy { diff --git a/frameworks/ndk/src/inputmethod_controller_capi.cpp b/frameworks/ndk/src/inputmethod_controller_capi.cpp index f7ff454313400d2872dafa0d802b241b63f6963d..436f08635a3d2ff761f94706854324937729ec81 100644 --- a/frameworks/ndk/src/inputmethod_controller_capi.cpp +++ b/frameworks/ndk/src/inputmethod_controller_capi.cpp @@ -133,7 +133,16 @@ static TextConfig ConstructTextConfig(const InputMethod_TextConfig &config) textConfig.windowId = config.windowId; textConfig.positionY = config.avoidInfo.positionY; textConfig.height = config.avoidInfo.height; - + auto placeholderLength = config.placeholderLength; + if (placeholderLength >0 && config.placeholder[placeholderLength - 1] == UTF16_ENDING_SYMBOL) { + placeholderLength = placeholderLength -1; + } + auto abilityNameLength = config.abilityNameLength; + if (abilityNameLength >0 && config.abilityName[abilityNameLength - 1] == UTF16_ENDING_SYMBOL) { + abilityNameLength = abilityNameLength - 1; + } + textConfig.inputAttribute.placeholder = std::u16string(config.placeholder, placeholderLength); + textConfig.inputAttribute.abilityName = std::u16string(config.abilityName, abilityNameLength); return textConfig; } diff --git a/frameworks/ndk/src/inputmethod_text_config_capi.cpp b/frameworks/ndk/src/inputmethod_text_config_capi.cpp index 9442a2f46cb330646de94bc9b155b2e6af8d8baa..7141cc791153bbbf865e064dc6ed836ce05f42af 100644 --- a/frameworks/ndk/src/inputmethod_text_config_capi.cpp +++ b/frameworks/ndk/src/inputmethod_text_config_capi.cpp @@ -12,12 +12,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "securec.h" + #include "global.h" #include "native_inputmethod_types.h" +#include "string_utils.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - +using namespace OHOS::MiscServices; InputMethod_TextConfig *OH_TextConfig_Create(void) { return new InputMethod_TextConfig(); @@ -82,6 +86,102 @@ InputMethod_ErrorCode OH_TextConfig_SetWindowId(InputMethod_TextConfig *config, return IME_ERR_OK; } +InputMethod_ErrorCode OH_TextConfig_SetPlaceholder(InputMethod_TextConfig *config, const char16_t *placeholder, + size_t length) +{ + if (config == nullptr) { + IMSA_HILOGE("config is nullptr"); + return IME_ERR_NULL_POINTER; + } + if (length <= 0 || placeholder == nullptr) { + config->placeholderLength = ENDING_SYMBOL_SIZE; + config->placeholder[0] = UTF16_ENDING_SYMBOL; + return IME_ERR_OK; + } + if (length == 1 && placeholder[length - 1] == UTF16_ENDING_SYMBOL) { + config->placeholderLength = ENDING_SYMBOL_SIZE; + config->placeholder[0] = UTF16_ENDING_SYMBOL; + return IME_ERR_OK; + } + if (length > MAX_PLACEHOLDER_INPUT_SIZE) { + IMSA_HILOGW("chars length exceeds limit inputLen:%{public}zu, limit len:%{public}zu", length, + MAX_PLACEHOLDER_INPUT_SIZE); + length = MAX_PLACEHOLDER_INPUT_SIZE; + } + std::u16string u16Placeholder(placeholder, length); + StringUtils::TruncateUtf16String(u16Placeholder, MAX_PLACEHOLDER_SIZE); + IMSA_HILOGD("memcpy_s begin dest len:%{public}zu, src len:%{public}zu", + MAX_PLACEHOLDER_INPUT_SIZE, u16Placeholder.size()); + if (u16Placeholder.size() > MAX_PLACEHOLDER_INPUT_SIZE) { + IMSA_HILOGE("function truncateUtf16String error"); + return IME_ERR_NULL_POINTER; + } + errno_t err = memcpy_s(config->placeholder, MAX_PLACEHOLDER_INPUT_SIZE * sizeof(char16_t), + u16Placeholder.data(), u16Placeholder.size() * sizeof(char16_t)); + if (err != EOK) { + IMSA_HILOGE("placeholder content copy error:%{public}d", (int32_t)err); + return IME_ERR_NULL_POINTER; + } + config->placeholderLength = u16Placeholder.size(); + if (config->placeholder[config->placeholderLength - 1] != UTF16_ENDING_SYMBOL && + config->placeholderLength < MAX_PLACEHOLDER_INPUT_SIZE) { + config->placeholder[config->placeholderLength] = UTF16_ENDING_SYMBOL; + config->placeholderLength = config->placeholderLength + 1; + } + IMSA_HILOGD("placeholderLength:%{public}zu,length:%{public}zu,lastChar16_t:%{public}u", + config->placeholderLength, length, + static_cast(config->placeholder[config->placeholderLength - 1])); + return IME_ERR_OK; +} + +InputMethod_ErrorCode OH_TextConfig_SetAbilityName(InputMethod_TextConfig *config, const char16_t *abilityName, + size_t length) +{ + if (config == nullptr) { + IMSA_HILOGE("config is nullptr"); + return IME_ERR_NULL_POINTER; + } + if (length <= 0 || abilityName == nullptr) { + config->abilityNameLength = ENDING_SYMBOL_SIZE; + config->abilityName[0] = UTF16_ENDING_SYMBOL; + return IME_ERR_OK; + } + if (length == 1 && abilityName[length - 1] == UTF16_ENDING_SYMBOL) { + config->abilityNameLength = ENDING_SYMBOL_SIZE; + config->abilityName[0] = UTF16_ENDING_SYMBOL; + return IME_ERR_OK; + } + if (length > MAX_ABILITY_NAME_INPUT_SIZE) { + IMSA_HILOGW("chars length exceeds limit inputLen:%{public}zu, limit len:%{public}zu", length, + MAX_ABILITY_NAME_INPUT_SIZE); + length = MAX_ABILITY_NAME_INPUT_SIZE; + } + std::u16string u16abilityName(abilityName, length); + StringUtils::TruncateUtf16String(u16abilityName, MAX_ABILITY_NAME_SIZE); + IMSA_HILOGD("memcpy_s begin dest len:%{public}zu, src len:%{public}zu", + MAX_ABILITY_NAME_INPUT_SIZE, u16abilityName.size()); + if (u16abilityName.size() > MAX_ABILITY_NAME_INPUT_SIZE) { + IMSA_HILOGE("function truncateUtf16String error"); + return IME_ERR_NULL_POINTER; + } + errno_t err = memcpy_s(config->abilityName, MAX_ABILITY_NAME_INPUT_SIZE * sizeof(char16_t), + u16abilityName.data(), u16abilityName.size() * sizeof(char16_t)); + if (err != EOK) { + IMSA_HILOGE("abilityName content copy error:%{public}d", (int32_t)err); + return IME_ERR_NULL_POINTER; + } + config->abilityNameLength = u16abilityName.size(); + if (config->abilityName[config->abilityNameLength - 1] != UTF16_ENDING_SYMBOL && + config->abilityNameLength < MAX_ABILITY_NAME_INPUT_SIZE) { + config->abilityName[config->abilityNameLength] = UTF16_ENDING_SYMBOL; + config->abilityNameLength = config->abilityNameLength + 1; + } + IMSA_HILOGD("abilityNameLength:%{public}zu,length:%{public}zu,lastChar16_t:%{public}u", + config->abilityNameLength, length, + static_cast(config->abilityName[config->abilityNameLength - 1])); + return IME_ERR_OK; +} + InputMethod_ErrorCode OH_TextConfig_GetInputType(InputMethod_TextConfig *config, InputMethod_TextInputType *inputType) { if (config == nullptr) { @@ -186,6 +286,80 @@ InputMethod_ErrorCode OH_TextConfig_GetWindowId(InputMethod_TextConfig *config, *windowId = config->windowId; return IME_ERR_OK; } + +InputMethod_ErrorCode OH_TextConfig_GetPlaceholder(InputMethod_TextConfig *config, char16_t *placeholder, + size_t *length) +{ + if (config == nullptr) { + IMSA_HILOGE("config is nullptr"); + return IME_ERR_NULL_POINTER; + } + if (length == nullptr) { + IMSA_HILOGE("length is nullptr"); + return IME_ERR_NULL_POINTER; + } + if (config->placeholderLength <= ENDING_SYMBOL_SIZE) { + config->placeholderLength = ENDING_SYMBOL_SIZE; + config->placeholder[0] = UTF16_ENDING_SYMBOL; + } + IMSA_HILOGD("curLen:%{public}zu,inputLen:%{public}zu", config->placeholderLength, *length); + if (placeholder == nullptr) { + IMSA_HILOGE("placeholder is nullptr"); + *length = config->placeholderLength; + return IME_ERR_NULL_POINTER; + } + if ((*length) < config->placeholderLength) { + IMSA_HILOGE("input memory is less than the length of the obtained memory. actual length:%{public}zu", + config->placeholderLength); + *length = config->placeholderLength; + return IME_ERR_PARAMCHECK; + } + auto byteLen = (*length) * sizeof(char16_t); + *length = config->placeholderLength; + errno_t err = memcpy_s(placeholder, byteLen, config->placeholder, config->placeholderLength * sizeof(char16_t)); + if (err != EOK) { + IMSA_HILOGE("placeholder content copy error:%{public}d", (int32_t)err); + return IME_ERR_PARAMCHECK; + } + return IME_ERR_OK; +} + +InputMethod_ErrorCode OH_TextConfig_GetAbilityName(InputMethod_TextConfig *config, char16_t *abilityName, + size_t *length) +{ + if (config == nullptr) { + IMSA_HILOGE("config is nullptr"); + return IME_ERR_NULL_POINTER; + } + if (length == nullptr) { + IMSA_HILOGE("length is nullptr"); + return IME_ERR_NULL_POINTER; + } + if (abilityName == nullptr) { + IMSA_HILOGE("abilityName is nullptr"); + *length = config->abilityNameLength; + return IME_ERR_NULL_POINTER; + } + if (config->abilityNameLength <= ENDING_SYMBOL_SIZE) { + config->abilityNameLength = ENDING_SYMBOL_SIZE; + config->abilityName[0] = UTF16_ENDING_SYMBOL; + } + IMSA_HILOGD("curLen:%{public}zu,inputLen:%{public}zu", config->abilityNameLength, *length); + if ((*length) < config->abilityNameLength) { + IMSA_HILOGE("input memory is less than the length of the obtained memory. actual length:%{public}zu", + config->abilityNameLength); + *length = config->abilityNameLength; + return IME_ERR_PARAMCHECK; + } + auto byteLen = (*length) * sizeof(char16_t); + *length = config->abilityNameLength; + errno_t err = memcpy_s(abilityName, byteLen, config->abilityName, config->abilityNameLength * sizeof(char16_t)); + if (err != EOK) { + IMSA_HILOGE("abilityName content copy error:%{public}d", (int32_t)err); + return IME_ERR_PARAMCHECK; + } + return IME_ERR_OK; +} #ifdef __cplusplus } #endif /* __cplusplus */ \ No newline at end of file diff --git a/interfaces/inner_api/inputmethod_ability/include/input_method_engine_listener.h b/interfaces/inner_api/inputmethod_ability/include/input_method_engine_listener.h index 21cdfa4fe44d2b970b0dff1636dc6322134a8972..ffdb16f61bb5b1ac657a3a461b91684d53ec32a7 100644 --- a/interfaces/inner_api/inputmethod_ability/include/input_method_engine_listener.h +++ b/interfaces/inner_api/inputmethod_ability/include/input_method_engine_listener.h @@ -27,6 +27,10 @@ public: virtual void OnKeyboardStatus(bool isShow) = 0; virtual void OnInputStart() = 0; virtual int32_t OnInputStop() = 0; + virtual int32_t OnDiscardTypingText() + { + return ErrorCode::NO_ERROR; + } virtual void OnSecurityChange(int32_t security) { }; @@ -40,6 +44,10 @@ public: { return false; } + virtual bool IsCallbackRegistered(const std::string &type) + { + return false; + } virtual bool PostTaskToEventHandler(std::function task, const std::string &taskName) { return false; diff --git a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h index 9db094f7b7b4cf089447642b042a81edb2f1331d..0c36b843a957d6b8b87658d74fcd5e0ecfa6a87f 100644 --- a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h +++ b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h @@ -260,6 +260,14 @@ public: */ IMF_API int32_t OnCursorUpdate(CursorInfo cursorInfo); + /** + * @brief Discard the typing text. + * + * @return Returns 0 for success, others for failure. + * @since 16 + */ + IMF_API int32_t DiscardTypingText(); + /** * @brief A callback function when the cursor changes. * diff --git a/interfaces/kits/c/inputmethod_text_config_capi.h b/interfaces/kits/c/inputmethod_text_config_capi.h index e7d5a136a91a2909e242a84c712777591637175b..2ae2ca057b4ed862a7ba7e42720c3412909f1956 100644 --- a/interfaces/kits/c/inputmethod_text_config_capi.h +++ b/interfaces/kits/c/inputmethod_text_config_capi.h @@ -35,6 +35,7 @@ * @version 1.0 */ #include +#include #include "inputmethod_cursor_info_capi.h" #include "inputmethod_text_avoid_info_capi.h" @@ -131,6 +132,46 @@ InputMethod_ErrorCode OH_TextConfig_SetSelection(InputMethod_TextConfig *config, */ InputMethod_ErrorCode OH_TextConfig_SetWindowId(InputMethod_TextConfig *config, int32_t windowId); +/** + * @brief Sets the placeholder text of an InputMethod_TextConfig instance. + * + * @param config Pointer to the InputMethod_TextConfig instance. + * @param placeholder Pointer to a UTF-16 encoded double-byte string. If a null pointer is passed, the placeholder text + * is an empty string. + * @param length Number of elements in the memory to which placeholder points, including the null character of + * the double-byte string. + * 1) If length is 0, the placeholder text is an empty string. + * 2) The maximum number of UTF-16 encoded characters is 256, and the last element must be a null character. + * 3) If the length exceeds 256, the placeholder text will be truncated. + * @return Returns a specific error code. + * {@link IME_ERR_OK} - success. + * {@link IME_ERR_NULL_POINTER} - unexpected null pointer. + * Specific error codes can be referenced {@link InputMethod_ErrorCode}. + * @since 20 + */ +InputMethod_ErrorCode OH_TextConfig_SetPlaceholder(InputMethod_TextConfig *config, const char16_t *placeholder, + size_t length); + +/** + * @brief Sets the ability name of an InputMethod_TextConfig instance. + * + * @param config Pointer to the InputMethod_TextConfig instance. + * @param abilityName Pointer to a UTF-16 encoded double-byte string. If a null pointer is passed, the ability name is + * an empty string. + * @param length Number of elements in the memory to which abilityName points, including the null character of +* the double-byte string. + * 1) If length is 0, the ability name is an empty string. + * 2) The maximum number of UTF-16 encoded characters is 128, and the last element must be a null character. + * 3) If the length exceeds 128, the placeholder text will be truncated. + * @return Returns a specific error code. + * {@link IME_ERR_OK} - success. + * {@link IME_ERR_NULL_POINTER} - unexpected null pointer. + * Specific error codes can be referenced {@link InputMethod_ErrorCode}. + * @since 20 + */ +InputMethod_ErrorCode OH_TextConfig_SetAbilityName(InputMethod_TextConfig *config, const char16_t *abilityName, + size_t length); + /** * @brief Get input type from TextConfig * @@ -139,6 +180,7 @@ InputMethod_ErrorCode OH_TextConfig_SetWindowId(InputMethod_TextConfig *config, * The text input type of text Editor * @return Returns a specific error code. * {@link IME_ERR_OK} - success. + * {@link IME_ERR_PARAMCHECK} - parameter check failed. * {@link IME_ERR_NULL_POINTER} - unexpected null pointer. * Specific error codes can be referenced {@link InputMethod_ErrorCode}. * @since 12 @@ -210,6 +252,7 @@ InputMethod_ErrorCode OH_TextConfig_GetTextAvoidInfo( * @since 12 */ InputMethod_ErrorCode OH_TextConfig_GetSelection(InputMethod_TextConfig *config, int32_t *start, int32_t *end); + /** * @brief Get window id from TextConfig. * @@ -222,6 +265,54 @@ InputMethod_ErrorCode OH_TextConfig_GetSelection(InputMethod_TextConfig *config, * @since 12 */ InputMethod_ErrorCode OH_TextConfig_GetWindowId(InputMethod_TextConfig *config, int32_t *windowId); + +/** + * @brief Obtains the placeholder text of an InputMethod_TextConfig instance. + * + * @param config Pointer to the InputMethod_TextConfig instance. + * @param placeholder Pointer to the placeholder text. The memory of this pointer is maintained by the caller. + * @param length Pointer to the length of the placeholder text, in double bytes. The length includes the null character + * of the string. + * 1) As an input parameter, length indicates the available length of the memory to which placeholder + * points. As an output parameter, it indicates the actual length of the placeholder text. + * 2) If placeholder is a null pointer and length points to valid memory, length will be set to + * the actual length of the placeholder text, and an error will be return. + * 3) If both placeholder and length point to valid memory, but the value of length is less + * than the actual length of the placeholder text, length will be set to the actual length of the + * placeholder text, and an error will be return. + * @return Returns a specific error code. + * {@link IME_ERR_OK} - success. + * {@link IME_ERR_PARAMCHECK} - parameter check failed. + * {@link IME_ERR_NULL_POINTER} - unexpected null pointer. + * Specific error codes can be referenced {@link InputMethod_ErrorCode}. + * @since 20 + */ +InputMethod_ErrorCode OH_TextConfig_GetPlaceholder(InputMethod_TextConfig *config, char16_t *placeholder, + size_t *length); + +/** + * @brief Obtains the ability name of an InputMethod_TextConfig instance. + * + * @param config Pointer to the InputMethod_TextConfig instance. + * @param abilityName Pointer to the ability name. The memory of this pointer is maintained by the caller. + * @param length Pointer to the length of the ability name, in double bytes. The length includes the null character of + * the string. + * 1) As an input parameter, length indicates the available length of the memory to which abilityName + * points. As an output parameter, it indicates the actual length of the ability name. + * 2) If abilityName is a null pointer and length points to valid memory, length will be set to + * the actual length of the ability name, and an error will be return. + * 3) If both abilityName and length point to valid memory, but the value of length is less + * than the actual length of the ability name, length will be set to the actual length of the ability + * name, and an error will be return. + * @return Returns a specific error code. + * {@link IME_ERR_OK} - success. + * {@link IME_ERR_PARAMCHECK} - parameter check failed. + * {@link IME_ERR_NULL_POINTER} - unexpected null pointer. + * Specific error codes can be referenced {@link InputMethod_ErrorCode}. + * @since 20 + */ +InputMethod_ErrorCode OH_TextConfig_GetAbilityName(InputMethod_TextConfig *config, char16_t *abilityName, + size_t *length); #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/interfaces/kits/c/inputmethod_types_capi.h b/interfaces/kits/c/inputmethod_types_capi.h index cde9f352581f8c67e6b56e8c7b964c0f90a6ebc5..0a8a4e3b50b8cdafcb73bae041470ec1314796d3 100644 --- a/interfaces/kits/c/inputmethod_types_capi.h +++ b/interfaces/kits/c/inputmethod_types_capi.h @@ -215,6 +215,10 @@ typedef enum InputMethod_TextInputType { * The text input type is NUMBER DECIMAL. */ IME_TEXT_INPUT_TYPE_NUMBER_DECIMAL = 12, + /** + * The text input type is ONE TIME CODE. + */ + IME_TEXT_INPUT_TYPE_ONE_TIME_CODE = 13, } InputMethod_TextInputType; /** diff --git a/services/include/input_method_system_ability.h b/services/include/input_method_system_ability.h index d98978ecbc739dca604f3ce1fd86f4243be39d7c..3c2601d6a7909b3b8057e05abb82463afe8ccf58 100644 --- a/services/include/input_method_system_ability.h +++ b/services/include/input_method_system_ability.h @@ -172,7 +172,7 @@ private: bool IsCurrentIme(int32_t userId); 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, bool &needHide); + void NeedHideWhenSwitchInputType(int32_t userId, InputType type, bool &needHide); bool GetDeviceFunctionKeyState(int32_t functionKey, bool &isEnable); bool ModifyImeCfgWithWrongCaps(); void HandleBundleScanFinished(); @@ -183,6 +183,8 @@ private: std::pair GetCurrentImeInfoForHiSysEvent(int32_t userId); int32_t GetScreenLockIme(int32_t userId, std::string &ime); int32_t GetAlternativeIme(int32_t userId, std::string &ime); + static InputType GetSecurityInputType(const InputClientInfo &inputClientInfo); + int32_t StartSecurityIme(int32_t &userId, InputClientInfo &inputClientInfo); #ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE int64_t GetTickCount(); void ResetDelayUnloadTask(uint32_t code = 0); diff --git a/services/include/input_type_manager.h b/services/include/input_type_manager.h index 7a2a2374c5fb94de288d7e0752bf89ddd77f216a..d8032a4b0cb1650ee75adc0d3580d707c36a515d 100644 --- a/services/include/input_type_manager.h +++ b/services/include/input_type_manager.h @@ -47,6 +47,8 @@ public: bool IsCameraImeStarted(); bool IsVoiceImeStarted(); bool IsVoiceKbImeStarted(); + bool IsOneTimeCodeImeStarted(); + bool IsInputTypeImeStarted(InputType type); InputType GetCurrentInputType(); void Set(bool isStarted, const ImeIdentification ¤tIme = {}); ImeIdentification GetCurrentIme(); diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index 8784d0e104e800cd400dec0572e952675a5269c4..5d502e2852a0b9ae961742af9ac71f60b5daf3f8 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -658,28 +658,12 @@ int32_t InputMethodSystemAbility::StartInputInner( int32_t InputMethodSystemAbility::CheckInputTypeOption(int32_t userId, InputClientInfo &inputClientInfo) { - IMSA_HILOGI("SecurityFlag: %{public}d, IsSameTextInput: %{public}d, IsStarted: %{public}d, " - "IsSecurityImeStarted: %{public}d.", - inputClientInfo.config.inputAttribute.GetSecurityFlag(), !inputClientInfo.isNotifyInputStart, - InputTypeManager::GetInstance().IsStarted(), InputTypeManager::GetInstance().IsSecurityImeStarted()); - if (inputClientInfo.config.inputAttribute.GetSecurityFlag()) { - if (!InputTypeManager::GetInstance().IsStarted()) { - IMSA_HILOGD("SecurityFlag, input type is not started, start."); - // if need to switch ime, no need to hide panel first. - NeedHideWhenSwitchInputType(userId, inputClientInfo.needHide); - return StartInputType(userId, InputType::SECURITY_INPUT); - } - if (!inputClientInfo.isNotifyInputStart) { - IMSA_HILOGD("SecurityFlag, same textField, input type is started, not deal."); - return ErrorCode::NO_ERROR; - } - if (!InputTypeManager::GetInstance().IsSecurityImeStarted()) { - IMSA_HILOGD("SecurityFlag, new textField, input type is started, but it is not security, switch."); - NeedHideWhenSwitchInputType(userId, inputClientInfo.needHide); - return StartInputType(userId, InputType::SECURITY_INPUT); - } - IMSA_HILOGD("SecurityFlag, other condition, not deal."); - return ErrorCode::NO_ERROR; + IMSA_HILOGI("SecurityImeFlag: %{public}d, IsSameTextInput: %{public}d, IsStarted: %{public}d.", + inputClientInfo.config.inputAttribute.IsSecurityImeFlag(), + !inputClientInfo.isNotifyInputStart, + InputTypeManager::GetInstance().IsStarted()); + if (inputClientInfo.config.inputAttribute.IsSecurityImeFlag()) { + return StartSecurityIme(userId, inputClientInfo); } if (!inputClientInfo.isNotifyInputStart) { IMSA_HILOGD("NormalFlag, same textField, not deal."); @@ -2281,7 +2265,7 @@ int32_t InputMethodSystemAbility::StartInputType(int32_t userId, InputType type) if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGW("not find input type: %{public}d.", type); // add for not adapter for SECURITY_INPUT - if (type == InputType::SECURITY_INPUT) { + if (type == InputType::SECURITY_INPUT || type == InputType::ONE_TIME_CODE) { return session->RestoreCurrentIme(DEFAULT_DISPLAY_ID); } return ret; @@ -2289,20 +2273,30 @@ int32_t InputMethodSystemAbility::StartInputType(int32_t userId, InputType type) SwitchInfo switchInfo = { std::chrono::system_clock::now(), ime.bundleName, ime.subName }; session->GetSwitchQueue().Push(switchInfo); IMSA_HILOGI("start input type: %{public}d.", type); - return type == InputType::SECURITY_INPUT ? OnStartInputType(userId, switchInfo, false) - : OnStartInputType(userId, switchInfo, true); + return (type == InputType::SECURITY_INPUT || type == InputType::ONE_TIME_CODE) ? + OnStartInputType(userId, switchInfo, false) : OnStartInputType(userId, switchInfo, true); } -void InputMethodSystemAbility::NeedHideWhenSwitchInputType(int32_t userId, bool &needHide) +void InputMethodSystemAbility::NeedHideWhenSwitchInputType(int32_t userId, InputType type, bool &needHide) { + if (!needHide) { + return; + } ImeIdentification ime; - InputTypeManager::GetInstance().GetImeByInputType(InputType::SECURITY_INPUT, ime); - auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId); - if (currentImeCfg == nullptr) { - IMSA_HILOGI("currentImeCfg is nullptr"); + InputTypeManager::GetInstance().GetImeByInputType(type, ime); + auto session = UserSessionManager::GetInstance().GetUserSession(userId); + if (session == nullptr) { + IMSA_HILOGE("UserId: %{public}d session is nullptr!", userId_); + needHide = false; + return; + } + auto imeData = session->GetReadyImeData(ImeType::IME); + if (imeData == nullptr) { + IMSA_HILOGI("Readyime is nullptr"); + needHide = false; return; } - needHide = currentImeCfg->bundleName == ime.bundleName; + needHide = imeData->ime.first == ime.bundleName; } void InputMethodSystemAbility::HandleBundleScanFinished() @@ -2537,5 +2531,38 @@ int32_t InputMethodSystemAbility::SendPrivateData( } return ret; } + +InputType InputMethodSystemAbility::GetSecurityInputType(const InputClientInfo &inputClientInfo) +{ + if (inputClientInfo.config.inputAttribute.IsOneTimeCodeFlag()) { + return InputType::ONE_TIME_CODE; + } else if (inputClientInfo.config.inputAttribute.GetSecurityFlag()) { + return InputType::SECURITY_INPUT; + } else { + return InputType::NONE; + } +} + +int32_t InputMethodSystemAbility::StartSecurityIme(int32_t &userId, InputClientInfo &inputClientInfo) +{ + InputType type = GetSecurityInputType(inputClientInfo); + IMSA_HILOGI("InputType:[%{public}d.", type); + if (!InputTypeManager::GetInstance().IsStarted()) { + IMSA_HILOGD("SecurityImeFlag, input type is not started, start."); + // if need to switch ime, no need to hide panel first. + NeedHideWhenSwitchInputType(userId, type, inputClientInfo.needHide); + return StartInputType(userId, type); + } + if (!inputClientInfo.isNotifyInputStart) { + IMSA_HILOGD("SecurityImeFlag, same textField, input type is started, not deal."); + return ErrorCode::NO_ERROR; + } + if (!InputTypeManager::GetInstance().IsInputTypeImeStarted(type)) { + IMSA_HILOGD("SecurityImeFlag, new textField, input type is started, but it is not target, switch."); + NeedHideWhenSwitchInputType(userId, type, inputClientInfo.needHide); + return StartInputType(userId, type); + } + return ErrorCode::NO_ERROR; +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/services/src/input_type_manager.cpp b/services/src/input_type_manager.cpp index 81f236ae6695109dd5b873503155d159ce111704..039dec749b0a99dd4beec94d2f9036dbfac9f977 100644 --- a/services/src/input_type_manager.cpp +++ b/services/src/input_type_manager.cpp @@ -76,46 +76,43 @@ bool InputTypeManager::IsStarted() bool InputTypeManager::IsSecurityImeStarted() { - if (!IsStarted()) { - return false; - } - + InputType type = InputType::SECURITY_INPUT; + return IsInputTypeImeStarted(type); std::lock_guard lock(typesLock_); - return inputTypes_.find(InputType::SECURITY_INPUT) != inputTypes_.end() && - inputTypes_[InputType::SECURITY_INPUT] == GetCurrentIme(); } bool InputTypeManager::IsCameraImeStarted() { - if (!IsStarted()) { - return false; - } - - std::lock_guard lock(typesLock_); - return inputTypes_.find(InputType::CAMERA_INPUT) != inputTypes_.end() && - inputTypes_[InputType::CAMERA_INPUT] == GetCurrentIme(); + InputType type = InputType::CAMERA_INPUT; + return IsInputTypeImeStarted(type); } bool InputTypeManager::IsVoiceImeStarted() { - if (!IsStarted()) { - return false; - } - - std::lock_guard lock(typesLock_); - return inputTypes_.find(InputType::VOICE_INPUT) != inputTypes_.end() && - inputTypes_[InputType::VOICE_INPUT] == GetCurrentIme(); + InputType type = InputType::VOICE_INPUT; + return IsInputTypeImeStarted(type); } bool InputTypeManager::IsVoiceKbImeStarted() +{ + InputType type = InputType::VOICEKB_INPUT; + return IsInputTypeImeStarted(type); +} + +bool InputTypeManager::IsOneTimeCodeImeStarted() +{ + InputType type = InputType::ONE_TIME_CODE; + return IsInputTypeImeStarted(type); +} + +bool InputTypeManager::IsInputTypeImeStarted(InputType type) { if (!IsStarted()) { return false; } - std::lock_guard lock(typesLock_); - return inputTypes_.find(InputType::VOICEKB_INPUT) != inputTypes_.end() && - inputTypes_[InputType::VOICEKB_INPUT] == GetCurrentIme(); + return inputTypes_.find(type) != inputTypes_.end() && + inputTypes_[type] == GetCurrentIme(); } InputType InputTypeManager::GetCurrentInputType() @@ -132,6 +129,9 @@ InputType InputTypeManager::GetCurrentInputType() if (IsVoiceKbImeStarted()) { return InputType::VOICEKB_INPUT; } + if (IsOneTimeCodeImeStarted()) { + return InputType::ONE_TIME_CODE; + } return InputType::NONE; } diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp index 77cf33b154b0fd84d099df758d866040aa1a88b8..6ce22ce11d624619b2f4911bbdd9a56068f23823 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -2141,7 +2141,7 @@ bool PerUserSession::SpecialScenarioCheck() IMSA_HILOGE("send failed, not input Status!"); return false; } - if (clientInfo->config.inputAttribute.GetSecurityFlag()) { + if (clientInfo->config.inputAttribute.IsSecurityImeFlag()) { IMSA_HILOGE("send failed, is special input box!"); return false; } diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 3fe4ec7a865c4286393d0b242b4f29d3e3a5ee16..eee417974ad0d862be4ffd918d0858d64b277a40 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -45,6 +45,7 @@ group("unittest") { "cpp_test:JsonOperateTest", "cpp_test:NewImeSwitchTest", "cpp_test:OnDemandStartStopSaTest", + "cpp_test:StringUtilsTest", "cpp_test:TaskManagerTest", "cpp_test:TextListenerInnerApiTest", "cpp_test:VirtualListenerTest", diff --git a/test/unittest/cpp_test/BUILD.gn b/test/unittest/cpp_test/BUILD.gn index 76855dc51b23facb145418e227d5aefa7e399176..9d47bfab7849adf4d89d720c1d66c0f821ddc63f 100644 --- a/test/unittest/cpp_test/BUILD.gn +++ b/test/unittest/cpp_test/BUILD.gn @@ -1512,3 +1512,27 @@ ohos_unittest("ImeEnabledInfoManagerTest") { cflags = [ "-DWITH_SELINUX" ] } } + +ohos_unittest("StringUtilsTest") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + module_out_path = module_output_path + + include_dirs = [ "${inputmethod_path}/common/include" ] + + sources = [ "src/string_utils_test.cpp" ] + + configs = [ ":module_private_config" ] + + deps = [ "${inputmethod_path}/common:inputmethod_common" ] + + external_deps = [ + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + ] +} diff --git a/test/unittest/cpp_test/src/ime_proxy_test.cpp b/test/unittest/cpp_test/src/ime_proxy_test.cpp index 41346d9a4533190c9dd95d729e2ee443e5d7e946..c5b91f4c7b8fdf78c7d6d6cbe53a6cdcf1532fab 100644 --- a/test/unittest/cpp_test/src/ime_proxy_test.cpp +++ b/test/unittest/cpp_test/src/ime_proxy_test.cpp @@ -656,5 +656,17 @@ HWTEST_F(ImeProxyTest, testIsFromTs, TestSize.Level0) bool isFrom = testListener->IsFromTs(); EXPECT_FALSE(isFrom); } + +/** + * @tc.name: DiscardTypingTextTest + * @tc.desc: DiscardTypingText + * @tc.type: FUNC + */ +HWTEST_F(ImeProxyTest, DiscardTypingTextTest, TestSize.Level0) +{ + IMSA_HILOGI("ImeProxyTest::DiscardTypingTextTest"); + auto ret = InputMethodAbility::GetInstance().OnDiscardTypingText(); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); +} } // namespace MiscServices } // namespace OHOS diff --git a/test/unittest/cpp_test/src/input_method_ability_test.cpp b/test/unittest/cpp_test/src/input_method_ability_test.cpp index 943add529460c4ed550cc26b263d7bdef88da7f0..67408d36b6106ed40679e8ba3099fa355942b97f 100644 --- a/test/unittest/cpp_test/src/input_method_ability_test.cpp +++ b/test/unittest/cpp_test/src/input_method_ability_test.cpp @@ -287,6 +287,28 @@ HWTEST_F(InputMethodAbilityTest, testSerializedInputAttribute, TestSize.Level0) EXPECT_TRUE(attribute->GetSecurityFlag()); } +/** + * @tc.name: testSerializedInputAttribute001 + * @tc.desc: Checkout the serialization of InputAttribute. + * @tc.type: FUNC + */ +HWTEST_F(InputMethodAbilityTest, testSerializedInputAttribute001, TestSize.Level0) +{ + InputAttributeInner inAttribute; + inAttribute.inputPattern = InputAttribute::PATTERN_ONE_TIME_CODE; + Parcel data; + EXPECT_TRUE(inAttribute.Marshalling(data)); + InputAttributeInner* outInnerAttribute = InputAttributeInner::Unmarshalling(data); + if (outInnerAttribute == nullptr) { + return; + } + InputAttribute outAttribute; + outAttribute.inputPattern = outInnerAttribute->inputPattern; + EXPECT_TRUE(outAttribute.IsSecurityImeFlag()); + EXPECT_TRUE(outAttribute.IsOneTimeCodeFlag()); + delete outInnerAttribute; +} + /** * @tc.name: testSerializedInputAttribute * @tc.desc: Checkout the serialization of InputAttribute. @@ -361,6 +383,19 @@ HWTEST_F(InputMethodAbilityTest, testHideKeyboardWithoutImeListener, TestSize.Le EXPECT_EQ(ret, ErrorCode::NO_ERROR); } +/** + * @tc.name: testDiscardTypingTextWithoutImeListener + * @tc.desc: InputMethodAbility DiscardTypingText without imeListener + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(InputMethodAbilityTest, testDiscardTypingTextWithoutImeListener, TestSize.Level0) +{ + IMSA_HILOGI("InputMethodAbilityTest testDiscardTypingTextWithoutImeListener start."); + auto ret = inputMethodAbility_.OnDiscardTypingText(); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); +} + /** * @tc.name: testStartInputWithoutPanel * @tc.desc: InputMethodAbility StartInput Without Panel @@ -1617,6 +1652,7 @@ HWTEST_F(InputMethodAbilityTest, BranchCoverage002, TestSize.Level0) std::string vailidString = ""; std::shared_ptr info; bool needHide = false; + InputType type = InputType::NONE; auto ret = imsa_->OnStartInputType(vailidUserId, switchInfo, true); EXPECT_NE(ret, ErrorCode::NO_ERROR); @@ -1625,7 +1661,7 @@ HWTEST_F(InputMethodAbilityTest, BranchCoverage002, TestSize.Level0) ret = imsa_->SwitchExtension(vailidUserId, info); EXPECT_EQ(ret, ErrorCode::ERROR_NULL_POINTER); ret = imsa_->SwitchSubType(vailidUserId, info); - imsa_->NeedHideWhenSwitchInputType(vailidUserId, needHide); + imsa_->NeedHideWhenSwitchInputType(vailidUserId, type, needHide); EXPECT_EQ(ret, ErrorCode::ERROR_NULL_POINTER); ret = imsa_->SwitchInputType(vailidUserId, switchInfo); EXPECT_EQ(ret, ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND); diff --git a/test/unittest/cpp_test/src/input_method_controller_test.cpp b/test/unittest/cpp_test/src/input_method_controller_test.cpp index 32d69dd37467bfa8c6a368c1ada162f8b4066147..fe63a538fcb8f509a79f5c75b469e494f8d4b052 100644 --- a/test/unittest/cpp_test/src/input_method_controller_test.cpp +++ b/test/unittest/cpp_test/src/input_method_controller_test.cpp @@ -594,6 +594,24 @@ HWTEST_F(InputMethodControllerTest, testIMCSetCallingWindow, TestSize.Level0) EXPECT_EQ(windowId, imeListener_->windowId_); } +/** + * @tc.name: testIMCDiscardTypingText + * @tc.desc: IMC DiscardTypingText. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(InputMethodControllerTest, testIMCDiscardTypingText, TestSize.Level0) +{ + IMSA_HILOGI("IMC DiscardTypingText Test START"); + InputMethodControllerTest::inputMethodController_->Close(); + auto ret = inputMethodController_->DiscardTypingText(); + EXPECT_EQ(ret, ErrorCode::ERROR_CLIENT_NOT_BOUND); + ret = inputMethodController_->Attach(textListener_); + EXPECT_EQ(ret, ErrorCode::NO_ERROR); + ret = inputMethodController_->DiscardTypingText(); + EXPECT_GE(ret, ErrorCode::NO_ERROR); +} + /** * @tc.name: testGetIMSAProxy * @tc.desc: Get Imsa Proxy. 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 f89db1d0e2df4adba98a7053b4c86051c0ffe977..d4a29a920b12220c3bd0d1a34aeb0e091af17118 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 @@ -1342,8 +1342,9 @@ HWTEST_F(InputMethodPrivateMemberTest, BranchCoverage002, TestSize.Level0) EXPECT_EQ(ret2, ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND); bool needHide = false; + InputType type = InputType::NONE; auto ret3 = service_->IsCurrentIme(INVALID_USER_ID); - service_->NeedHideWhenSwitchInputType(INVALID_USER_ID, needHide); + service_->NeedHideWhenSwitchInputType(INVALID_USER_ID, type, needHide); EXPECT_FALSE(ret3); } diff --git a/test/unittest/cpp_test/src/inputmethod_controller_capi_test.cpp b/test/unittest/cpp_test/src/inputmethod_controller_capi_test.cpp index a74ff2b25c3a6e8de1175539cc1b3dbcd217f5b6..4a914cee2d1ebece54fa9163a80a6f81af9decb6 100644 --- a/test/unittest/cpp_test/src/inputmethod_controller_capi_test.cpp +++ b/test/unittest/cpp_test/src/inputmethod_controller_capi_test.cpp @@ -12,10 +12,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "inputmethod_controller_capi.h" #include +#include "string_ex.h" + +#include "global.h" +#include "native_inputmethod_types.h" + using namespace testing::ext; +using namespace OHOS; class InputMethodControllerCapiTest : public testing::Test { }; namespace { /** @@ -144,6 +149,26 @@ HWTEST_F(InputMethodControllerCapiTest, TestTextConfig_001, TestSize.Level0) OH_TextConfig_Destroy(config); } + +/** + * @tc.name: TestTextConfig_002 + * @tc.desc: create and destroy TestTextConfig success + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, TestTextConfig_002, TestSize.Level0) +{ + auto config = OH_TextConfig_Create(); + ASSERT_NE(nullptr, config); + + // test set and get inputType + InputMethod_TextInputType expInputType = IME_TEXT_INPUT_TYPE_ONE_TIME_CODE; + InputMethod_TextInputType actInputType = IME_TEXT_INPUT_TYPE_NONE; + EXPECT_EQ(IME_ERR_OK, OH_TextConfig_SetInputType(config, expInputType)); + EXPECT_EQ(IME_ERR_OK, OH_TextConfig_GetInputType(config, &actInputType)); + EXPECT_EQ(expInputType, actInputType); + OH_TextConfig_Destroy(config); +} + void GetTextConfigFunc(InputMethod_TextEditorProxy *proxy, InputMethod_TextConfig *config) { } void InsertTextFunc(InputMethod_TextEditorProxy *proxy, const char16_t *text, size_t length) { } void DeleteForwardFunc(InputMethod_TextEditorProxy *proxy, int32_t length) { } @@ -1513,4 +1538,268 @@ HWTEST_F(InputMethodControllerCapiTest, TestAttachWithNorrmalParam_001, TestSize OH_AttachOptions_Destroy(options); OH_TextEditorProxy_Destroy(textEditorProxy); } + +/** + * @tc.name: TestAttachWithPlaceholderAndAbility_001 + * @tc.desc: the input parameter contains the placeholder and ability name + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, TestAttachWithPlaceholderAndAbility_001, TestSize.Level0) +{ + auto options = OH_AttachOptions_Create(true); + auto textEditorProxy2 = OH_TextEditorProxy_Create(); + EXPECT_NE(nullptr, textEditorProxy2); + ConstructTextEditorProxy(textEditorProxy2); + auto fnGetTextConfigFunc = [](InputMethod_TextEditorProxy *textEditorProxy, + InputMethod_TextConfig *config) { + std::u16string placeholder = u"test placeholder"; + std::u16string abilityName = u"test ability name"; + OH_TextConfig_SetPlaceholder(config, placeholder.data(), placeholder.size()); + OH_TextConfig_SetAbilityName(config, abilityName.data(), abilityName.size()); + }; + OH_TextEditorProxy_SetGetTextConfigFunc(textEditorProxy2, fnGetTextConfigFunc); + InputMethod_InputMethodProxy *inputMethodProxy = nullptr; + auto ret = OH_InputMethodController_Attach(textEditorProxy2, options, &inputMethodProxy); + EXPECT_NE(ret, IME_ERR_OK); + OH_TextEditorProxy_Destroy(textEditorProxy2); + OH_AttachOptions_Destroy(options); +} + +/** + * @tc.name: OH_TextConfig_SetPlaceholder_001 + * @tc.desc: Input parameters are valid + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, OH_TextConfig_SetPlaceholder_001, TestSize.Level0) +{ + auto config = OH_TextConfig_Create(); + ASSERT_NE(nullptr, config); + std::u16string input= u"test"; + auto ret = OH_TextConfig_SetPlaceholder(config, input.data(), input.size()); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_GetPlaceholder(nullptr, nullptr, nullptr); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + ret = OH_TextConfig_GetPlaceholder(config, nullptr, nullptr); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + size_t outLen = 513; + char16_t pOut[513] = {}; + ret = OH_TextConfig_GetPlaceholder(config, pOut, nullptr); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + outLen = 1; + ret = OH_TextConfig_GetPlaceholder(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_PARAMCHECK); + EXPECT_EQ(outLen -1, input.size()); + outLen = 513; + ret = OH_TextConfig_GetPlaceholder(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + EXPECT_EQ(outLen -1, input.size()); + outLen = input.size(); + ret = OH_TextConfig_GetPlaceholder(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_PARAMCHECK); + std::u16string out(pOut, outLen); + EXPECT_GT(out.size(), input.size()); + outLen = 4; + ret = OH_TextConfig_GetPlaceholder(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_PARAMCHECK); + OH_TextConfig_Destroy(config); +} + +/** + * @tc.name: OH_TextConfig_SetPlaceholder_002 + * @tc.desc: Invalid test input parameter + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, OH_TextConfig_SetPlaceholder_002, TestSize.Level0) { + auto config = OH_TextConfig_Create(); + ASSERT_NE(nullptr, config); + std::u16string input= u"test"; + auto ret = OH_TextConfig_SetPlaceholder(config, input.data(), input.size()); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_SetPlaceholder(config, nullptr, 0); + EXPECT_EQ(ret, IME_ERR_OK); + size_t outLen = 512; + char16_t pOut[512] = {}; + ret = OH_TextConfig_GetPlaceholder(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + EXPECT_EQ(outLen, 1); + OH_TextConfig_Destroy(config); +} + +/** + * @tc.name: OH_TextConfig_SetPlaceholder_003 + * @tc.desc: Invalid test input parameter + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, OH_TextConfig_SetPlaceholder_003, TestSize.Level0) { + auto config = OH_TextConfig_Create(); + ASSERT_NE(nullptr, config); + auto ret = OH_TextConfig_SetPlaceholder(config, nullptr, 257); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_SetPlaceholder(config, nullptr, 1); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_SetPlaceholder(nullptr, nullptr, 1); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + std::u16string input = u""; + for (int i = 0; i < MAX_PLACEHOLDER_SIZE; ++i) { + input.append(u"𪛊"); + } + IMSA_HILOGI("inputLen:%{public}zu,input:%{public}s", input.size(), Str16ToStr8(input).c_str()); + ret = OH_TextConfig_SetPlaceholder(config, input.data(), input.size()); + EXPECT_EQ(ret, IME_ERR_OK); + std::u16string out(MAX_PLACEHOLDER_INPUT_SIZE, u'\0'); + size_t outLen = out.size(); + ret = OH_TextConfig_GetPlaceholder(config, out.data(), &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + EXPECT_EQ(out.size(), outLen); + EXPECT_EQ(out[out.size() - 1], 0); + out.pop_back(); + EXPECT_EQ(out.compare(input), 0); + input.append(u"a"); + IMSA_HILOGI("inputLen:%{public}zu,input:%{public}s", input.size(), Str16ToStr8(input).c_str()); + ret = OH_TextConfig_SetPlaceholder(config, input.data(), input.size()); + EXPECT_EQ(ret, IME_ERR_OK); + std::u16string out2(MAX_PLACEHOLDER_INPUT_SIZE, u'\0'); + outLen = out2.size(); + ret = OH_TextConfig_GetPlaceholder(config, out2.data(), &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + EXPECT_EQ(out2[out2.size() - 1], 0); + input[input.size() - 1] = u'\0'; + EXPECT_EQ(out2.compare(input), 0); + OH_TextConfig_Destroy(config); +} + +/** + * @tc.name: OH_TextConfig_SetAbilityName_001 + * @tc.desc: Input parameters are valid + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, OH_TextConfig_SetAbilityName_001, TestSize.Level0) { + auto config = OH_TextConfig_Create(); + ASSERT_NE(nullptr, config); + std::u16string input= u"test"; + auto ret = OH_TextConfig_SetAbilityName(config, input.data(), input.size()); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_GetAbilityName(nullptr, nullptr, nullptr); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + ret = OH_TextConfig_GetAbilityName(config, nullptr, nullptr); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + size_t outLen = 66; + char16_t pOut[66] = {}; + ret = OH_TextConfig_GetAbilityName(config, pOut, nullptr); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + outLen = 1; + ret = OH_TextConfig_GetAbilityName(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_PARAMCHECK); + EXPECT_EQ(outLen, 5); + outLen = 65; + ret = OH_TextConfig_GetAbilityName(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + EXPECT_EQ(outLen, 5); + outLen = 5; + ret = OH_TextConfig_GetAbilityName(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + std::u16string out(pOut, outLen); + IMSA_HILOGI("outLen:%{public}zu,out:%{public}s,outSize:%{public}zu", outLen, + Str16ToStr8(out).c_str(), out.size()); + EXPECT_GT(out.size(), input.size()); + outLen = input.size(); + ret = OH_TextConfig_GetAbilityName(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_PARAMCHECK); + OH_TextConfig_Destroy(config); +} + +/** + * @tc.name: OH_TextConfig_SetAbilityName_002 + * @tc.desc: Invalid test input parameter + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, OH_TextConfig_SetAbilityName_002, TestSize.Level0) { + auto config = OH_TextConfig_Create(); + ASSERT_NE(nullptr, config); + std::u16string input= u"test"; + auto ret = OH_TextConfig_SetAbilityName(config, input.data(), input.size()); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_SetAbilityName(config, nullptr, 0); + EXPECT_EQ(ret, IME_ERR_OK); + char16_t *pOut = nullptr; + size_t outLen = 0; + ret = OH_TextConfig_GetAbilityName(config, pOut, &outLen); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + EXPECT_EQ(outLen, 1); + EXPECT_EQ(pOut, nullptr); + OH_TextConfig_Destroy(config); +} + +/** + * @tc.name: OH_TextConfig_SetAbilityName_003 + * @tc.desc: Invalid test input parameter + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, OH_TextConfig_SetAbilityName_003, TestSize.Level0) { + auto config = OH_TextConfig_Create(); + ASSERT_NE(nullptr, config); + auto ret = OH_TextConfig_SetAbilityName(config, nullptr, 128); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_SetAbilityName(config, nullptr, 1); + EXPECT_EQ(ret, IME_ERR_OK); + char16_t input[] = u"0"; + ret = OH_TextConfig_SetAbilityName(config, input, 0); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_SetAbilityName(config, input, 1); + EXPECT_EQ(ret, IME_ERR_OK); + ret = OH_TextConfig_SetAbilityName(nullptr, nullptr, 1); + EXPECT_EQ(ret, IME_ERR_NULL_POINTER); + OH_TextConfig_Destroy(config); +} + +/** + * @tc.name: OH_TextConfig_SetAbilityName_004 + * @tc.desc: Invalid test input parameter + * @tc.type: FUNC + */ +HWTEST_F(InputMethodControllerCapiTest, OH_TextConfig_SetAbilityName_004, TestSize.Level0) { + auto config = OH_TextConfig_Create(); + ASSERT_NE(nullptr, config); + std::u16string input = u""; + for (int i = 0; i < MAX_ABILITY_NAME_SIZE; ++i) { + input.append(u"𪛊"); + } + IMSA_HILOGI("inputLen:%{public}zu,input:%{public}s", input.size(), Str16ToStr8(input).c_str()); + auto ret = OH_TextConfig_SetAbilityName(config, input.data(), input.size()); + EXPECT_EQ(ret, IME_ERR_OK); + std::u16string out(MAX_ABILITY_NAME_INPUT_SIZE, u'\0'); + size_t outLen = out.size(); + ret = OH_TextConfig_GetAbilityName(config, out.data(), &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + IMSA_HILOGI("outLen:%{public}zu,input:%{public}s,outSize:%{public}zu,inputSize:%{public}zu", outLen, + Str16ToStr8(input).c_str(), out.size(), input.size()); + EXPECT_GT(out.size(), input.size()); + EXPECT_EQ(out[out.size() - 1], 0); + out.pop_back(); + EXPECT_EQ(out.compare(input), 0); + input.append(u"a"); + IMSA_HILOGI("inputLen:%{public}zu,input:%{public}s", input.size(), Str16ToStr8(input).c_str()); + ret = OH_TextConfig_SetAbilityName(config, input.data(), input.size()); + EXPECT_EQ(ret, IME_ERR_OK); + std::u16string out2(MAX_ABILITY_NAME_INPUT_SIZE, u'\0'); + outLen = out2.size(); + ret = OH_TextConfig_GetAbilityName(config, out2.data(), &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + EXPECT_EQ(out2[out2.size() - 1], 0); + input[input.size() -1] = u'\0'; + EXPECT_EQ(out2.compare(input), 0); + char16_t charInput[65] = u"123456789\0123456789\0012345678901\023456789"; + size_t charInputLen = 32; + IMSA_HILOGI("inputLen:%{public}zu,input:%{public}s", charInputLen, Str16ToStr8(input).c_str()); + ret = OH_TextConfig_SetAbilityName(config, charInput, charInputLen); + EXPECT_EQ(ret, IME_ERR_OK); + char16_t outChar[66] = {}; + outLen = 33; + ret = OH_TextConfig_GetAbilityName(config, outChar, &outLen); + EXPECT_EQ(ret, IME_ERR_OK); + out = std::u16string(outChar, outLen); + auto utf8Out = Str16ToStr8(outChar); + IMSA_HILOGI("outLen:%{public}zu,out:%{public}s, utf8len:%{public}zu", outLen, utf8Out.c_str(), utf8Out.size()); + OH_TextConfig_Destroy(config); +} } // namespace \ No newline at end of file diff --git a/test/unittest/cpp_test/src/string_utils_test.cpp b/test/unittest/cpp_test/src/string_utils_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d944dd754e5db1f23aedc594965455d875634c7 --- /dev/null +++ b/test/unittest/cpp_test/src/string_utils_test.cpp @@ -0,0 +1,78 @@ +/* + * 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 +#include +#include + +#include "global.h" +#include "string_utils.h" + + +using namespace testing::ext; +namespace OHOS { +namespace MiscServices { +class StringUtilsTest : public testing::Test { +public: + void SetUp() + { + IMSA_HILOGI("StringUtils::SetUp"); + } + void TearDown() + { + IMSA_HILOGI("StringUtils::TearDown"); + } +}; + +/** + * @tc.name: testToHex_001 + * @tc.desc: IMA + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(StringUtilsTest, testToHex_001, TestSize.Level0) +{ + std::string out = StringUtils::ToHex(std::string("a")); + std::string result = "61"; + IMSA_HILOGI("out:%{public}s,result:%{public}s", out.c_str(), result.c_str()); + EXPECT_TRUE(out.compare(result) == 0); + out = StringUtils::ToHex(std::u16string(u"a")); + IMSA_HILOGI("out:%{public}s,result:%{public}s", out.c_str(), result.c_str()); + result = "0061"; + EXPECT_TRUE(out.compare(result) == 0); +} + +/** + * @tc.name: testCountUtf16Chars_001 + * @tc.desc: IMA + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(StringUtilsTest, testCountUtf16Chars_001, TestSize.Level0) +{ + char16_t inputChar[] = u"abcdefg\0𪛊"; + size_t inputLen = sizeof(inputChar) / sizeof(char16_t); + IMSA_HILOGI("out:%{public}zu", inputLen); + std::u16string out(inputChar, inputLen); + IMSA_HILOGI("out:%{public}s", StringUtils::ToHex(out).c_str()); + auto charNum = StringUtils::CountUtf16Chars(out); + StringUtils::TruncateUtf16String(out, charNum -1); + std::u16string checkOut(inputChar, inputLen - 1); + IMSA_HILOGI("out:%{public}s", StringUtils::ToHex(checkOut).c_str()); + EXPECT_TRUE(out.compare(checkOut) == 0); +} + +} // namespace MiscServices +} // namespace OHOS diff --git a/test/unittest/napi_test/src/InputMethodWithAttachTest.js b/test/unittest/napi_test/src/InputMethodWithAttachTest.js index b5f9543b3bb9312f7d6d0ffe406cc7f0fd87f936..6e0ca2448f18530d80dab5156870ef8546e5f78d 100644 --- a/test/unittest/napi_test/src/InputMethodWithAttachTest.js +++ b/test/unittest/napi_test/src/InputMethodWithAttachTest.js @@ -1380,4 +1380,34 @@ describe('InputMethodWithAttachTest', function () { done(); } }); + + /* + * @tc.number inputmethod_with_attach_test_discardTypingText + * @tc.name discard Typing Text + * @tc.desc Function test + * @tc.level 2 + */ + it('inputmethod_with_attach_test_discardTypingText', 0, async function (done) { + console.info('************* inputmethod_with_attach_test_discardTypingText Test start*************'); + let cfg = { + inputAttribute: + { + textInputType: inputMethod.TextInputType.TEXT, + enterKeyType: inputMethod.EnterKeyType.SEARCH + } + }; + await inputMethod.getController().attach(true, cfg); + let inputMethodCtrl = inputMethod.getController(); + inputMethodCtrl.discardTypingText((err) => { + if (err) { + console.info(`inputmethod_with_attach_test_discardTypingText result: ${JSON.stringify(err)}`); + expect().assertFail(); + done(); + } + console.info('inputmethod_with_attach_test_discardTypingText callback success'); + expect(true).assertTrue(); + done(); + }); + console.info('************* inputmethod_with_attach_test_discardTypingText Test end*************'); + }); }); \ No newline at end of file diff --git a/test/unittest/resource/bundle_dependencies/extImfBundle/entry/src/main/ets/InputMethodExtAbility/model/KeyboardController.ts b/test/unittest/resource/bundle_dependencies/extImfBundle/entry/src/main/ets/InputMethodExtAbility/model/KeyboardController.ts index 6f94fb899a49fe121d2ee3d51f346b6295f198a4..c2cba8bebd3f595d713778b8d014da5812716bed 100644 --- a/test/unittest/resource/bundle_dependencies/extImfBundle/entry/src/main/ets/InputMethodExtAbility/model/KeyboardController.ts +++ b/test/unittest/resource/bundle_dependencies/extImfBundle/entry/src/main/ets/InputMethodExtAbility/model/KeyboardController.ts @@ -207,12 +207,17 @@ export class KeyboardController { inputMethodAbility.on('inputStop', () => { this.onDestroy(); }); + inputMethodAbility.on('discardTypingText', () => { + console.log('[registerInputListener] discardTypingText start:' ) + }); } private unRegisterListener(): void { inputMethodAbility.off('inputStart'); inputMethodAbility.off('inputStop', () => { }); + inputMethodAbility.off('discardTypingText', () => { + }); } getBackwardSync() { diff --git a/test/unittest/resource/bundle_dependencies/newTestIme/entry/src/main/ets/InputMethodExtAbility/model/KeyboardController.ts b/test/unittest/resource/bundle_dependencies/newTestIme/entry/src/main/ets/InputMethodExtAbility/model/KeyboardController.ts index 5b511e30a3c6f2580ea8826852978a82fdbafc98..d6a57500fb63fbd30494925b5c7d574f5e5d3441 100644 --- a/test/unittest/resource/bundle_dependencies/newTestIme/entry/src/main/ets/InputMethodExtAbility/model/KeyboardController.ts +++ b/test/unittest/resource/bundle_dependencies/newTestIme/entry/src/main/ets/InputMethodExtAbility/model/KeyboardController.ts @@ -46,12 +46,16 @@ export class KeyboardController { this.onDestroy(); } }); + globalThis.inputEngine.on('discardTypingText', () => { + console.log('[registerInputListener] discardTypingText start:' ) + }); } private unRegisterListener(): void { this.addLog("unRegisterListener"); globalThis.inputEngine.off('inputStart'); globalThis.inputEngine.off('inputStop'); + globalThis.inputEngine.off('discardTypingText'); } public onDestroy(): void {